# HG changeset patch # User Doug Simon # Date 1401231011 -7200 # Node ID 5c73b162eec248fc2d06f59d8f25860871a21be5 # Parent b35b1dc75ec005ccc31278201527269eba970b27 reduced execution time of ReplacementsImple.registerSubstitutions() by deferring parsing of substitution classes until the first request for a substitute method is received diff -r b35b1dc75ec0 -r 5c73b162eec2 graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/GraalKernelTester.java --- a/graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/GraalKernelTester.java Tue May 27 22:00:41 2014 +0200 +++ b/graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/GraalKernelTester.java Wed May 28 00:50:11 2014 +0200 @@ -54,7 +54,7 @@ private static synchronized void installSubstitutions() { if (!substitutionsInstalled) { - getHSAILBackend().getProviders().getReplacements().registerSubstitutions(ForceDeoptSubstitutions.class); + getHSAILBackend().getProviders().getReplacements().registerSubstitutions(GraalKernelTester.class, ForceDeoptSubstitutions.class); substitutionsInstalled = true; } } diff -r b35b1dc75ec0 -r 5c73b162eec2 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java Tue May 27 22:00:41 2014 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java Wed May 28 00:50:11 2014 +0200 @@ -89,7 +89,7 @@ private void installSubstitutions() { if (!substitutionsInstalled) { - this.providers.getReplacements().registerSubstitutions(InjectProfileDataSubstitutions.class); + this.providers.getReplacements().registerSubstitutions(GraalCompilerTest.class, InjectProfileDataSubstitutions.class); substitutionsInstalled = true; } } diff -r b35b1dc75ec0 -r 5c73b162eec2 graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotReplacementsImpl.java --- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotReplacementsImpl.java Tue May 27 22:00:41 2014 +0200 +++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotReplacementsImpl.java Wed May 28 00:50:11 2014 +0200 @@ -59,16 +59,16 @@ public void completeInitialization() { // Register the substitutions for java.lang.Math routines. - registerSubstitutions(HSAILMathSubstitutions.class); + registerSubstitutions(Math.class, HSAILMathSubstitutions.class); // Register the ignored substitutions addIgnoredResolvedMethod(String.class, "equals", Object.class); } @Override - protected ResolvedJavaMethod registerMethodSubstitution(Member originalMethod, Method substituteMethod) { + protected ResolvedJavaMethod registerMethodSubstitution(ClassReplacements cr, Member originalMethod, Method substituteMethod) { // TODO: decide if we want to override this in any way - return super.registerMethodSubstitution(originalMethod, substituteMethod); + return super.registerMethodSubstitution(cr, originalMethod, substituteMethod); } @Override diff -r b35b1dc75ec0 -r 5c73b162eec2 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java Tue May 27 22:00:41 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java Wed May 28 00:50:11 2014 +0200 @@ -48,7 +48,7 @@ } @Override - protected ResolvedJavaMethod registerMethodSubstitution(Member originalMethod, Method substituteMethod) { + protected ResolvedJavaMethod registerMethodSubstitution(ClassReplacements cr, Member originalMethod, Method substituteMethod) { final Class substituteClass = substituteMethod.getDeclaringClass(); if (substituteClass.getDeclaringClass() == BoxingSubstitutions.class) { if (config.useHeapProfiler) { @@ -78,7 +78,7 @@ return null; } } - return super.registerMethodSubstitution(originalMethod, substituteMethod); + return super.registerMethodSubstitution(cr, originalMethod, substituteMethod); } @Override diff -r b35b1dc75ec0 -r 5c73b162eec2 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CallSiteSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CallSiteSubstitutions.java Tue May 27 22:00:41 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CallSiteSubstitutions.java Wed May 28 00:50:11 2014 +0200 @@ -35,9 +35,9 @@ @Override public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider loweringProvider, SnippetReflectionProvider snippetReflection, Replacements replacements, TargetDescription target) { - replacements.registerSubstitutions(ConstantCallSiteSubstitutions.class); - replacements.registerSubstitutions(MutableCallSiteSubstitutions.class); - replacements.registerSubstitutions(VolatileCallSiteSubstitutions.class); + replacements.registerSubstitutions(ConstantCallSite.class, ConstantCallSiteSubstitutions.class); + replacements.registerSubstitutions(MutableCallSite.class, MutableCallSiteSubstitutions.class); + replacements.registerSubstitutions(VolatileCallSite.class, VolatileCallSiteSubstitutions.class); } @ClassSubstitution(ConstantCallSite.class) diff -r b35b1dc75ec0 -r 5c73b162eec2 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java Tue May 27 22:00:41 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java Wed May 28 00:50:11 2014 +0200 @@ -22,29 +22,50 @@ */ package com.oracle.graal.hotspot.replacements; +import java.lang.reflect.*; +import java.util.zip.*; + +import sun.misc.*; +import sun.reflect.*; + import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.api.replacements.*; import com.oracle.graal.api.runtime.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.lir.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.replacements.*; @ServiceProvider(ReplacementsProvider.class) public class HotSpotSubstitutions implements ReplacementsProvider { + static class NamedType implements Type { + private final String name; + + public NamedType(String name) { + this.name = name; + } + + @Override + public String toString() { + return name; + } + } + @Override public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider loweringProvider, SnippetReflectionProvider snippetReflection, Replacements replacements, TargetDescription target) { - replacements.registerSubstitutions(ObjectSubstitutions.class); - replacements.registerSubstitutions(SystemSubstitutions.class); - replacements.registerSubstitutions(ThreadSubstitutions.class); - replacements.registerSubstitutions(UnsafeSubstitutions.class); - replacements.registerSubstitutions(ClassSubstitutions.class); - replacements.registerSubstitutions(AESCryptSubstitutions.class); - replacements.registerSubstitutions(CipherBlockChainingSubstitutions.class); - replacements.registerSubstitutions(CRC32Substitutions.class); - replacements.registerSubstitutions(ReflectionSubstitutions.class); - replacements.registerSubstitutions(HotSpotNodeClassSubstitutions.class); - replacements.registerSubstitutions(HotSpotNodeSubstitutions.class); - replacements.registerSubstitutions(CompositeValueClassSubstitutions.class); + replacements.registerSubstitutions(Object.class, ObjectSubstitutions.class); + replacements.registerSubstitutions(System.class, SystemSubstitutions.class); + replacements.registerSubstitutions(Thread.class, ThreadSubstitutions.class); + replacements.registerSubstitutions(Unsafe.class, UnsafeSubstitutions.class); + replacements.registerSubstitutions(Class.class, ClassSubstitutions.class); + replacements.registerSubstitutions(CRC32.class, CRC32Substitutions.class); + replacements.registerSubstitutions(Reflection.class, ReflectionSubstitutions.class); + replacements.registerSubstitutions(NodeClass.class, HotSpotNodeClassSubstitutions.class); + replacements.registerSubstitutions(Node.class, HotSpotNodeSubstitutions.class); + replacements.registerSubstitutions(CompositeValueClass.class, CompositeValueClassSubstitutions.class); + replacements.registerSubstitutions(new NamedType("com.sun.crypto.provider.AESCrypt"), AESCryptSubstitutions.class); + replacements.registerSubstitutions(new NamedType("com.sun.crypto.provider.CipherBlockChaining"), CipherBlockChainingSubstitutions.class); } } diff -r b35b1dc75ec0 -r 5c73b162eec2 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java Tue May 27 22:00:41 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java Wed May 28 00:50:11 2014 +0200 @@ -22,6 +22,7 @@ */ package com.oracle.graal.nodes.spi; +import java.lang.reflect.*; import java.util.*; import com.oracle.graal.api.code.*; @@ -36,14 +37,14 @@ /** * Gets the snippet graph derived from a given method. - * + * * @return the snippet graph, if any, that is derived from {@code method} */ StructuredGraph getSnippet(ResolvedJavaMethod method); /** * Gets the snippet graph derived from a given method. - * + * * @param recursiveEntry if the snippet contains a call to this method, it's considered as * recursive call and won't be processed for {@linkplain MethodSubstitution * substitutions} or {@linkplain MacroSubstitution macro nodes}. @@ -59,7 +60,7 @@ /** * Notifies this object during snippet specialization once the specialized snippet's constant * parameters have been replaced with constant values. - * + * * @param specializedSnippet the snippet in the process of being specialized. This is a copy of * the unspecialized snippet graph created during snippet preparation. */ @@ -67,14 +68,14 @@ /** * Gets the graph that is a substitution for a given method. - * + * * @return the graph, if any, that is a substitution for {@code method} */ StructuredGraph getMethodSubstitution(ResolvedJavaMethod method); /** * Gets the node class with which a method invocation should be replaced. - * + * * @param method target of an invocation * @return the {@linkplain MacroSubstitution#macro() macro node class} associated with * {@code method} or null if there is no such association @@ -89,8 +90,15 @@ /** * Registers all the {@linkplain MethodSubstitution method} and {@linkplain MacroSubstitution * macro} substitutions defined by a given class. + * + * @param original the original class for which substitutions are being registered. This must be + * the same type denoted by the {@link ClassSubstitution} annotation on + * {@code substitutions}. It is required here so that an implementation is not forced + * to read annotations during registration. + * @param substitutions the class defining substitutions for {@code original}. This class must + * be annotated with {@link ClassSubstitution}. */ - void registerSubstitutions(Class substitutions); + void registerSubstitutions(Type original, Class substitutions); /** * Returns all methods that are currently registered as method/macro substitution or as a diff -r b35b1dc75ec0 -r 5c73b162eec2 graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64Substitutions.java --- a/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64Substitutions.java Tue May 27 22:00:41 2014 +0200 +++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64Substitutions.java Wed May 28 00:50:11 2014 +0200 @@ -25,6 +25,8 @@ import static com.oracle.graal.compiler.common.GraalOptions.*; +import java.util.*; + import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.api.replacements.*; @@ -40,8 +42,8 @@ public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider lowerer, SnippetReflectionProvider snippetReflection, Replacements replacements, TargetDescription target) { if (Intrinsify.getValue()) { - replacements.registerSubstitutions(ArraysSubstitutions.class); - replacements.registerSubstitutions(StringSubstitutions.class); + replacements.registerSubstitutions(Arrays.class, ArraysSubstitutions.class); + replacements.registerSubstitutions(String.class, StringSubstitutions.class); } } diff -r b35b1dc75ec0 -r 5c73b162eec2 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BoxingSubstitutions.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BoxingSubstitutions.java Tue May 27 22:00:41 2014 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BoxingSubstitutions.java Wed May 28 00:50:11 2014 +0200 @@ -25,6 +25,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.api.replacements.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.spi.*; public class BoxingSubstitutions { @@ -140,8 +141,14 @@ } } - public static Class[] getClasses() { - return new Class[]{BooleanSubstitutions.class, ByteSubstitutions.class, CharacterSubstitutions.class, DoubleSubstitutions.class, FloatSubstitutions.class, IntegerSubstitutions.class, - LongSubstitutions.class, ShortSubstitutions.class}; + public static void registerReplacements(Replacements replacements) { + replacements.registerSubstitutions(Boolean.class, BooleanSubstitutions.class); + replacements.registerSubstitutions(Character.class, CharacterSubstitutions.class); + replacements.registerSubstitutions(Double.class, DoubleSubstitutions.class); + replacements.registerSubstitutions(Byte.class, ByteSubstitutions.class); + replacements.registerSubstitutions(Float.class, FloatSubstitutions.class); + replacements.registerSubstitutions(Integer.class, IntegerSubstitutions.class); + replacements.registerSubstitutions(Short.class, ShortSubstitutions.class); + replacements.registerSubstitutions(Long.class, LongSubstitutions.class); } } diff -r b35b1dc75ec0 -r 5c73b162eec2 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraalMethodSubstitutions.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraalMethodSubstitutions.java Tue May 27 22:00:41 2014 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraalMethodSubstitutions.java Wed May 28 00:50:11 2014 +0200 @@ -24,6 +24,8 @@ import static com.oracle.graal.compiler.common.GraalOptions.*; +import java.lang.reflect.*; + import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.api.replacements.*; @@ -37,20 +39,17 @@ public class GraalMethodSubstitutions implements ReplacementsProvider { public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider loweringProvider, SnippetReflectionProvider snippetReflection, Replacements replacements, TargetDescription target) { - for (Class clazz : BoxingSubstitutions.getClasses()) { - replacements.registerSubstitutions(clazz); - } - + BoxingSubstitutions.registerReplacements(replacements); if (Intrinsify.getValue()) { - replacements.registerSubstitutions(ArraySubstitutions.class); - replacements.registerSubstitutions(MathSubstitutionsX86.class); - replacements.registerSubstitutions(DoubleSubstitutions.class); - replacements.registerSubstitutions(FloatSubstitutions.class); - replacements.registerSubstitutions(LongSubstitutions.class); - replacements.registerSubstitutions(IntegerSubstitutions.class); - replacements.registerSubstitutions(CharacterSubstitutions.class); - replacements.registerSubstitutions(ShortSubstitutions.class); - replacements.registerSubstitutions(UnsignedMathSubstitutions.class); + replacements.registerSubstitutions(Array.class, ArraySubstitutions.class); + replacements.registerSubstitutions(Math.class, MathSubstitutionsX86.class); + replacements.registerSubstitutions(Double.class, DoubleSubstitutions.class); + replacements.registerSubstitutions(Float.class, FloatSubstitutions.class); + replacements.registerSubstitutions(Long.class, LongSubstitutions.class); + replacements.registerSubstitutions(Integer.class, IntegerSubstitutions.class); + replacements.registerSubstitutions(Character.class, CharacterSubstitutions.class); + replacements.registerSubstitutions(Short.class, ShortSubstitutions.class); + replacements.registerSubstitutions(UnsignedMath.class, UnsignedMathSubstitutions.class); } } } diff -r b35b1dc75ec0 -r 5c73b162eec2 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java Tue May 27 22:00:41 2014 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java Wed May 28 00:50:11 2014 +0200 @@ -29,6 +29,7 @@ import java.lang.reflect.*; import java.util.*; import java.util.concurrent.*; +import java.util.concurrent.atomic.*; import sun.misc.*; @@ -68,28 +69,165 @@ */ protected final ConcurrentMap graphs; - // These data structures are all fully initialized during single-threaded - // compiler startup and so do not need to be concurrent. - protected final Map registeredMethodSubstitutions; - private final Map> registeredMacroSubstitutions; - private final Set forcedSubstitutions; + /** + * Encapsulates method and macro substitutions for a single class. + */ + protected class ClassReplacements { + protected final Map methodSubstitutions = new HashMap<>(); + private final Map> macroSubstitutions = new HashMap<>(); + private final Set forcedSubstitutions = new HashSet<>(); + + public ClassReplacements(Class[] substitutionClasses, AtomicReference ref) { + for (Class substitutionClass : substitutionClasses) { + ClassSubstitution classSubstitution = substitutionClass.getAnnotation(ClassSubstitution.class); + assert !Snippets.class.isAssignableFrom(substitutionClass); + SubstitutionGuard defaultGuard = getGuard(classSubstitution.defaultGuard()); + for (Method substituteMethod : substitutionClass.getDeclaredMethods()) { + if (ref.get() != null) { + // Bail if another thread beat us creating the substitutions + return; + } + MethodSubstitution methodSubstitution = substituteMethod.getAnnotation(MethodSubstitution.class); + MacroSubstitution macroSubstitution = substituteMethod.getAnnotation(MacroSubstitution.class); + if (methodSubstitution == null && macroSubstitution == null) { + continue; + } + + int modifiers = substituteMethod.getModifiers(); + if (!Modifier.isStatic(modifiers)) { + throw new GraalInternalError("Substitution methods must be static: " + substituteMethod); + } + + if (methodSubstitution != null) { + SubstitutionGuard guard = getGuard(methodSubstitution.guard()); + if (guard == null) { + guard = defaultGuard; + } + + if (macroSubstitution != null && macroSubstitution.isStatic() != methodSubstitution.isStatic()) { + throw new GraalInternalError("Macro and method substitution must agree on isStatic attribute: " + substituteMethod); + } + if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) { + throw new GraalInternalError("Substitution method must not be abstract or native: " + substituteMethod); + } + String originalName = originalName(substituteMethod, methodSubstitution.value()); + JavaSignature originalSignature = originalSignature(substituteMethod, methodSubstitution.signature(), methodSubstitution.isStatic()); + Member originalMethod = originalMethod(classSubstitution, methodSubstitution.optional(), originalName, originalSignature); + if (originalMethod != null && (guard == null || guard.execute())) { + ResolvedJavaMethod original = registerMethodSubstitution(this, originalMethod, substituteMethod); + if (original != null && methodSubstitution.forced() && shouldIntrinsify(original)) { + forcedSubstitutions.add(original); + } + } + } + // We don't have per method guards for macro substitutions but at + // least respect the defaultGuard if there is one. + if (macroSubstitution != null && (defaultGuard == null || defaultGuard.execute())) { + String originalName = originalName(substituteMethod, macroSubstitution.value()); + JavaSignature originalSignature = originalSignature(substituteMethod, macroSubstitution.signature(), macroSubstitution.isStatic()); + Member originalMethod = originalMethod(classSubstitution, macroSubstitution.optional(), originalName, originalSignature); + if (originalMethod != null) { + ResolvedJavaMethod original = registerMacroSubstitution(this, originalMethod, macroSubstitution.macro()); + if (original != null && macroSubstitution.forced() && shouldIntrinsify(original)) { + forcedSubstitutions.add(original); + } + } + } + } + } + } + + private JavaSignature originalSignature(Method substituteMethod, String methodSubstitution, boolean isStatic) { + Class[] parameters; + Class returnType; + if (methodSubstitution.isEmpty()) { + parameters = substituteMethod.getParameterTypes(); + if (!isStatic) { + assert parameters.length > 0 : "must be a static method with the 'this' object as its first parameter"; + parameters = Arrays.copyOfRange(parameters, 1, parameters.length); + } + returnType = substituteMethod.getReturnType(); + } else { + Signature signature = providers.getMetaAccess().parseMethodDescriptor(methodSubstitution); + parameters = new Class[signature.getParameterCount(false)]; + for (int i = 0; i < parameters.length; i++) { + parameters[i] = resolveClass(signature.getParameterType(i, null)); + } + returnType = resolveClass(signature.getReturnType(null)); + } + return new JavaSignature(returnType, parameters); + } + + private Member originalMethod(ClassSubstitution classSubstitution, boolean optional, String name, JavaSignature signature) { + Class originalClass = classSubstitution.value(); + if (originalClass == ClassSubstitution.class) { + originalClass = resolveClass(classSubstitution.className(), classSubstitution.optional()); + if (originalClass == null) { + // optional class was not found + return null; + } + } + try { + if (name.equals("")) { + assert signature.returnType.equals(void.class) : signature; + Constructor original = originalClass.getDeclaredConstructor(signature.parameters); + return original; + } else { + Method original = originalClass.getDeclaredMethod(name, signature.parameters); + if (!original.getReturnType().equals(signature.returnType)) { + throw new NoSuchMethodException(originalClass.getName() + "." + name + signature); + } + return original; + } + } catch (NoSuchMethodException | SecurityException e) { + if (optional) { + return null; + } + throw new GraalInternalError(e); + } + } + } + + /** + * Per-class replacements. The entries in these maps are all fully initialized during + * single-threaded compiler startup and so do not need to be concurrent. + */ + private final Map> classReplacements; + private final Map[]> internalNameToSubstitutionClasses; + private final Map, SnippetTemplateCache> snippetTemplateCache; public ReplacementsImpl(Providers providers, SnippetReflectionProvider snippetReflection, Assumptions assumptions, TargetDescription target) { this.providers = providers.copyWith(this); + this.classReplacements = new HashMap<>(); + this.internalNameToSubstitutionClasses = new HashMap<>(); this.snippetReflection = snippetReflection; this.target = target; this.assumptions = assumptions; this.graphs = new ConcurrentHashMap<>(); - this.registeredMethodSubstitutions = new HashMap<>(); - this.registeredMacroSubstitutions = new HashMap<>(); - this.forcedSubstitutions = new HashSet<>(); this.snippetTemplateCache = new HashMap<>(); } private static final boolean UseSnippetGraphCache = Boolean.parseBoolean(System.getProperty("graal.useSnippetGraphCache", "true")); private static final DebugTimer SnippetPreparationTime = Debug.timer("SnippetPreparationTime"); + /** + * Gets the method and macro replacements for a given class. This method will parse the + * replacements in the substitution classes associated with {@code internalName} the first time + * this method is called for {@code internalName}. + */ + protected ClassReplacements getClassReplacements(String internalName) { + Class[] substitutionClasses = internalNameToSubstitutionClasses.get(internalName); + if (substitutionClasses != null) { + AtomicReference crRef = classReplacements.get(internalName); + if (crRef.get() == null) { + crRef.compareAndSet(null, new ClassReplacements(substitutionClasses, crRef)); + } + return crRef.get(); + } + return null; + } + public StructuredGraph getSnippet(ResolvedJavaMethod method) { return getSnippet(method, null); } @@ -133,7 +271,8 @@ @Override public StructuredGraph getMethodSubstitution(ResolvedJavaMethod original) { - ResolvedJavaMethod substitute = registeredMethodSubstitutions.get(original); + ClassReplacements cr = getClassReplacements(original.getDeclaringClass().getName()); + ResolvedJavaMethod substitute = cr == null ? null : cr.methodSubstitutions.get(original); if (substitute == null) { return null; } @@ -150,7 +289,8 @@ } public Class getMacroSubstitution(ResolvedJavaMethod method) { - return registeredMacroSubstitutions.get(method); + ClassReplacements cr = getClassReplacements(method.getDeclaringClass().getName()); + return cr == null ? null : cr.macroSubstitutions.get(method); } public Assumptions getAssumptions() { @@ -168,59 +308,29 @@ return null; } - public void registerSubstitutions(Class substitutions) { - ClassSubstitution classSubstitution = substitutions.getAnnotation(ClassSubstitution.class); - assert classSubstitution != null; - assert !Snippets.class.isAssignableFrom(substitutions); - SubstitutionGuard defaultGuard = getGuard(classSubstitution.defaultGuard()); - for (Method substituteMethod : substitutions.getDeclaredMethods()) { - MethodSubstitution methodSubstitution = substituteMethod.getAnnotation(MethodSubstitution.class); - MacroSubstitution macroSubstitution = substituteMethod.getAnnotation(MacroSubstitution.class); - if (methodSubstitution == null && macroSubstitution == null) { - continue; - } - - int modifiers = substituteMethod.getModifiers(); - if (!Modifier.isStatic(modifiers)) { - throw new GraalInternalError("Substitution methods must be static: " + substituteMethod); - } - - if (methodSubstitution != null) { - SubstitutionGuard guard = getGuard(methodSubstitution.guard()); - if (guard == null) { - guard = defaultGuard; - } + private static String getOriginalInternalName(Class substitutions) { + ClassSubstitution cs = substitutions.getAnnotation(ClassSubstitution.class); + assert cs != null : substitutions + " must be annotated by " + ClassSubstitution.class.getSimpleName(); + if (cs.value() == ClassSubstitution.class) { + return toInternalName(cs.className()); + } + return toInternalName(cs.value().getName()); + } - if (macroSubstitution != null && macroSubstitution.isStatic() != methodSubstitution.isStatic()) { - throw new GraalInternalError("Macro and method substitution must agree on isStatic attribute: " + substituteMethod); - } - if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) { - throw new GraalInternalError("Substitution method must not be abstract or native: " + substituteMethod); - } - String originalName = originalName(substituteMethod, methodSubstitution.value()); - JavaSignature originalSignature = originalSignature(substituteMethod, methodSubstitution.signature(), methodSubstitution.isStatic()); - Member originalMethod = originalMethod(classSubstitution, methodSubstitution.optional(), originalName, originalSignature); - if (originalMethod != null && (guard == null || guard.execute())) { - ResolvedJavaMethod original = registerMethodSubstitution(originalMethod, substituteMethod); - if (original != null && methodSubstitution.forced() && shouldIntrinsify(original)) { - forcedSubstitutions.add(original); - } - } - } - // We don't have per method guards for macro substitutions but at - // least respect the defaultGuard if there is one. - if (macroSubstitution != null && (defaultGuard == null || defaultGuard.execute())) { - String originalName = originalName(substituteMethod, macroSubstitution.value()); - JavaSignature originalSignature = originalSignature(substituteMethod, macroSubstitution.signature(), macroSubstitution.isStatic()); - Member originalMethod = originalMethod(classSubstitution, macroSubstitution.optional(), originalName, originalSignature); - if (originalMethod != null) { - ResolvedJavaMethod original = registerMacroSubstitution(originalMethod, macroSubstitution.macro()); - if (original != null && macroSubstitution.forced() && shouldIntrinsify(original)) { - forcedSubstitutions.add(original); - } - } - } + public void registerSubstitutions(Type original, Class substitutionClass) { + String internalName = toInternalName(original.getTypeName()); + assert getOriginalInternalName(substitutionClass).equals(internalName) : getOriginalInternalName(substitutionClass) + " != " + (internalName); + Class[] classes = internalNameToSubstitutionClasses.get(internalName); + if (classes == null) { + classes = new Class[]{substitutionClass}; + } else { + assert !Arrays.asList(classes).contains(substitutionClass); + classes = Arrays.copyOf(classes, classes.length + 1); + classes[classes.length - 1] = substitutionClass; } + internalNameToSubstitutionClasses.put(internalName, classes); + AtomicReference existing = classReplacements.put(internalName, new AtomicReference<>()); + assert existing == null || existing.get() == null; } /** @@ -230,7 +340,7 @@ * @param substituteMethod the substitute method * @return the original method */ - protected ResolvedJavaMethod registerMethodSubstitution(Member originalMember, Method substituteMethod) { + protected ResolvedJavaMethod registerMethodSubstitution(ClassReplacements cr, Member originalMember, Method substituteMethod) { MetaAccessProvider metaAccess = providers.getMetaAccess(); ResolvedJavaMethod substitute = metaAccess.lookupJavaMethod(substituteMethod); ResolvedJavaMethod original; @@ -243,7 +353,7 @@ Debug.log("substitution: %s --> %s", MetaUtil.format("%H.%n(%p) %r", original), MetaUtil.format("%H.%n(%p) %r", substitute)); } - registeredMethodSubstitutions.put(original, substitute); + cr.methodSubstitutions.put(original, substitute); return original; } @@ -254,7 +364,7 @@ * @param macro the substitute macro node class * @return the original method */ - protected ResolvedJavaMethod registerMacroSubstitution(Member originalMethod, Class macro) { + protected ResolvedJavaMethod registerMacroSubstitution(ClassReplacements cr, Member originalMethod, Class macro) { ResolvedJavaMethod originalJavaMethod; MetaAccessProvider metaAccess = providers.getMetaAccess(); if (originalMethod instanceof Method) { @@ -262,7 +372,7 @@ } else { originalJavaMethod = metaAccess.lookupJavaConstructor((Constructor) originalMethod); } - registeredMacroSubstitutions.put(originalJavaMethod, macro); + cr.macroSubstitutions.put(originalJavaMethod, macro); return originalJavaMethod; } @@ -551,7 +661,7 @@ * @param optional if true, resolution failure returns null * @return the resolved class or null if resolution fails and {@code optional} is true */ - static Class resolveType(String className, boolean optional) { + static Class resolveClass(String className, boolean optional) { try { // Need to use launcher class path to handle classes // that are not on the boot class path @@ -565,7 +675,7 @@ } } - private static Class resolveType(JavaType type) { + private static Class resolveClass(JavaType type) { JavaType base = type; int dimensions = 0; while (base.getComponentType() != null) { @@ -573,7 +683,7 @@ dimensions++; } - Class baseClass = base.getKind() != Kind.Object ? base.getKind().toJavaClass() : resolveType(toJavaName(base), false); + Class baseClass = base.getKind() != Kind.Object ? base.getKind().toJavaClass() : resolveClass(toJavaName(base), false); return dimensions == 0 ? baseClass : Array.newInstance(baseClass, new int[dimensions]).getClass(); } @@ -599,67 +709,21 @@ } } - private JavaSignature originalSignature(Method substituteMethod, String methodSubstitution, boolean isStatic) { - Class[] parameters; - Class returnType; - if (methodSubstitution.isEmpty()) { - parameters = substituteMethod.getParameterTypes(); - if (!isStatic) { - assert parameters.length > 0 : "must be a static method with the 'this' object as its first parameter"; - parameters = Arrays.copyOfRange(parameters, 1, parameters.length); - } - returnType = substituteMethod.getReturnType(); - } else { - Signature signature = providers.getMetaAccess().parseMethodDescriptor(methodSubstitution); - parameters = new Class[signature.getParameterCount(false)]; - for (int i = 0; i < parameters.length; i++) { - parameters[i] = resolveType(signature.getParameterType(i, null)); - } - returnType = resolveType(signature.getReturnType(null)); - } - return new JavaSignature(returnType, parameters); - } - - private static Member originalMethod(ClassSubstitution classSubstitution, boolean optional, String name, JavaSignature signature) { - Class originalClass = classSubstitution.value(); - if (originalClass == ClassSubstitution.class) { - originalClass = resolveType(classSubstitution.className(), classSubstitution.optional()); - if (originalClass == null) { - // optional class was not found - return null; - } - } - try { - if (name.equals("")) { - assert signature.returnType.equals(void.class) : signature; - Constructor original = originalClass.getDeclaredConstructor(signature.parameters); - return original; - } else { - Method original = originalClass.getDeclaredMethod(name, signature.parameters); - if (!original.getReturnType().equals(signature.returnType)) { - throw new NoSuchMethodException(originalClass.getName() + "." + name + signature); - } - return original; - } - } catch (NoSuchMethodException | SecurityException e) { - if (optional) { - return null; - } - throw new GraalInternalError(e); - } - } - @Override public Collection getAllReplacements() { HashSet result = new HashSet<>(); - result.addAll(registeredMethodSubstitutions.keySet()); - result.addAll(registeredMacroSubstitutions.keySet()); + for (String internalName : classReplacements.keySet()) { + ClassReplacements cr = getClassReplacements(internalName); + result.addAll(cr.methodSubstitutions.keySet()); + result.addAll(cr.macroSubstitutions.keySet()); + } return result; } @Override public boolean isForcedSubstitution(ResolvedJavaMethod method) { - return forcedSubstitutions.contains(method); + ClassReplacements cr = getClassReplacements(method.getDeclaringClass().getName()); + return cr != null && cr.forcedSubstitutions.contains(method); } @Override diff -r b35b1dc75ec0 -r 5c73b162eec2 graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/ExactMathTest.java --- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/ExactMathTest.java Tue May 27 22:00:41 2014 +0200 +++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/ExactMathTest.java Wed May 28 00:50:11 2014 +0200 @@ -38,7 +38,7 @@ public ExactMathTest() { if (!substitutionsInstalled) { Replacements replacements = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getProviders().getReplacements(); - replacements.registerSubstitutions(ExactMathSubstitutions.class); + replacements.registerSubstitutions(ExactMath.class, ExactMathSubstitutions.class); substitutionsInstalled = true; } } diff -r b35b1dc75ec0 -r 5c73b162eec2 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleReplacements.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleReplacements.java Tue May 27 22:00:41 2014 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleReplacements.java Wed May 28 00:50:11 2014 +0200 @@ -32,6 +32,7 @@ import com.oracle.graal.phases.util.*; import com.oracle.graal.replacements.*; import com.oracle.graal.truffle.substitutions.*; +import com.oracle.truffle.api.*; /** * Custom {@link Replacements} for Truffle compilation. @@ -48,11 +49,11 @@ } protected void registerTruffleSubstitutions() { - registerSubstitutions(CompilerAssertsSubstitutions.class); - registerSubstitutions(CompilerDirectivesSubstitutions.class); - registerSubstitutions(ExactMathSubstitutions.class); - registerSubstitutions(OptimizedAssumptionSubstitutions.class); - registerSubstitutions(OptimizedCallTargetSubstitutions.class); + registerSubstitutions(CompilerAsserts.class, CompilerAssertsSubstitutions.class); + registerSubstitutions(CompilerDirectives.class, CompilerDirectivesSubstitutions.class); + registerSubstitutions(ExactMath.class, ExactMathSubstitutions.class); + registerSubstitutions(OptimizedAssumption.class, OptimizedAssumptionSubstitutions.class); + registerSubstitutions(OptimizedCallTarget.class, OptimizedCallTargetSubstitutions.class); } @Override