# HG changeset patch # User Tom Rodriguez # Date 1429120984 25200 # Node ID 23d6b95bd687f4fc6fc0ac43331a3488a52e94f1 # Parent 92fc95e8667d5aae8815f55f0cda68ef441e0c6f# Parent 018c536858ccbc51cd513648daa209d9353c2ba5 Merge diff -r 92fc95e8667d -r 23d6b95bd687 CHANGELOG.md --- a/CHANGELOG.md Wed Apr 15 10:09:13 2015 -0700 +++ b/CHANGELOG.md Wed Apr 15 11:03:04 2015 -0700 @@ -36,6 +36,10 @@ * Changed syntax and semantics of Specialization#assumptions and Specialization#guards. They now use a Java like expression syntax. * Changed guard expressions that do not bind any dynamic parameter are invoked just once per specialization instantiation. They are now asserted to be true on the fast path. * Renamed @ImportGuards to @ImportStatic. +* Changed declaring a @TypeSystemReference for a node that contains specializations is not mandatory anymore. +* Changed types used in specializations are not restricted on types declared in the type system anymore. +* Changed nodes that declare all execute methods with the same number of evaluated arguments as specialization arguments do not require @NodeChild annotations anymore. +* Changed types used in checks and casts are not mandatory to be declared in the type system. ## Version 0.6 19-Dec-2014, [Repository Revision](http://hg.openjdk.java.net/graal/graal/shortlog/graal-0.6) diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java --- a/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java Wed Apr 15 11:03:04 2015 -0700 @@ -1790,4 +1790,8 @@ public void fpadd32(Register rs1, Register rs2, Register rd) { op3(Impdep1, Fpadd32, rs1, rs2, rd); } + + public boolean isCbcond(int i) { + return (i & 0xC1C00000) == 0xC00000; + } } diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCMacroAssembler.java --- a/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCMacroAssembler.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCMacroAssembler.java Wed Apr 15 11:03:04 2015 -0700 @@ -87,7 +87,7 @@ case Bpr: boolean isCBcond = (inst & CBCOND_MASK) != 0; if (isCBcond) { - assert isSimm10(disp); + assert isSimm10(disp) : String.format("%d: instruction: 0x%x", disp, inst); int d10Split = 0; d10Split |= (disp & 0b11_0000_0000) << D10HI_SHIFT - 8; d10Split |= (disp & 0b00_1111_1111) << D10LO_SHIFT; diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugin.java --- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugin.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugin.java Wed Apr 15 11:03:04 2015 -0700 @@ -44,6 +44,13 @@ } /** + * Determines if this plugin can only be used when inlining the method is it associated with. + */ + default boolean inlineOnly() { + return isSignaturePolymorphic(); + } + + /** * Handles invocation of a signature polymorphic method. * * @param receiver access to the receiver, {@code null} if {@code targetMethod} is static diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/MethodSubstitutionPlugin.java --- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/MethodSubstitutionPlugin.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/MethodSubstitutionPlugin.java Wed Apr 15 11:03:04 2015 -0700 @@ -62,6 +62,11 @@ this.originalIsStatic = parameters.length == 0 || parameters[0] != Receiver.class; } + public boolean inlineOnly() { + // Conservatively assume MacroNodes may be used in a substitution + return true; + } + /** * Gets the substitute method, resolving it first if necessary. */ @@ -121,8 +126,7 @@ return m; } } - throw new GraalInternalError("No method found in %s compatible with \"%s(%s)\"", declaringClass.getName(), name, Arrays.asList(parameters).stream().map(c -> c.getSimpleName()).collect( - Collectors.joining(", "))); + throw new GraalInternalError("No method found specified by %s", this); } /** @@ -165,4 +169,10 @@ } throw new GraalInternalError("could not find method named \"execute\" in " + c.getName()); } + + @Override + public String toString() { + return String.format("%s[%s.%s(%s)]", getClass().getSimpleName(), declaringClass.getName(), name, + Arrays.asList(parameters).stream().map(c -> c.getSimpleName()).collect(Collectors.joining(", "))); + } } diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/CompileTheWorldTest.java --- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/CompileTheWorldTest.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/CompileTheWorldTest.java Wed Apr 15 11:03:04 2015 -0700 @@ -40,7 +40,7 @@ boolean originalSetting = ExitVMOnException.getValue(); // Compile a couple classes in rt.jar String file = System.getProperty("java.home") + "/lib/rt.jar"; - new CompileTheWorld(file, new Config(null), 1, 5, null, false).compile(); + new CompileTheWorld(file, new Config(null), 1, 5, null, null, false).compile(); ExitVMOnException.setValue(originalSetting); } diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotCryptoSubstitutionTest.java --- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotCryptoSubstitutionTest.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotCryptoSubstitutionTest.java Wed Apr 15 11:03:04 2015 -0700 @@ -126,7 +126,7 @@ Method method = lookup(className, methodName); if (method != null) { ResolvedJavaMethod installedCodeOwner = getMetaAccess().lookupJavaMethod(method); - StructuredGraph subst = getReplacements().getSubstitution(installedCodeOwner); + StructuredGraph subst = getReplacements().getSubstitution(installedCodeOwner, 0); ResolvedJavaMethod substMethod = subst == null ? null : subst.method(); if (substMethod != null) { StructuredGraph graph = new StructuredGraph(substMethod, AllowAssumptions.YES); diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/MemoryUsageBenchmark.java --- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/MemoryUsageBenchmark.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/MemoryUsageBenchmark.java Wed Apr 15 11:03:04 2015 -0700 @@ -180,7 +180,7 @@ compileAndTime("complex"); if (CompileTheWorldClasspath.getValue() != SUN_BOOT_CLASS_PATH) { CompileTheWorld ctw = new CompileTheWorld(CompileTheWorldClasspath.getValue(), new Config(CompileTheWorldConfig.getValue()), CompileTheWorldStartAt.getValue(), - CompileTheWorldStopAt.getValue(), CompileTheWorldMethodFilter.getValue(), CompileTheWorldVerbose.getValue()); + CompileTheWorldStopAt.getValue(), CompileTheWorldMethodFilter.getValue(), CompileTheWorldExcludeMethodFilter.getValue(), CompileTheWorldVerbose.getValue()); try { ctw.compile(); } catch (Throwable e) { diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java Wed Apr 15 11:03:04 2015 -0700 @@ -70,6 +70,8 @@ public static final OptionValue CompileTheWorldIterations = new OptionValue<>(1); @Option(help = "Only compile methods matching this filter", type = OptionType.Debug) public static final OptionValue CompileTheWorldMethodFilter = new OptionValue<>(null); + @Option(help = "Exclude methods matching this filter from compilation", type = OptionType.Debug) + public static final OptionValue CompileTheWorldExcludeMethodFilter = new OptionValue<>(null); @Option(help = "First class to consider when using -XX:+CompileTheWorld", type = OptionType.Debug) public static final OptionValue CompileTheWorldStartAt = new OptionValue<>(1); @Option(help = "Last class to consider when using -XX:+CompileTheWorld", type = OptionType.Debug) @@ -158,6 +160,9 @@ /** Only compile methods matching one of the filters in this array if the array is non-null. */ private final MethodFilter[] methodFilters; + /** Exclude methods matching one of the filters in this array if the array is non-null. */ + private final MethodFilter[] excludeMethodFilters; + // Counters private int classFileCounter = 0; private AtomicLong compiledMethodsCounter = new AtomicLong(); @@ -180,12 +185,15 @@ * @param files {@link File#pathSeparator} separated list of Zip/Jar files to compile * @param startAt index of the class file to start compilation at * @param stopAt index of the class file to stop compilation at + * @param methodFilters + * @param excludeMethodFilters */ - public CompileTheWorld(String files, Config config, int startAt, int stopAt, String methodFilters, boolean verbose) { + public CompileTheWorld(String files, Config config, int startAt, int stopAt, String methodFilters, String excludeMethodFilters, boolean verbose) { this.files = files; this.startAt = startAt; this.stopAt = stopAt; this.methodFilters = methodFilters == null || methodFilters.isEmpty() ? null : MethodFilter.parse(methodFilters); + this.excludeMethodFilters = excludeMethodFilters == null || excludeMethodFilters.isEmpty() ? null : MethodFilter.parse(excludeMethodFilters); this.verbose = verbose; this.config = config; @@ -292,8 +300,12 @@ if (methodFilters == null || methodFilters.length == 0) { println("CompileTheWorld : Compiling all classes in " + entry); } else { - println("CompileTheWorld : Compiling all methods in " + entry + " matching one of the following filters: " + - Arrays.asList(methodFilters).stream().map(MethodFilter::toString).collect(Collectors.joining(", "))); + String include = Arrays.asList(methodFilters).stream().map(MethodFilter::toString).collect(Collectors.joining(", ")); + println("CompileTheWorld : Compiling all methods in " + entry + " matching one of the following filters: " + include); + } + if (excludeMethodFilters != null && excludeMethodFilters.length > 0) { + String exclude = Arrays.asList(excludeMethodFilters).stream().map(MethodFilter::toString).collect(Collectors.joining(", ")); + println("CompileTheWorld : Excluding all methods matching one of the follwing filters: " + exclude); } println(); @@ -321,6 +333,9 @@ if (methodFilters != null && !MethodFilter.matchesClassName(methodFilters, dottedClassName)) { continue; } + if (excludeMethodFilters != null && MethodFilter.matchesClassName(excludeMethodFilters, dottedClassName)) { + continue; + } if (dottedClassName.startsWith("jdk.management.") || dottedClassName.startsWith("jdk.internal.cmm.*")) { continue; @@ -427,6 +442,9 @@ if (methodFilters != null && !MethodFilter.matches(methodFilters, method)) { return; } + if (excludeMethodFilters != null && MethodFilter.matches(excludeMethodFilters, method)) { + return; + } Future task = threadPool.submit(new Runnable() { public void run() { waitToRun(); diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java Wed Apr 15 11:03:04 2015 -0700 @@ -552,7 +552,7 @@ getCompilerToVM().resetCompilationStatistics(); TTY.println("CompileTheWorld : iteration " + i); CompileTheWorld ctw = new CompileTheWorld(CompileTheWorldClasspath.getValue(), new Config(CompileTheWorldConfig.getValue()), CompileTheWorldStartAt.getValue(), - CompileTheWorldStopAt.getValue(), CompileTheWorldMethodFilter.getValue(), CompileTheWorldVerbose.getValue()); + CompileTheWorldStopAt.getValue(), CompileTheWorldMethodFilter.getValue(), CompileTheWorldExcludeMethodFilter.getValue(), CompileTheWorldVerbose.getValue()); ctw.compile(); } System.exit(0); diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java Wed Apr 15 11:03:04 2015 -0700 @@ -88,7 +88,7 @@ } if (BootstrapReplacements.getValue()) { for (ResolvedJavaMethod method : replacements.getAllReplacements()) { - replacements.getSubstitution(method); + replacements.getSubstitution(method, -1); } } } catch (Throwable e) { diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java Wed Apr 15 11:03:04 2015 -0700 @@ -99,6 +99,10 @@ b.addPush(Kind.Object, new ObjectCloneNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnType(), object)); return true; } + + public boolean inlineOnly() { + return true; + } }); r.registerMethodSubstitution(ObjectSubstitutions.class, "hashCode", Receiver.class); } @@ -118,6 +122,10 @@ } return true; } + + public boolean inlineOnly() { + return true; + } }); } r.register2("cast", Receiver.class, Object.class, new InvocationPlugin() { @@ -131,6 +139,10 @@ } return true; } + + public boolean inlineOnly() { + return true; + } }); } @@ -146,6 +158,10 @@ } return true; } + + public boolean inlineOnly() { + return true; + } }; plugins.register(plugin, ConstantCallSite.class, "getTarget", Receiver.class); plugins.register(plugin, MutableCallSite.class, "getTarget", Receiver.class); @@ -159,6 +175,10 @@ b.addPush(new ReflectionGetCallerClassNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnType())); return true; } + + public boolean inlineOnly() { + return true; + } }); } @@ -171,12 +191,20 @@ b.addPush(new IdentityHashCodeNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnType(), object)); return true; } + + public boolean inlineOnly() { + return true; + } }); r.register5("arraycopy", Object.class, int.class, Object.class, int.class, int.class, new InvocationPlugin() { public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode src, ValueNode srcPos, ValueNode dst, ValueNode dstPos, ValueNode length) { b.add(new ArrayCopyNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnType(), src, srcPos, dst, dstPos, length)); return true; } + + public boolean inlineOnly() { + return true; + } }); } diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInvocationPlugins.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInvocationPlugins.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInvocationPlugins.java Wed Apr 15 11:03:04 2015 -0700 @@ -40,6 +40,7 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.CallTargetNode.InvokeKind; import com.oracle.graal.replacements.StandardGraphBuilderPlugins.BoxPlugin; +import com.oracle.graal.replacements.nodes.*; /** * Extension of {@link InvocationPlugins} that disables plugins based on runtime configuration. @@ -136,6 +137,14 @@ @Override public void checkNewNodes(GraphBuilderContext b, InvocationPlugin plugin, NodeIterable newNodes) { + for (Node node : newNodes) { + if (node instanceof MacroNode) { + // MacroNode based plugins can only be used for inlining since they + // require a valid bci should they need to replace themselves with + // an InvokeNode during lowering. + assert plugin.inlineOnly() : String.format("plugin that creates a %s (%s) must return true for inlineOnly(): %s", MacroNode.class.getSimpleName(), node, plugin); + } + } if (GraalOptions.ImmutableCode.getValue()) { for (Node node : newNodes) { if (node.hasUsages() && node instanceof ConstantNode) { diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java --- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java Wed Apr 15 11:03:04 2015 -0700 @@ -225,8 +225,12 @@ SPARCMove.move(crb, masm, scratchValue, actualY, SPARCDelayedControlTransfer.DUMMY); actualY = scratchValue; } + // Test if the previous instruction was cbcond, if so, put a nop inbetween (See + // SPARC Architecture 2011 manual) + if (masm.isCbcond(masm.getInt(masm.position() - 1))) { + masm.nop(); + } emitCBCond(masm, actualX, actualY, actualTrueTarget, actualConditionFlag); - masm.nop(); } if (needJump) { masm.jmp(actualFalseTarget); diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.graal.nodeinfo.processor/src/com/oracle/graal/nodeinfo/processor/GraphNodeProcessor.java --- a/graal/com.oracle.graal.nodeinfo.processor/src/com/oracle/graal/nodeinfo/processor/GraphNodeProcessor.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.graal.nodeinfo.processor/src/com/oracle/graal/nodeinfo/processor/GraphNodeProcessor.java Wed Apr 15 11:03:04 2015 -0700 @@ -22,7 +22,6 @@ */ package com.oracle.graal.nodeinfo.processor; -import static com.oracle.truffle.dsl.processor.java.ElementUtils.*; import static java.util.Collections.*; import java.io.*; @@ -71,6 +70,21 @@ } } + private static List getElementHierarchy(Element e) { + List elements = new ArrayList<>(); + elements.add(e); + + Element enclosing = e.getEnclosingElement(); + while (enclosing != null && enclosing.getKind() != ElementKind.PACKAGE) { + elements.add(enclosing); + enclosing = enclosing.getEnclosingElement(); + } + if (enclosing != null) { + elements.add(enclosing); + } + return elements; + } + /** * Bugs in an annotation processor can cause silent failure so try to report any exception * throws as errors. diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.graal.nodeinfo.processor/src/com/oracle/graal/nodeinfo/processor/GraphNodeVerifier.java --- a/graal/com.oracle.graal.nodeinfo.processor/src/com/oracle/graal/nodeinfo/processor/GraphNodeVerifier.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.graal.nodeinfo.processor/src/com/oracle/graal/nodeinfo/processor/GraphNodeVerifier.java Wed Apr 15 11:03:04 2015 -0700 @@ -22,7 +22,6 @@ */ package com.oracle.graal.nodeinfo.processor; -import static com.oracle.truffle.dsl.processor.java.ElementUtils.*; import static javax.lang.model.element.Modifier.*; import java.util.*; @@ -32,10 +31,6 @@ import javax.lang.model.type.*; import javax.lang.model.util.*; -import com.oracle.truffle.dsl.processor.java.*; -import com.oracle.truffle.dsl.processor.java.compiler.*; -import com.oracle.truffle.dsl.processor.java.compiler.Compiler; - /** * Verifies static constraints on nodes. */ @@ -54,6 +49,8 @@ private final TypeElement NodeInputList; private final TypeElement NodeSuccessorList; + private final TypeElement object; + // Checkstyle: resume public GraphNodeVerifier(GraphNodeProcessor processor) { @@ -68,6 +65,7 @@ this.Node = getTypeElement("com.oracle.graal.graph.Node"); this.NodeInputList = getTypeElement("com.oracle.graal.graph.NodeInputList"); this.NodeSuccessorList = getTypeElement("com.oracle.graal.graph.NodeSuccessorList"); + this.object = getTypeElement("java.lang.Object"); } /** @@ -91,10 +89,6 @@ return getTypeElement(name).asType(); } - public TypeMirror getType(Class cls) { - return ElementUtils.getType(getProcessingEnv(), cls); - } - public ProcessingEnvironment getProcessingEnv() { return env.getProcessingEnv(); } @@ -106,10 +100,9 @@ } private void scanFields(TypeElement node) { - Compiler compiler = CompilerFactory.getCompiler(node); TypeElement currentClazz = node; do { - for (VariableElement field : ElementFilter.fieldsIn(compiler.getEnclosedElementsInDeclarationOrder(currentClazz))) { + for (VariableElement field : ElementFilter.fieldsIn(currentClazz.getEnclosedElements())) { Set modifiers = field.getModifiers(); if (modifiers.contains(STATIC) || modifiers.contains(TRANSIENT)) { continue; @@ -117,7 +110,7 @@ List annotations = field.getAnnotationMirrors(); - boolean isNonOptionalInput = findAnnotationMirror(annotations, Input.asType()) != null; + boolean isNonOptionalInput = findAnnotationMirror(annotations, Input) != null; boolean isOptionalInput = findAnnotationMirror(annotations, OptionalInput) != null; boolean isSuccessor = findAnnotationMirror(annotations, Successor) != null; @@ -187,6 +180,30 @@ } while (!isObject(getSuperType(currentClazz).asType())); } + private AnnotationMirror findAnnotationMirror(List mirrors, TypeElement expectedAnnotationType) { + for (AnnotationMirror mirror : mirrors) { + if (sameType(mirror.getAnnotationType(), expectedAnnotationType.asType())) { + return mirror; + } + } + return null; + } + + private boolean isObject(TypeMirror type) { + return sameType(object.asType(), type); + } + + private boolean sameType(TypeMirror type1, TypeMirror type2) { + return env.getProcessingEnv().getTypeUtils().isSameType(type1, type2); + } + + private TypeElement getSuperType(TypeElement element) { + if (element.getSuperclass() != null) { + return (TypeElement) env.getProcessingEnv().getTypeUtils().asElement(element.getSuperclass()); + } + return null; + } + void verify(TypeElement node) { scanFields(node); diff -r 92fc95e8667d -r 23d6b95bd687 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 Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java Wed Apr 15 11:03:04 2015 -0700 @@ -70,39 +70,47 @@ /** * Gets a graph that is a substitution for a given method. * + * @param invokeBci the call site BCI if this request is made for inlining a substitute + * otherwise {@code -1} * @return the graph, if any, that is a substitution for {@code method} */ - default StructuredGraph getSubstitution(ResolvedJavaMethod method) { - return getSubstitution(method, false); + default StructuredGraph getSubstitution(ResolvedJavaMethod method, int invokeBci) { + return getSubstitution(method, false, invokeBci); } /** * Gets a graph that is a substitution for a given method. * * @param fromBytecodeOnly only return a graph created by parsing the bytecode of another method + * @param invokeBci the call site BCI if this request is made for inlining a substitute + * otherwise {@code -1} * @return the graph, if any, that is a substitution for {@code method} */ - StructuredGraph getSubstitution(ResolvedJavaMethod method, boolean fromBytecodeOnly); + StructuredGraph getSubstitution(ResolvedJavaMethod method, boolean fromBytecodeOnly, int invokeBci); /** - * Determines if there is a {@linkplain #getSubstitution(ResolvedJavaMethod) substitution graph} - * for a given method. + * Determines if there is a {@linkplain #getSubstitution(ResolvedJavaMethod, int) substitution + * graph} for a given method. * + * @param invokeBci the call site BCI if this request is made for inlining a substitute + * otherwise {@code -1} * @return true iff there is a substitution graph available for {@code method} */ - default boolean hasSubstitution(ResolvedJavaMethod method) { - return hasSubstitution(method, false); + default boolean hasSubstitution(ResolvedJavaMethod method, int invokeBci) { + return hasSubstitution(method, false, invokeBci); } /** - * Determines if there is a {@linkplain #getSubstitution(ResolvedJavaMethod) substitution graph} - * for a given method. + * Determines if there is a {@linkplain #getSubstitution(ResolvedJavaMethod, int) substitution + * graph} for a given method. * * @param fromBytecodeOnly only consider graphs created by parsing the bytecode of another * method + * @param invokeBci the call site BCI if this request is made for inlining a substitute + * otherwise {@code -1} * @return true iff there is a substitution graph available for {@code method} */ - boolean hasSubstitution(ResolvedJavaMethod method, boolean fromBytecodeOnly); + boolean hasSubstitution(ResolvedJavaMethod method, boolean fromBytecodeOnly, int invokeBci); /** * Registers all the {@linkplain MethodSubstitution method} substitutions defined by a given diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java Wed Apr 15 11:03:04 2015 -0700 @@ -646,12 +646,12 @@ return firstParam; } - public static boolean canIntrinsify(Replacements replacements, ResolvedJavaMethod target) { - return replacements.hasSubstitution(target, false); + public static boolean canIntrinsify(Replacements replacements, ResolvedJavaMethod target, int invokeBci) { + return replacements.hasSubstitution(target, false, invokeBci); } - public static StructuredGraph getIntrinsicGraph(Replacements replacements, ResolvedJavaMethod target) { - return replacements.getSubstitution(target); + public static StructuredGraph getIntrinsicGraph(Replacements replacements, ResolvedJavaMethod target, int invokeBci) { + return replacements.getSubstitution(target, invokeBci); } public static FixedWithNextNode inlineMacroNode(Invoke invoke, ResolvedJavaMethod concrete, Class macroNodeClass) throws GraalInternalError { diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableGraph.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableGraph.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableGraph.java Wed Apr 15 11:03:04 2015 -0700 @@ -59,7 +59,7 @@ private FixedNodeProbabilityCache probabilites = new FixedNodeProbabilityCache(); public InlineableGraph(final ResolvedJavaMethod method, final Invoke invoke, final HighTierContext context, CanonicalizerPhase canonicalizer) { - StructuredGraph original = getOriginalGraph(method, context, canonicalizer, invoke.asNode().graph()); + StructuredGraph original = getOriginalGraph(method, context, canonicalizer, invoke.asNode().graph(), invoke.bci()); // TODO copying the graph is only necessary if it is modified or if it contains any invokes this.graph = original.copy(); specializeGraphToArguments(invoke, context, canonicalizer); @@ -70,8 +70,8 @@ * The graph thus obtained is returned, ie the caller is responsible for cloning before * modification. */ - private static StructuredGraph getOriginalGraph(final ResolvedJavaMethod method, final HighTierContext context, CanonicalizerPhase canonicalizer, StructuredGraph caller) { - StructuredGraph result = InliningUtil.getIntrinsicGraph(context.getReplacements(), method); + private static StructuredGraph getOriginalGraph(final ResolvedJavaMethod method, final HighTierContext context, CanonicalizerPhase canonicalizer, StructuredGraph caller, int callerBci) { + StructuredGraph result = InliningUtil.getIntrinsicGraph(context.getReplacements(), method, callerBci); if (result != null) { return result; } diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/AbstractInliningPolicy.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/AbstractInliningPolicy.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/AbstractInliningPolicy.java Wed Apr 15 11:03:04 2015 -0700 @@ -66,7 +66,7 @@ private static boolean onlyIntrinsics(Replacements replacements, InlineInfo info) { for (int i = 0; i < info.numberOfMethods(); i++) { - if (!InliningUtil.canIntrinsify(replacements, info.methodAt(i))) { + if (!InliningUtil.canIntrinsify(replacements, info.methodAt(i), info.invoke().bci())) { return false; } } @@ -75,7 +75,7 @@ private static boolean onlyForcedIntrinsics(Replacements replacements, InlineInfo info) { for (int i = 0; i < info.numberOfMethods(); i++) { - if (!InliningUtil.canIntrinsify(replacements, info.methodAt(i))) { + if (!InliningUtil.canIntrinsify(replacements, info.methodAt(i), info.invoke().bci())) { return false; } if (!replacements.isForcedSubstitution(info.methodAt(i))) { diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/InlineMethodSubstitutionsPolicy.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/InlineMethodSubstitutionsPolicy.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/InlineMethodSubstitutionsPolicy.java Wed Apr 15 11:03:04 2015 -0700 @@ -38,7 +38,7 @@ CallTargetNode callTarget = invocation.callee().invoke().callTarget(); if (callTarget instanceof MethodCallTargetNode) { ResolvedJavaMethod calleeMethod = ((MethodCallTargetNode) callTarget).targetMethod(); - if (replacements.getSubstitution(calleeMethod) != null) { + if (replacements.getSubstitution(calleeMethod, invocation.callee().invoke().bci()) != null) { return true; } } diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java Wed Apr 15 11:03:04 2015 -0700 @@ -108,10 +108,10 @@ return (arg instanceof AbstractNewObjectNode) || (arg instanceof AllocatedObjectNode) || (arg instanceof VirtualObjectNode); } - private String checkTargetConditionsHelper(ResolvedJavaMethod method) { + private String checkTargetConditionsHelper(ResolvedJavaMethod method, int invokeBci) { if (method == null) { return "the method is not resolved"; - } else if (method.isNative() && (!Intrinsify.getValue() || !InliningUtil.canIntrinsify(context.getReplacements(), method))) { + } else if (method.isNative() && (!Intrinsify.getValue() || !InliningUtil.canIntrinsify(context.getReplacements(), method, invokeBci))) { return "it is a non-intrinsic native method"; } else if (method.isAbstract()) { return "it is an abstract method"; @@ -129,7 +129,7 @@ } private boolean checkTargetConditions(Invoke invoke, ResolvedJavaMethod method) { - final String failureMessage = checkTargetConditionsHelper(method); + final String failureMessage = checkTargetConditionsHelper(method, invoke.bci()); if (failureMessage == null) { return true; } else { diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/MethodSubstitutionTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/MethodSubstitutionTest.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/MethodSubstitutionTest.java Wed Apr 15 11:03:04 2015 -0700 @@ -76,7 +76,7 @@ StructuredGraph graph = testGraph(testMethodName); // Check to see if the resulting graph contains the expected node - StructuredGraph replacement = getReplacements().getSubstitution(realMethod); + StructuredGraph replacement = getReplacements().getSubstitution(realMethod, -1); if (replacement == null && !optional) { assertInGraph(graph, intrinsicClass); } diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StandardMethodSubstitutionsTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StandardMethodSubstitutionsTest.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StandardMethodSubstitutionsTest.java Wed Apr 15 11:03:04 2015 -0700 @@ -131,7 +131,7 @@ StructuredGraph graph = testGraph(testMethodName); // Check to see if the resulting graph contains the expected node - StructuredGraph replacement = getReplacements().getSubstitution(realJavaMethod); + StructuredGraph replacement = getReplacements().getSubstitution(realJavaMethod, -1); if (replacement == null && !optional) { assertInGraph(graph, intrinsicClass); } diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StringSubstitutionsTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StringSubstitutionsTest.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StringSubstitutionsTest.java Wed Apr 15 11:03:04 2015 -0700 @@ -41,7 +41,7 @@ StructuredGraph graph = testGraph(testMethodName); // Check to see if the resulting graph contains the expected node - StructuredGraph replacement = getReplacements().getSubstitution(realMethod); + StructuredGraph replacement = getReplacements().getSubstitution(realMethod, -1); if (replacement == null && !optional) { assertInGraph(graph, intrinsicClass); } diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/IntrinsicGraphBuilder.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/IntrinsicGraphBuilder.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/IntrinsicGraphBuilder.java Wed Apr 15 11:03:04 2015 -0700 @@ -45,16 +45,18 @@ private final StampProvider stampProvider; private final StructuredGraph graph; private final ResolvedJavaMethod method; + private final int invokeBci; private FixedWithNextNode lastInstr; private ValueNode[] arguments; private ValueNode returnValue; - public IntrinsicGraphBuilder(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, StampProvider stampProvider, ResolvedJavaMethod method) { + public IntrinsicGraphBuilder(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, StampProvider stampProvider, ResolvedJavaMethod method, int invokeBci) { this.metaAccess = metaAccess; this.constantReflection = constantReflection; this.stampProvider = stampProvider; this.graph = new StructuredGraph(method, AllowAssumptions.YES); this.method = method; + this.invokeBci = invokeBci; this.lastInstr = graph.start(); Signature sig = method.getSignature(); @@ -163,7 +165,7 @@ } public int bci() { - return -1; + return invokeBci; } public InvokeKind getInvokeKind() { diff -r 92fc95e8667d -r 23d6b95bd687 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 Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java Wed Apr 15 11:03:04 2015 -0700 @@ -334,17 +334,21 @@ } @Override - public StructuredGraph getSubstitution(ResolvedJavaMethod original, boolean fromBytecodeOnly) { + public StructuredGraph getSubstitution(ResolvedJavaMethod original, boolean fromBytecodeOnly, int invokeBci) { ResolvedJavaMethod substitute = null; if (!fromBytecodeOnly) { InvocationPlugin plugin = graphBuilderPlugins.getInvocationPlugins().lookupInvocation(original); - if (plugin instanceof MethodSubstitutionPlugin) { - MethodSubstitutionPlugin msplugin = (MethodSubstitutionPlugin) plugin; - substitute = msplugin.getSubstitute(providers.getMetaAccess()); - } else if (plugin != null) { - StructuredGraph graph = new IntrinsicGraphBuilder(providers.getMetaAccess(), providers.getConstantReflection(), providers.getStampProvider(), original).buildGraph(plugin); - if (graph != null) { - return graph; + if (plugin != null) { + if (!plugin.inlineOnly() || invokeBci >= 0) { + if (plugin instanceof MethodSubstitutionPlugin) { + MethodSubstitutionPlugin msplugin = (MethodSubstitutionPlugin) plugin; + substitute = msplugin.getSubstitute(providers.getMetaAccess()); + } else { + StructuredGraph graph = new IntrinsicGraphBuilder(providers.getMetaAccess(), providers.getConstantReflection(), providers.getStampProvider(), original, invokeBci).buildGraph(plugin); + if (graph != null) { + return graph; + } + } } } } @@ -806,10 +810,13 @@ return cr != null && cr.forcedSubstitutions.contains(method); } - public boolean hasSubstitution(ResolvedJavaMethod method, boolean fromBytecodeOnly) { + public boolean hasSubstitution(ResolvedJavaMethod method, boolean fromBytecodeOnly, int callerBci) { if (!fromBytecodeOnly) { - if (graphBuilderPlugins.getInvocationPlugins().lookupInvocation(method) != null) { - return true; + InvocationPlugin plugin = graphBuilderPlugins.getInvocationPlugins().lookupInvocation(method); + if (plugin != null) { + if (!plugin.inlineOnly() || callerBci >= 0) { + return true; + } } } return getSubstitutionMethod(method) != null; diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java Wed Apr 15 11:03:04 2015 -0700 @@ -74,6 +74,7 @@ this.targetMethod = targetMethod; this.returnType = returnType; this.invokeKind = invokeKind; + assert bci >= 0; } public int getBci() { @@ -108,7 +109,7 @@ * lowered}. */ protected StructuredGraph getLoweredSubstitutionGraph(LoweringTool tool) { - StructuredGraph methodSubstitution = tool.getReplacements().getSubstitution(getTargetMethod(), true); + StructuredGraph methodSubstitution = tool.getReplacements().getSubstitution(getTargetMethod(), true, bci); if (methodSubstitution != null) { methodSubstitution = methodSubstitution.copy(); if (stateAfter() == null || stateAfter().bci == BytecodeFrame.AFTER_BCI) { diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.graal.truffle.test/sl/TestInliningMaxCallerSize.sl --- a/graal/com.oracle.graal.truffle.test/sl/TestInliningMaxCallerSize.sl Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.graal.truffle.test/sl/TestInliningMaxCallerSize.sl Wed Apr 15 11:03:04 2015 -0700 @@ -2,11 +2,11 @@ * This test verifies that CallTargets cannot exceed the TruffleInliningMaxCallerSize limit when inlining. */ function inlinableFunction() { - generateDummyNodes(getOption("TruffleInliningMaxCallerSize") - 8); + generateDummyNodes(getOption("TruffleInliningMaxCallerSize") - 7); } function notInlinableFunction() { - generateDummyNodes(getOption("TruffleInliningMaxCallerSize") - 7); + generateDummyNodes(getOption("TruffleInliningMaxCallerSize") - 6); } function test1() { diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Wed Apr 15 11:03:04 2015 -0700 @@ -184,7 +184,7 @@ if (original.getAnnotation(TruffleBoundary.class) != null) { return null; } - assert !replacements.hasSubstitution(original) : "Replacements must have been processed by now"; + assert !replacements.hasSubstitution(original, builder.bci()) : "Replacements must have been processed by now"; assert !builder.parsingReplacement(); if (TruffleCompilerOptions.TruffleFunctionInlining.getValue()) { @@ -260,7 +260,7 @@ if (original.getAnnotation(TruffleBoundary.class) != null) { return null; } - assert !replacements.hasSubstitution(original) : "Replacements must have been processed by now"; + assert !replacements.hasSubstitution(original, builder.bci()) : "Replacements must have been processed by now"; if (original.equals(callSiteProxyMethod) || original.equals(callDirectMethod)) { return null; @@ -366,7 +366,7 @@ new ConvertDeoptimizeToGuardPhase().apply(graph, tierContext); for (MethodCallTargetNode methodCallTargetNode : graph.getNodes(MethodCallTargetNode.TYPE)) { - StructuredGraph inlineGraph = providers.getReplacements().getSubstitution(methodCallTargetNode.targetMethod()); + StructuredGraph inlineGraph = providers.getReplacements().getSubstitution(methodCallTargetNode.targetMethod(), methodCallTargetNode.invoke().bci()); if (inlineGraph != null) { InliningUtil.inline(methodCallTargetNode.invoke(), inlineGraph, true, null); } diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ArrayTest.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ArrayTest.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ArrayTest.java Wed Apr 15 11:03:04 2015 -0700 @@ -26,7 +26,6 @@ import com.oracle.truffle.api.*; import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.dsl.internal.*; import com.oracle.truffle.api.dsl.test.ArrayTestFactory.TestNode1NodeGen; import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.nodes.*; @@ -97,7 +96,6 @@ } @TypeSystem({int.class, int[].class, double[].class, String[].class, Object[].class}) - @DSLOptions(useNewLayout = true) public static class ArrayTypeSystem { @ImplicitCast diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteGroupingTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteGroupingTest.java Wed Apr 15 11:03:04 2015 -0700 @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.dsl.test; + +import org.junit.*; +import org.junit.experimental.theories.*; +import org.junit.runner.*; +import org.junit.runners.Parameterized.Parameters; + +import static org.junit.Assert.*; + +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.dsl.test.ExecuteGroupingTestFactory.ExecuteGrouping1NodeGen; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; + +/* + * This test aims to test the reuse of execute methods with evaluated parameters as much as possible. + */ +@SuppressWarnings("unused") +@RunWith(Theories.class) +public class ExecuteGroupingTest { + + @DataPoints public static final Object[] parameters = new Object[]{1, 2}; + + static final class ExecuteGroupingChild extends Node { + + int invocationCount = 0; + + private final Object returnValue; + + public ExecuteGroupingChild(Object returnValue) { + this.returnValue = returnValue; + } + + Object execute() { + invocationCount++; + return returnValue; + } + + } + + @Theory + public void testExecuteGrouping1Node(Object a, Object b, Object c) throws UnexpectedResultException { + ExecuteGroupingChild child0 = new ExecuteGroupingChild(a); + ExecuteGroupingChild child1 = new ExecuteGroupingChild(b); + ExecuteGroupingChild child2 = new ExecuteGroupingChild(c); + + int result = ((int) a) + ((int) b) + ((int) c); + + assertEquals(result, TestHelper.createRoot(ExecuteGrouping1NodeGen.create(child0, child1, child2)).execute()); + assertEquals(result, TestHelper.createRoot(ExecuteGrouping1NodeGen.create(child0, child1, child2)).execute((VirtualFrame) null)); + assertEquals(result, TestHelper.createRoot(ExecuteGrouping1NodeGen.create(null, child1, child2)).execute(a)); + assertEquals(result, TestHelper.createRoot(ExecuteGrouping1NodeGen.create(null, child1, child2)).executeInt(a)); + + assertEquals(result, TestHelper.createRoot(ExecuteGrouping1NodeGen.create(null, null, child2)).execute(a, b)); + assertEquals(result, TestHelper.createRoot(ExecuteGrouping1NodeGen.create(null, null, child2)).execute((int) a, b)); + assertEquals(result, TestHelper.createRoot(ExecuteGrouping1NodeGen.create(null, null, child2)).execute(a, (int) b)); + assertEquals(result, TestHelper.createRoot(ExecuteGrouping1NodeGen.create(null, null, child2)).execute((int) a, (int) b)); + assertEquals(result, TestHelper.createRoot(ExecuteGrouping1NodeGen.create(null, null, child2)).executeInt((int) a, (int) b)); + + assertEquals(result, TestHelper.createRoot(ExecuteGrouping1NodeGen.create(null, null, null)).execute(a, b, c)); + assertEquals(result, TestHelper.createRoot(ExecuteGrouping1NodeGen.create(null, null, null)).execute((int) a, (int) b, c)); + assertEquals(result, TestHelper.createRoot(ExecuteGrouping1NodeGen.create(null, null, null)).execute((int) a, (int) b, (int) c)); + + } + + @NodeChildren({@NodeChild(type = ExecuteGroupingChild.class), @NodeChild(type = ExecuteGroupingChild.class), @NodeChild(type = ExecuteGroupingChild.class)}) + abstract static class ExecuteGrouping1Node extends Node { + + abstract Object execute(); + + int executeInt() throws UnexpectedResultException { + Object value = execute(); + if (value instanceof Integer) { + return (int) value; + } + throw new UnexpectedResultException(value); + } + + abstract double executeDouble() throws UnexpectedResultException; + + abstract Object execute(VirtualFrame frame); + + abstract Object execute(Object o1); + + abstract int executeInt(Object o1) throws UnexpectedResultException; + + abstract Object execute(Object o1, Object o2); + + abstract Object execute(int o1, int o2); + + abstract Object execute(int o1, int o2, Object o3); + + abstract int executeInt(int o1, int o2) throws UnexpectedResultException; + + abstract Object execute(Object o1, int o2); + + abstract Object execute(int o1, Object o2); + + abstract Object execute(Object o1, Object o2, Object o3); + + abstract Object execute(int o1, int o2, int o3); + + @Specialization + int s1(int a, int b, int c) { + return a + b + c; + } + + @Specialization + int s2(Object a, Object b, Object c) { + return ((int) a) + ((int) b) + ((int) c); + } + + } + + abstract static class StrangeReturnCase extends Node { + + // we don't know how to implement executeDouble + public abstract double executeDouble(); + + public int executeInt() { + return 42; + } + + @Specialization(rewriteOn = RuntimeException.class) + int s1() { + return 42; + } + + @Specialization + int s2() { + return 42; + } + + } + + @ExpectError("Incompatible abstract execute methods found [executeDouble(), executeInt()].%") + abstract static class IncompatibleAbstract1 extends Node { + + // we don't know how to implement executeDouble + abstract double executeDouble(); + + abstract int executeInt(); + + @Specialization + int s1() { + return 42; + } + + } + + abstract static class IncompatibleAbstract2 extends Node { + + abstract double executeDouble(); + + // we can resolve duplicate path errors by making an execute method final + @SuppressWarnings("static-method") + public final int executeInt() { + return 42; + } + + @ExpectError("The provided return type \"int\" does not match expected return type \"double\".%") + @Specialization(rewriteOn = RuntimeException.class) + int s1() { + return 42; + } + + @Specialization + double s2() { + return 42; + } + + } + +} diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteMethodTest.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteMethodTest.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteMethodTest.java Wed Apr 15 11:03:04 2015 -0700 @@ -137,7 +137,6 @@ @TypeSystemReference(ExecuteMethodTypes.class) @NodeChild(value = "a", type = ChildNoFrame.class) - @ExpectError("Multiple accessible and overridable generic execute methods found [executeInt(), executeObject()]. Remove all but one or mark all but one as final.") abstract static class ExecuteThis8 extends Node { abstract int executeInt(); @@ -175,8 +174,7 @@ abstract void executeVoid(); @Specialization - int doInt(int a) { - return a; + void doInt(@SuppressWarnings("unused") int a) { } } @@ -197,7 +195,6 @@ @TypeSystemReference(ExecuteMethodTypes.class) @NodeChild(value = "a", type = ChildNoFrame.class) - @ExpectError("Multiple accessible and overridable generic execute methods found [executeVoid1(), executeVoid2()]. Remove all but one or mark all but one as final.") abstract static class ExecuteThisVoid3 extends Node { // allow only one execute void diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/FallbackTest.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/FallbackTest.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/FallbackTest.java Wed Apr 15 11:03:04 2015 -0700 @@ -32,6 +32,7 @@ import com.oracle.truffle.api.dsl.test.FallbackTestFactory.Fallback3Factory; import com.oracle.truffle.api.dsl.test.FallbackTestFactory.Fallback4Factory; import com.oracle.truffle.api.dsl.test.TypeSystemTest.*; +import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.nodes.*; public class FallbackTest { @@ -53,6 +54,9 @@ @NodeChild("a") abstract static class Fallback1 extends ValueNode { + @Override + public abstract String executeString(VirtualFrame frame); + @Specialization String f1(int a) { return "(int)"; diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/NoTypeSystemTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/NoTypeSystemTest.java Wed Apr 15 11:03:04 2015 -0700 @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.dsl.test; + +import org.junit.*; + +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.dsl.test.NoTypeSystemTestFactory.JustFrameTestNodeGen; +import com.oracle.truffle.api.dsl.test.NoTypeSystemTestFactory.NoParameterTestNodeGen; +import com.oracle.truffle.api.dsl.test.NoTypeSystemTestFactory.ObjectInterfaceNodeGen; +import com.oracle.truffle.api.dsl.test.NoTypeSystemTestFactory.ObjectPrimitiveTestNodeGen; +import com.oracle.truffle.api.dsl.test.NoTypeSystemTestFactory.ObjectStringTestNodeGen; +import com.oracle.truffle.api.dsl.test.NoTypeSystemTestFactory.PrimitiveTestNodeGen; +import com.oracle.truffle.api.dsl.test.NoTypeSystemTestFactory.TypesNotInTypeSystemTestNodeGen; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; + +public class NoTypeSystemTest { + + abstract static class DummyChild extends Node { + abstract Object execute(); + } + + abstract static class NoParameterTestNode extends Node { + abstract void execute(); + + @Specialization + void s1() { + } + } + + @Test + public void testNoParameter() { + NoParameterTestNodeGen.create().execute(); + } + + abstract static class JustFrameTestNode extends Node { + + abstract void execute(VirtualFrame frames); + + @Specialization + void s1(@SuppressWarnings("unused") VirtualFrame frame) { + } + } + + @Test + public void testJustFrame() { + JustFrameTestNodeGen.create().execute(null); + } + + abstract static class PrimitiveTestNode extends Node { + + abstract int execute(int primitive); + + @Specialization + int test(int primitive) { + return primitive; + } + + } + + @Test + public void testPrimitive() { + Assert.assertEquals(42, PrimitiveTestNodeGen.create().execute(42)); + } + + abstract static class ObjectInterfaceNode extends Node { + + abstract CharSequence execute(Object operand); + + @Specialization + CharSequence s1(CharSequence operandSpecial) { + return operandSpecial; + } + } + + @Test + public void testObjectInterface() { + Assert.assertEquals("42", ObjectInterfaceNodeGen.create().execute("42")); + } + + abstract static class ObjectPrimitiveTestNode extends Node { + + abstract int execute(Object primitive); + + @Specialization + int s1(int primitive) { + return primitive; + } + + } + + @Test + public void testObjectPrimitiveTest() { + Assert.assertEquals(42, ObjectPrimitiveTestNodeGen.create().execute(42)); + } + + abstract static class ObjectStringTestNode extends Node { + + abstract String execute(Object operand); + + @Specialization + String s1(String operand) { + return operand; + } + } + + @Test + public void testObjectStringTest() { + Assert.assertEquals("42", ObjectStringTestNodeGen.create().execute("42")); + } + + abstract static class TypesNotInTypeSystemTest extends Node { + + abstract Object execute(Object primitive); + + abstract int executeInt(Object primitive) throws UnexpectedResultException; + + abstract double executeDouble(Object primitive) throws UnexpectedResultException; + + abstract String executeString(Object primitive) throws UnexpectedResultException; + + abstract int[] executeIntArray(Object primitive) throws UnexpectedResultException; + + abstract void executeVoid(Object primitive); + + abstract void executeChar(Object primitive); + + abstract int executeInt(int primitive) throws UnexpectedResultException; + + abstract double executeDouble(double primitive) throws UnexpectedResultException; + + abstract String executeString(String primitive) throws UnexpectedResultException; + + abstract int[] executeIntArray(int[] primitive) throws UnexpectedResultException; + + abstract void executeChar(char primitive); + + @Specialization + int s1(int primitive) { + return primitive; + } + + @Specialization + double s2(double primitive) { + return (int) primitive; + } + + @Specialization + String s3(String object) { + return object; + } + + @Specialization + int[] s4(int[] object) { + return object; + } + + @Specialization + void s5(@SuppressWarnings("unused") char object) { + } + + } + + @Test + public void testTypesNotInTypeSystem() throws UnexpectedResultException { + int[] someArray = {1, 2, 3}; + Assert.assertEquals(42, createTypesNotInTypeSystem().execute(42)); + Assert.assertEquals(42d, createTypesNotInTypeSystem().execute(42d)); + Assert.assertEquals(someArray, createTypesNotInTypeSystem().execute(someArray)); + Assert.assertNull(createTypesNotInTypeSystem().execute((char) 42)); + + Assert.assertEquals(42, createTypesNotInTypeSystem().executeInt((Object) 42)); + Assert.assertEquals(42d, createTypesNotInTypeSystem().executeDouble((Object) 42d), 0d); + Assert.assertEquals(someArray, createTypesNotInTypeSystem().executeIntArray((Object) someArray)); + createTypesNotInTypeSystem().executeChar((Object) (char) 42); + + Assert.assertEquals(42, createTypesNotInTypeSystem().executeInt(42)); + Assert.assertEquals(42d, createTypesNotInTypeSystem().executeDouble(42d), 0d); + Assert.assertEquals(someArray, createTypesNotInTypeSystem().executeIntArray(someArray)); + createTypesNotInTypeSystem().executeChar((char) 42); + + try { + createTypesNotInTypeSystem().executeInt("a"); + Assert.fail(); + } catch (UnexpectedResultException e) { + } + + try { + createTypesNotInTypeSystem().executeDouble("a"); + Assert.fail(); + } catch (UnexpectedResultException e) { + } + + try { + createTypesNotInTypeSystem().executeIntArray("a"); + Assert.fail(); + } catch (UnexpectedResultException e) { + } + + createTypesNotInTypeSystem().executeChar("a"); + + } + + private static TypesNotInTypeSystemTest createTypesNotInTypeSystem() { + return TestHelper.createRoot(TypesNotInTypeSystemTestNodeGen.create()); + } + + abstract static class ErrorImpossibleTypes1 extends Node { + + abstract int execute(int primitive); + + @Specialization + int test(int primitive) { + return primitive; + } + + @ExpectError("The provided return type \"Object\" does not match expected return type \"int\".%") + @Specialization + Object s2(int arg0) { + return arg0; + } + } + + abstract static class ErrorImpossibleTypes2 extends Node { + + abstract int execute(int primitive); + + @Specialization + int test(int primitive) { + return primitive; + } + + @ExpectError("Method signature (Object) does not match to the expected signature: %") + @Specialization + int s2(Object arg0) { + return (int) arg0; + } + } + + @ExpectError("Not enough child node declarations found. Please annotate the node class with addtional @NodeChild annotations or remove all execute methods that do not provide all evaluated values. " + + "The following execute methods do not provide all evaluated values for the expected signature size 1: [execute()].") + abstract static class ErrorMissingNodeChild1 extends Node { + + abstract int execute(); + + @Specialization + int s1(int arg0) { + return arg0; + } + } + + @ExpectError("Not enough child node declarations found. Please annotate the node class with addtional @NodeChild annotations or remove all execute methods that do not provide all evaluated values. " + + "The following execute methods do not provide all evaluated values for the expected signature size 2: [execute(int)].") + @NodeChild(type = DummyChild.class) + abstract static class ErrorMissingNodeChild2 extends Node { + + abstract int execute(int arg0); + + @Specialization + int s1(int arg0, int arg1) { + return arg0 + arg1; + } + } + + @ExpectError("Not enough child node declarations found. Please annotate the node class with addtional @NodeChild annotations or remove all execute methods that do not provide all evaluated values. " + + "The following execute methods do not provide all evaluated values for the expected signature size 1: [execute()].") + abstract static class ErrorMissingNodeChild3 extends Node { + + abstract int execute(); + + abstract int execute(int arg0); + + @Specialization + int s1(int arg0) { + return arg0; + } + + } + + @ExpectError("Unnecessary @NodeChild declaration. All evaluated child values are provided as parameters in execute methods.") + @NodeChild(type = DummyChild.class) + abstract static class ErrorAdditionalNodeChild1 extends Node { + + abstract int execute(int arg0); + + @Specialization + int s1(int arg0) { + return arg0; + } + } + + @NodeChild(type = DummyChild.class) + @ExpectError("Not enough child node declarations found. Please annotate the node class with addtional @NodeChild annotations or remove all execute methods that do not provide all evaluated values. " + + "The following execute methods do not provide all evaluated values for the expected signature size 2: [execute(int)].") + abstract static class ErrorAdditionalNodeChild2 extends Node { + + abstract int execute(int arg0); + + @Specialization + int s1(int arg0, int arg1) { + return arg0 + arg1; + } + } + +} diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/NodeChildTest.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/NodeChildTest.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/NodeChildTest.java Wed Apr 15 11:03:04 2015 -0700 @@ -71,10 +71,11 @@ } + @ExpectError("Not enough child node declarations found. Please annotate the node class with addtional @NodeChild annotations or remove all execute methods that do not provide all evaluated values. " + + "The following execute methods do not provide all evaluated values for the expected signature size 3:%") @NodeChildren({@NodeChild(value = "child2", type = ValueNode.class)}) abstract static class Child2Node extends Base1Node { - // TODO this is an error to fix @ExpectError("Method signature (int, int, int) does not match to the expected signature:%") @Specialization int intField(int child0, int child1, int child2) { diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/NodeFieldTest.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/NodeFieldTest.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/NodeFieldTest.java Wed Apr 15 11:03:04 2015 -0700 @@ -123,7 +123,7 @@ } @Specialization(contains = "alwaysRewrite") - String returnField() { + Object returnField() { return getField(); } } diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/NullLiteralGuardsTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/NullLiteralGuardsTest.java Wed Apr 15 11:03:04 2015 -0700 @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.dsl.test; + +import static com.oracle.truffle.api.dsl.test.TestHelper.*; +import static org.junit.Assert.*; + +import org.junit.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.dsl.test.NullLiteralGuardsTestFactory.CompareNotNullNodeFactory; +import com.oracle.truffle.api.dsl.test.NullLiteralGuardsTestFactory.CompareObjectsNullNodeFactory; +import com.oracle.truffle.api.dsl.test.NullLiteralGuardsTestFactory.CompareStringNullNodeFactory; +import com.oracle.truffle.api.dsl.test.TypeSystemTest.ChildrenNode; + +@SuppressWarnings("unused") +public class NullLiteralGuardsTest { + + @Test + public void testCompareObjectsNull() { + CallTarget root = createCallTarget(CompareObjectsNullNodeFactory.getInstance()); + assertEquals("do1", root.call((Object) null)); + assertEquals("do2", root.call("42")); + } + + abstract static class CompareObjectsNullNode extends ChildrenNode { + @Specialization(guards = "value == null") + String do1(Object value) { + return "do1"; + } + + @Specialization + String do2(Object value) { + return "do2"; + } + } + + @Test + public void testCompareStringNull() { + CallTarget root = createCallTarget(CompareStringNullNodeFactory.getInstance()); + assertEquals("do1", root.call("42")); + assertEquals("do2", root.call((Object) null)); + } + + abstract static class CompareStringNullNode extends ChildrenNode { + @Specialization(guards = "value != null") + String do1(String value) { + return "do1"; + } + + @Specialization + String do2(Object value) { + return "do2"; + } + } + + @Test + public void testCompareNotNull() { + CallTarget root = createCallTarget(CompareNotNullNodeFactory.getInstance()); + assertEquals("do1", root.call("42")); + assertEquals("do2", root.call((Object) null)); + } + + abstract static class CompareNotNullNode extends ChildrenNode { + @Specialization(guards = "value != null") + String do1(Object value) { + return "do1"; + } + + @Specialization + String do2(Object value) { + return "do2"; + } + } + + abstract static class ErrorNullIntComparison1 extends ChildrenNode { + @ExpectError("Error parsing expression 'value == null': Incompatible operand types int and null.") + @Specialization(guards = "value == null") + String do1(int value) { + return "do1"; + } + } + + abstract static class ErrorNullIntComparison2 extends ChildrenNode { + @ExpectError("Error parsing expression '1 == null': Incompatible operand types int and null.") + @Specialization(guards = "1 == null") + String do1(int value) { + return "do1"; + } + } + + abstract static class ErrorNullNullComparison extends ChildrenNode { + @ExpectError("Error parsing expression 'null == null': The operator == is undefined for the argument type(s) null null.") + @Specialization(guards = "null == null") + String do1(int value) { + return "do1"; + } + } + + abstract static class ErrorObjectVoidComparison extends ChildrenNode { + protected static void returnVoid() { + } + + @ExpectError("Error parsing expression 'value == returnVoid()': Incompatible operand types Object and void.") + @Specialization(guards = "value == returnVoid()") + String do1(Object value) { + return "do1"; + } + } + +} diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TestHelper.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TestHelper.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TestHelper.java Wed Apr 15 11:03:04 2015 -0700 @@ -32,12 +32,27 @@ import com.oracle.truffle.api.dsl.test.TypeSystemTest.ChildrenNode; import com.oracle.truffle.api.dsl.test.TypeSystemTest.TestRootNode; import com.oracle.truffle.api.dsl.test.TypeSystemTest.ValueNode; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; /** * Utility class to provide some test helper functions. */ class TestHelper { + // make nodes replacable + public static T createRoot(final T node) { + new RootNode() { + @Child T child = node; + + @Override + public Object execute(VirtualFrame frame) { + return null; + } + }.adoptChildren(); + return node; + } + private static ArgumentNode[] arguments(int count) { ArgumentNode[] nodes = new ArgumentNode[count]; for (int i = 0; i < nodes.length; i++) { diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TypeSystemErrorsTest.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TypeSystemErrorsTest.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TypeSystemErrorsTest.java Wed Apr 15 11:03:04 2015 -0700 @@ -102,15 +102,6 @@ } } - @TypeSystem({boolean.class}) - public static class CastError3 { - @ExpectError("The type 'int' is not declared in the @TypeSystem.") - @TypeCast(int.class) - public static int asInt(Object value) { - return (int) value; - } - } - @TypeSystem({int.class}) public static class CastError4 { @ExpectError("@TypeCast annotated method asInt must be public and static.") @@ -129,15 +120,6 @@ } } - @TypeSystem({boolean.class}) - public static class CheckError1 { - @ExpectError("The type 'int' is not declared in the @TypeSystem.") - @TypeCheck(int.class) - public static boolean isInt(Object value) { - return value instanceof Integer; - } - } - @TypeSystem({int.class}) public static class CheckError2 { @ExpectError("@TypeCheck annotated method isInt must be public and static.") diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/examples/RubyCall.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/examples/RubyCall.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/examples/RubyCall.java Wed Apr 15 11:03:04 2015 -0700 @@ -96,12 +96,12 @@ public static class RubyHeadNode extends ExampleNode { - @Child private RubyLookupNode lookup = RubyLookupNodeGen.create(null); - @Child private RubyDispatchNode dispatch = RubyDispatchNodeGen.create(null); + @Child private RubyLookupNode lookup = RubyLookupNodeGen.create(); + @Child private RubyDispatchNode dispatch = RubyDispatchNodeGen.create(); @Specialization - public Object doCall(VirtualFrame frame, Object receiverObject, Object methodName, Object blockObject, Object... argumentsObjects) { - InternalMethod method = lookup.executeLookup(frame, receiverObject, methodName); + public Object doCall(VirtualFrame frame, RubyObject receiverObject, Object methodName, Object blockObject, Object... argumentsObjects) { + InternalMethod method = lookup.executeLookup(receiverObject, methodName); Object[] packedArguments = new Object[argumentsObjects.length + 3]; packedArguments[0] = method; @@ -113,9 +113,9 @@ } } - public abstract static class RubyLookupNode extends ExampleNode { + public abstract static class RubyLookupNode extends Node { - public abstract InternalMethod executeLookup(VirtualFrame frame, Object receiverObject, Object methodName); + public abstract InternalMethod executeLookup(RubyObject receiver, Object method); @Specialization(guards = "receiver.getRubyClass() == cachedClass", assumptions = "cachedClass.getDependentAssumptions()") protected static InternalMethod cachedLookup(RubyObject receiver, Object name, // @@ -132,7 +132,7 @@ } @ImportStatic(InternalMethod.class) - public abstract static class RubyDispatchNode extends ExampleNode { + public abstract static class RubyDispatchNode extends Node { public abstract Object executeDispatch(VirtualFrame frame, InternalMethod function, Object[] packedArguments); diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java Wed Apr 15 11:03:04 2015 -0700 @@ -62,24 +62,25 @@ * * *
  • The effect of the binding is to intercept {@linkplain TruffleEvents execution events} - * arriving at the "probed" AST node and notify each attached {@link Instrument} before execution is + * arriving at the "probed" AST Node and notify each attached {@link Instrument} before execution is * allowed to proceed to the child and again after execution completes.
  • * - *
  • A Probe is "inserted" into a GL node via a call to {@link Node#probe()}. No more than one - * Probe can be inserted at a node; a redundant call returns the existing Probe<./li> + *
  • The method {@link Node#probe()} creates a Probe on an AST Node; redundant calls return the + * same Probe.
  • * *
  • The "probing" of a Truffle AST must be done after the AST is complete (i.e. parent pointers * correctly assigned), but before any cloning or executions. This is done by creating an instance - * of {@link ASTProber} and registering it via {@link #registerASTProber(ASTProber)}, after which it - * will be applied automatically to every newly created AST.
  • + * of {@link ASTProber} and registering it via {@link #registerASTProber(ASTProber)}. Once + * registered, it will be applied automatically to every newly created AST. * - *
  • An AST node becomes probed by insertion of a {@link ProbeNode.WrapperNode} into the - * AST, together with an associated {@link ProbeNode} that routes events to all the - * {@linkplain Instrument Instruments} attached to its instrument chain.
  • + *
  • The "probing" of an AST Node is implemented by insertion of a {@link ProbeNode.WrapperNode} + * into the AST (as new parent of the Node being probed), together with an associated + * {@link ProbeNode} that routes execution events at the probed Node to all the + * {@linkplain Instrument Instruments} attached to the Probe's instrument chain.
  • * *
  • When Truffle clones an AST, any attached WrapperNodes and ProbeNodes are cloned as well, - * together with their attached instrument chains. The {@link Probe} instance intercepts cloning - * events and keeps track of all copies.
  • + * together with their attached instrument chains. Each Probe instance intercepts cloning events and + * keeps track of all AST copies. * *
  • All attached {@link InstrumentationNode}s effectively become part of the running program: *
      diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeNode.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeNode.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeNode.java Wed Apr 15 11:03:04 2015 -0700 @@ -42,8 +42,9 @@ *

      * When Truffle clones an AST, the chain, including all attached {@linkplain Instrument instruments} * will be cloned along with the {@link WrapperNode} to which it is attached. An instance of - * {@link Probe} represents abstractly the instrumentation at a particular location in a GL AST, - * tracks the clones of the chain, and keeps the instrumentation attached to the clones consistent. + * {@link Probe} represents abstractly the instrumentation at a particular location in a Guest + * Language AST, tracks the clones of the chain, and keeps the instrumentation attached to the + * clones consistent. */ @NodeInfo(cost = NodeCost.NONE) public final class ProbeNode extends Node implements TruffleEvents, InstrumentationNode { diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ProcessorContext.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ProcessorContext.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ProcessorContext.java Wed Apr 15 11:03:04 2015 -0700 @@ -88,6 +88,10 @@ return (DeclaredType) ElementUtils.getType(environment, element); } + public boolean isType(TypeMirror type, Class clazz) { + return ElementUtils.typeEquals(type, getType(clazz)); + } + public TypeMirror getType(Class element) { return ElementUtils.getType(environment, element); } diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/expression/DSLExpressionResolver.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/expression/DSLExpressionResolver.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/expression/DSLExpressionResolver.java Wed Apr 15 11:03:04 2015 -0700 @@ -197,27 +197,32 @@ public void visitVariable(Variable variable) { List lookupVariables; DSLExpression receiver = variable.getReceiver(); - if (receiver == null) { - lookupVariables = this.variables; + if (variable.getName().equals("null")) { + variable.setResolvedVariable(new CodeVariableElement(new CodeTypeMirror(TypeKind.NULL), "null")); } else { - TypeMirror type = receiver.getResolvedType(); - if (type.getKind() == TypeKind.DECLARED) { - type = context.reloadType(type); // ensure ECJ has the type loaded - lookupVariables = new ArrayList<>(); - variablesIn(lookupVariables, context.getEnvironment().getElementUtils().getAllMembers((TypeElement) ((DeclaredType) type).asElement()), true); - } else if (type.getKind() == TypeKind.ARRAY) { - lookupVariables = Arrays. asList(new CodeVariableElement(context.getType(int.class), "length")); + if (receiver == null) { + lookupVariables = this.variables; } else { - lookupVariables = Collections.emptyList(); + TypeMirror type = receiver.getResolvedType(); + if (type.getKind() == TypeKind.DECLARED) { + type = context.reloadType(type); // ensure ECJ has the type loaded + lookupVariables = new ArrayList<>(); + variablesIn(lookupVariables, context.getEnvironment().getElementUtils().getAllMembers((TypeElement) ((DeclaredType) type).asElement()), true); + } else if (type.getKind() == TypeKind.ARRAY) { + lookupVariables = Arrays. asList(new CodeVariableElement(context.getType(int.class), "length")); + } else { + lookupVariables = Collections.emptyList(); + } + } + + for (VariableElement variableElement : lookupVariables) { + if (variableElement.getSimpleName().toString().equals(variable.getName())) { + variable.setResolvedVariable(variableElement); + break; + } } } - for (VariableElement variableElement : lookupVariables) { - if (variableElement.getSimpleName().toString().equals(variable.getName())) { - variable.setResolvedVariable(variableElement); - break; - } - } if (variable.getResolvedVariable() == null) { throw new InvalidExpressionException(String.format("%s cannot be resolved.", variable.getName())); } diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/DSLExpressionGenerator.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/DSLExpressionGenerator.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/DSLExpressionGenerator.java Wed Apr 15 11:03:04 2015 -0700 @@ -25,6 +25,7 @@ import java.util.*; import javax.lang.model.element.*; +import javax.lang.model.type.*; import com.oracle.truffle.dsl.processor.expression.*; import com.oracle.truffle.dsl.processor.expression.DSLExpression.Binary; @@ -97,7 +98,9 @@ public void visitVariable(Variable variable) { VariableElement resolvedVariable = variable.getResolvedVariable(); CodeTree tree; - if (variable.getReceiver() == null) { + if (variable.getResolvedType().getKind() == TypeKind.NULL) { + tree = CodeTreeBuilder.singleString("null"); + } else if (variable.getReceiver() == null) { if (isStatic(resolvedVariable)) { tree = staticReference(resolvedVariable); diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/GeneratorUtils.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/GeneratorUtils.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/GeneratorUtils.java Wed Apr 15 11:03:04 2015 -0700 @@ -85,14 +85,14 @@ return method; } - public static boolean isTypeBoxingOptimized(TypeBoxingOptimization boxing, TypeData type) { + public static boolean isTypeBoxingOptimized(TypeBoxingOptimization boxing, TypeMirror type) { switch (boxing) { case NONE: return false; case ALWAYS: - return !type.isGeneric() && !type.isVoid(); + return !ElementUtils.isObject(type) && !ElementUtils.isVoid(type); case PRIMITIVE: - return type.isPrimitive(); + return ElementUtils.isPrimitive(type); default: throw new AssertionError(); } diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/ImplicitCastNodeFactory.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/ImplicitCastNodeFactory.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/ImplicitCastNodeFactory.java Wed Apr 15 11:03:04 2015 -0700 @@ -44,31 +44,30 @@ public class ImplicitCastNodeFactory { private final ProcessorContext context; - private final TypeData forType; + private final TypeMirror forType; private final TypeSystemData typeSystem; private final DSLOptions options; - private final List sourceTypes; + private final List sourceTypes; - public ImplicitCastNodeFactory(ProcessorContext context, TypeData forType) { + public ImplicitCastNodeFactory(ProcessorContext context, TypeSystemData typeSystem, TypeMirror forType) { this.context = context; this.forType = forType; - this.typeSystem = forType.getTypeSystem(); + this.typeSystem = typeSystem; this.options = typeSystem.getOptions(); this.sourceTypes = typeSystem.lookupSourceTypes(forType); } - public static String typeName(TypeData type) { - return "Implicit" + getTypeId(type.getBoxedType()) + "Cast"; + public static String typeName(TypeMirror type) { + return "Implicit" + getTypeId(type) + "Cast"; } - public static TypeMirror type(TypeData type) { - TypeSystemData typeSystem = type.getTypeSystem(); + public static TypeMirror type(TypeSystemData typeSystem, TypeMirror type) { String typeSystemName = TypeSystemCodeGenerator.typeName(typeSystem); return new GeneratedTypeMirror(ElementUtils.getPackageName(typeSystem.getTemplateType()) + "." + typeSystemName, typeName(type)); } - public static CodeTree create(TypeData type, CodeTree value) { - return CodeTreeBuilder.createBuilder().startStaticCall(type(type), "create").tree(value).end().build(); + public static CodeTree create(TypeSystemData typeSystem, TypeMirror type, CodeTree value) { + return CodeTreeBuilder.createBuilder().startStaticCall(type(typeSystem, type), "create").tree(value).end().build(); } public static CodeTree cast(String nodeName, CodeTree value) { @@ -79,8 +78,8 @@ return CodeTreeBuilder.createBuilder().startCall(nodeName, "check").tree(value).end().build(); } - private static String seenFieldName(TypeData type) { - return "seen" + getTypeId(type.getBoxedType()); + private static String seenFieldName(TypeMirror type) { + return "seen" + getTypeId(type); } public CodeTypeElement create() { @@ -88,7 +87,7 @@ TypeMirror baseType = context.getType(Object.class); CodeTypeElement clazz = GeneratorUtils.createClass(typeSystem, null, modifiers(PUBLIC, FINAL, STATIC), typeName, baseType); - for (TypeData sourceType : sourceTypes) { + for (TypeMirror sourceType : sourceTypes) { CodeVariableElement hasSeen = new CodeVariableElement(modifiers(PUBLIC), context.getType(boolean.class), seenFieldName(sourceType)); hasSeen.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(CompilationFinal.class))); clazz.add(hasSeen); @@ -113,7 +112,7 @@ CodeTreeBuilder builder = method.createBuilder(); builder.startReturn(); String operator = ""; - for (TypeData sourceType : sourceTypes) { + for (TypeMirror sourceType : sourceTypes) { builder.string(operator); builder.string(seenFieldName(sourceType)); operator = " ^ "; @@ -129,15 +128,15 @@ private Element createCreate(CodeTypeElement clazz) { String methodName = "create"; CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), clazz.asType(), methodName); - method.addParameter(new CodeVariableElement(typeSystem.getGenericType(), "value")); + method.addParameter(new CodeVariableElement(context.getType(Object.class), "value")); CodeTreeBuilder builder = method.createBuilder(); builder.declaration(clazz.asType(), "newCast", builder.create().startNew(clazz.asType()).end()); - for (TypeData sourceType : sourceTypes) { + for (TypeMirror sourceType : sourceTypes) { String seenField = seenFieldName(sourceType); builder.startStatement(); - builder.string("newCast.").string(seenField).string(" = ").tree(TypeSystemCodeGenerator.check(sourceType, "value")); + builder.string("newCast.").string(seenField).string(" = ").tree(TypeSystemCodeGenerator.check(typeSystem, sourceType, "value")); builder.end(); } builder.startReturn().string("newCast").end(); @@ -150,7 +149,7 @@ method.addParameter(new CodeVariableElement(clazz.asType(), "otherCast")); CodeTreeBuilder builder = method.createBuilder(); - for (TypeData sourceType : sourceTypes) { + for (TypeMirror sourceType : sourceTypes) { String seenField = seenFieldName(sourceType); builder.startStatement(); builder.string("this.").string(seenField).string(" |= ").string("otherCast.").string(seenField); @@ -162,13 +161,13 @@ private Element createCheck() { String methodName = "check"; CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), context.getType(boolean.class), methodName); - method.addParameter(new CodeVariableElement(typeSystem.getGenericType(), "value")); + method.addParameter(new CodeVariableElement(context.getType(Object.class), "value")); CodeTreeBuilder builder = method.createBuilder(); boolean elseIf = false; - for (TypeData sourceType : sourceTypes) { + for (TypeMirror sourceType : sourceTypes) { elseIf = builder.startIf(elseIf); - builder.string(seenFieldName(sourceType)).string(" && ").tree(TypeSystemCodeGenerator.check(sourceType, "value")); + builder.string(seenFieldName(sourceType)).string(" && ").tree(TypeSystemCodeGenerator.check(typeSystem, sourceType, "value")); builder.end(); builder.startBlock().returnTrue().end(); } @@ -178,8 +177,8 @@ private Element createCast(boolean expect) { String methodName = expect ? "expect" : "cast"; - CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), forType.getPrimitiveType(), methodName); - method.addParameter(new CodeVariableElement(typeSystem.getGenericType(), "value")); + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), forType, methodName); + method.addParameter(new CodeVariableElement(context.getType(Object.class), "value")); if (expect) { method.getThrownTypes().add(context.getType(UnexpectedResultException.class)); } @@ -187,16 +186,16 @@ CodeTreeBuilder builder = method.createBuilder(); boolean elseIf = false; - for (TypeData sourceType : sourceTypes) { + for (TypeMirror sourceType : sourceTypes) { elseIf = builder.startIf(elseIf); - builder.string(seenFieldName(sourceType)).string(" && ").tree(TypeSystemCodeGenerator.check(sourceType, "value")); + builder.string(seenFieldName(sourceType)).string(" && ").tree(TypeSystemCodeGenerator.check(typeSystem, sourceType, "value")); builder.end(); builder.startBlock(); builder.startReturn(); - CodeTree castTree = TypeSystemCodeGenerator.cast(sourceType, "value"); + CodeTree castTree = TypeSystemCodeGenerator.cast(typeSystem, sourceType, "value"); ImplicitCastData cast = typeSystem.lookupCast(sourceType, forType); if (cast != null) { - builder.tree(TypeSystemCodeGenerator.invokeImplicitCast(cast, castTree)); + builder.tree(TypeSystemCodeGenerator.invokeImplicitCast(typeSystem, cast, castTree)); } else { builder.tree(castTree); } diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeCodeGenerator.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeCodeGenerator.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeCodeGenerator.java Wed Apr 15 11:03:04 2015 -0700 @@ -152,7 +152,7 @@ } prev = child.getNodeType(); } - TypeMirror commonNodeSuperType = ElementUtils.getCommonSuperType(context, nodeTypesList.toArray(new TypeMirror[nodeTypesList.size()])); + TypeMirror commonNodeSuperType = ElementUtils.getCommonSuperType(context, nodeTypesList); Types types = context.getEnvironment().getTypeUtils(); TypeMirror factoryType = context.getType(NodeFactory.class); diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java Wed Apr 15 11:03:04 2015 -0700 @@ -61,19 +61,25 @@ private final ProcessorContext context; private final NodeData node; private final TypeSystemData typeSystem; - private final TypeData genericType; + private final TypeMirror genericType; private final DSLOptions options; private final boolean singleSpecializable; private final int varArgsThreshold; + private final Set expectedTypes = new HashSet<>(); + private boolean nextUsed; + private List usedTypes; + private List reachableSpecializations; public NodeGenFactory(ProcessorContext context, NodeData node) { this.context = context; this.node = node; this.typeSystem = node.getTypeSystem(); - this.genericType = typeSystem.getGenericTypeData(); + this.genericType = context.getType(Object.class); this.options = typeSystem.getOptions(); + this.varArgsThreshold = calculateVarArgsThreshold(); + this.reachableSpecializations = calculateReachableSpecializations(); this.singleSpecializable = isSingleSpecializableImpl(); - this.varArgsThreshold = calculateVarArgsThreshold(); + this.usedTypes = filterBaseExecutableTypes(node.getExecutableTypes(), reachableSpecializations); } private int calculateVarArgsThreshold() { @@ -139,8 +145,8 @@ return "exclude" + specialization.getId() + NAME_SUFFIX; } - private static String executeChildMethodName(NodeExecutionData execution, TypeData type) { - return "execute" + ElementUtils.firstLetterUpperCase(execution.getName()) + (type.isGeneric() ? "" : getTypeId(type.getBoxedType())) + NAME_SUFFIX; + private static String executeChildMethodName(NodeExecutionData execution, TypeMirror type) { + return "execute" + ElementUtils.firstLetterUpperCase(execution.getName()) + (ElementUtils.isObject(type) ? "" : getTypeId(type)) + NAME_SUFFIX; } private CodeTree accessParent(String name) { @@ -186,7 +192,9 @@ } for (NodeExecutionData execution : node.getChildExecutions()) { - clazz.add(createNodeField(PRIVATE, execution.getNodeType(), nodeFieldName(execution), Child.class)); + if (execution.getChild() != null) { + clazz.add(createNodeField(PRIVATE, execution.getNodeType(), nodeFieldName(execution), Child.class)); + } } for (NodeExecutionData execution : node.getChildExecutions()) { @@ -201,16 +209,13 @@ } } - Collection specializedTypes = node.findSpecializedReturnTypes(); - List implementedExecutables = new ArrayList<>(); - for (ExecutableTypeData execType : node.getExecutableTypes()) { - if (shouldImplementExecutableType(specializedTypes, execType)) { - implementedExecutables.add(execType); + for (ExecutableTypeData execType : usedTypes) { + if (execType.getMethod() == null) { + continue; } + clazz.add(createExecutableTypeOverride(usedTypes, execType)); } - for (ExecutableTypeData execType : implementedExecutables) { - clazz.add(createExecutableTypeOverride(implementedExecutables, execType)); - } + clazz.add(createGetCostMethod()); avoidFindbugsProblems(clazz); @@ -235,6 +240,12 @@ } } + for (TypeMirror type : ElementUtils.uniqueSortedTypes(expectedTypes)) { + if (!typeSystem.hasType(type)) { + clazz.addOptional(TypeSystemCodeGenerator.createExpectMethod(PRIVATE, typeSystem, context.getType(Object.class), type)); + } + } + return clazz; } @@ -295,7 +306,7 @@ CodeTree nameTree = CodeTreeBuilder.singleString(name); CodeTreeBuilder callBuilder = builder.create(); callBuilder.string(name).string(" != null ? "); - callBuilder.tree(callTemplateMethod(null, createCast, nameTree)); + callBuilder.tree(callMethod(null, createCast.getMethod(), nameTree)); callBuilder.string(" : null"); name += "_"; builder.declaration(child.getNodeType(), name, callBuilder.build()); @@ -305,6 +316,9 @@ } for (NodeExecutionData execution : node.getChildExecutions()) { + if (execution.getChild() == null) { + continue; + } CreateCastData createCast = node.findCast(execution.getChild().getName()); builder.startStatement(); @@ -315,18 +329,18 @@ accessorBuilder.string(name); if (execution.isIndexed()) { - accessorBuilder.string("[").string(String.valueOf(execution.getIndex())).string("]"); + accessorBuilder.string("[").string(String.valueOf(execution.getChildIndex())).string("]"); } CodeTree accessor = accessorBuilder.build(); if (createCast != null && execution.getChild().getCardinality().isOne()) { - accessor = callTemplateMethod(null, createCast, accessor); + accessor = callMethod(null, createCast.getMethod(), accessor); } if (execution.isIndexed()) { CodeTreeBuilder nullCheck = builder.create(); - nullCheck.string(name).string(" != null && ").string(String.valueOf(execution.getIndex())).string(" < ").string(name).string(".length").string(" ? "); + nullCheck.string(name).string(" != null && ").string(String.valueOf(execution.getChildIndex())).string(" < ").string(name).string(".length").string(" ? "); nullCheck.tree(accessor); nullCheck.string(" : null"); accessor = nullCheck.build(); @@ -345,8 +359,6 @@ } private SpecializationData createSpecializations(CodeTypeElement clazz) { - List reachableSpecializations = getReachableSpecializations(); - CodeTypeElement baseSpecialization = clazz.add(createBaseSpecialization()); TypeMirror baseSpecializationType = baseSpecialization.asType(); @@ -366,20 +378,20 @@ baseSpecialization.addOptional(createCreateNext(generated)); baseSpecialization.addOptional(createCreateFallback(generated)); baseSpecialization.addOptional(createCreatePolymorphic(generated)); + baseSpecialization.addOptional(createGetNext(baseSpecialization)); return node.getUninitializedSpecialization(); } private boolean needsPolymorphic() { - List reachableSpecializations = getReachableSpecializations(); if (reachableSpecializations.size() != 1) { return true; } SpecializationData specialization = reachableSpecializations.get(0); for (Parameter parameter : specialization.getSignatureParameters()) { - TypeData type = parameter.getTypeSystemType(); - if (type != null && type.hasImplicitSourceTypes()) { + TypeMirror type = parameter.getType(); + if (type != null && typeSystem.hasImplicitSourceTypes(type)) { return true; } } @@ -393,26 +405,23 @@ // create specialization private CodeTypeElement createBaseSpecialization() { - CodeTypeElement clazz = createClass(node, null, modifiers(PRIVATE, ABSTRACT, STATIC), specializationTypeName(null), TypeSystemNodeFactory.nodeType(typeSystem)); + CodeTypeElement clazz = createClass(node, null, modifiers(PRIVATE, ABSTRACT, STATIC), specializationTypeName(null), typeSystem.getContext().getType(SpecializationNode.class)); clazz.addOptional(createSpecializationConstructor(clazz, null, null)); clazz.add(new CodeVariableElement(modifiers(PROTECTED, FINAL), nodeType(node), "root")); clazz.addOptional(createUnsupported()); clazz.add(createGetSuppliedChildrenMethod()); - - int signatureSize = node.getSignatureSize(); - Set evaluatedCount = getEvaluatedCounts(); - for (int evaluated : evaluatedCount) { - if (signatureSize != evaluated || signatureSize == 0) { - clazz.add(createFastPathExecuteMethod(null, evaluated > 0 ? null : genericType, evaluated)); - } + clazz.add(createAcceptAndExecute()); + + for (ExecutableTypeData type : usedTypes) { + clazz.add(createFastPathExecuteMethod(null, type, usedTypes)); } for (NodeExecutionData execution : node.getChildExecutions()) { - Collection specializedTypes = node.findSpecializedTypes(execution); + Collection specializedTypes = node.findSpecializedTypes(execution); specializedTypes.add(genericType); - for (TypeData specializedType : specializedTypes) { + for (TypeMirror specializedType : specializedTypes) { if (isExecuteChildShared(execution, specializedType)) { clazz.add(createExecuteChildMethod(execution, specializedType)); } @@ -422,16 +431,162 @@ return clazz; } + private Element createAcceptAndExecute() { + + TypeMirror[] parameters = new TypeMirror[node.getSignatureSize()]; + Arrays.fill(parameters, genericType); + + ExecutableTypeData executableElement = new ExecutableTypeData(genericType, "acceptAndExecute", context.getType(Frame.class), Arrays.asList(parameters)); + + LocalContext currentLocals = LocalContext.load(this, node.getSignatureSize(), varArgsThreshold); + CodeExecutableElement executable = createExecuteMethod(null, executableElement, currentLocals, false); + + executable.getModifiers().add(FINAL); + CodeTreeBuilder builder = executable.createBuilder(); + + CodeTree receiver = CodeTreeBuilder.singleString("this"); + + builder.tree(createCallDelegateExecute(builder, receiver, currentLocals, executableElement, node.getGenericExecutableType(null))); + + return executable; + } + + private boolean shouldImplementExecutableType(SpecializationData specialization, ExecutableTypeData executableType) { + // always implement the root execute method. they are declared abstract in the base node. + if (executableType.getDelegatedTo() == null) { + return true; + } + + // specializations with more parameters are just ignored + if (executableType.getEvaluatedCount() > node.getSignatureSize()) { + return false; + } + + if (!isSubtypeBoxed(context, specialization.getReturnType().getType(), executableType.getReturnType())) { + return false; + } + + // the evaluated signature might be compatible to the specialization + boolean specializationCompatible = true; + for (int i = 0; i < executableType.getEvaluatedCount(); i++) { + TypeMirror evaluatedType = executableType.getEvaluatedParameters().get(i); + TypeMirror specializedType = specialization.findParameterOrDie(node.getChildExecutions().get(i)).getType(); + + if (!isSubtypeBoxed(context, evaluatedType, specializedType) && !isSubtypeBoxed(context, specializedType, evaluatedType)) { + specializationCompatible = false; + break; + } + } + if (!specializationCompatible) { + return false; + } + + // possibly trigger void optimization for a specialization if it is enabled + if (isVoid(executableType.getReturnType())) { + if (isTypeBoxingOptimized(options.voidBoxingOptimization(), specialization.getReturnType().getType())) { + return true; + } + } + + // trigger type boxing elimination for unevaluated arguments + for (int i = executableType.getEvaluatedCount(); i < node.getSignatureSize(); i++) { + NodeExecutionData execution = node.getChildExecutions().get(i); + TypeMirror specializedType = specialization.findParameterOrDie(execution).getType(); + if (isTypeBoxingOptimized(options.monomorphicTypeBoxingOptimization(), specializedType)) { + // it does not make sense to do type boxing elimination for children with + // no type specialized execute method + if (execution.getChild() != null) { + ExecutableTypeData executedType = execution.getChild().findExecutableType(specializedType); + if (executedType != null) { + return true; + } + } + } + } + + // trigger type boxing elimination for return types + if (typeEquals(executableType.getReturnType(), specialization.getReturnType().getType())) { + if (isTypeBoxingOptimized(options.monomorphicTypeBoxingOptimization(), executableType.getReturnType())) { + return true; + } + } + + // trigger generation for evaluated assignable type matches other than generic + for (int i = 0; i < executableType.getEvaluatedCount(); i++) { + TypeMirror evaluatedType = executableType.getEvaluatedParameters().get(i); + NodeExecutionData execution = node.getChildExecutions().get(i); + TypeMirror specializedType = specialization.findParameterOrDie(execution).getType(); + + if (isSubtypeBoxed(context, evaluatedType, specializedType) && !isObject(specializedType)) { + return true; + } + } + + return false; + } + + private List filterBaseExecutableTypes(List executableTypes, List specializations) { + Set returnTypes = new HashSet<>(); + for (SpecializationData specialization : node.getSpecializations()) { + returnTypes.add(specialization.getReturnType().getType()); + } + + List prefilteredTypes = new ArrayList<>(); + for (ExecutableTypeData type : executableTypes) { + if (type.getDelegatedTo() == null || shouldAlwaysImplementExecutableType(type)) { + prefilteredTypes.add(type); + } else { + boolean foundSubtype = false; + for (TypeMirror returnType : returnTypes) { + if (isSubtypeBoxed(context, returnType, type.getReturnType())) { + foundSubtype = true; + } + } + if (foundSubtype) { + prefilteredTypes.add(type); + } + } + } + + Set types = new HashSet<>(); + type: for (ExecutableTypeData type : prefilteredTypes) { + for (SpecializationData specialization : specializations) { + if (shouldImplementExecutableType(specialization, type) || shouldAlwaysImplementExecutableType(type)) { + types.add(type); + continue type; + } + } + } + Set delegatesToAdd = new HashSet<>(); + do { + delegatesToAdd.clear(); + for (ExecutableTypeData type : types) { + ExecutableTypeData delegate = type.getDelegatedTo(); + if (delegate != null && !types.contains(delegate)) { + delegatesToAdd.add(delegate); + } + } + types.addAll(delegatesToAdd); + } while (!delegatesToAdd.isEmpty()); + List newUsedTypes = new ArrayList<>(types); + Collections.sort(newUsedTypes); + return newUsedTypes; + } + + private boolean shouldAlwaysImplementExecutableType(ExecutableTypeData type) { + return type.isAbstract() || !(type.hasUnexpectedValue(context) && type.getMethod() != null); + } + private CodeTypeElement createSpecialization(SpecializationData specialization, TypeMirror baseType) { CodeTypeElement clazz = createClass(node, specialization, modifiers(PRIVATE, STATIC, FINAL), specializationTypeName(specialization), baseType); CodeExecutableElement constructor = clazz.addOptional(createSpecializationConstructor(clazz, specialization, null)); for (Parameter p : specialization.getSignatureParameters()) { - TypeData targetType = p.getTypeSystemType(); - if (targetType.hasImplicitSourceTypes()) { + TypeMirror targetType = p.getType(); + if (typeSystem.hasImplicitSourceTypes(targetType)) { NodeExecutionData execution = p.getSpecification().getExecution(); - CodeVariableElement implicitProfile = createImplicitProfileParameter(execution, p.getTypeSystemType()); + CodeVariableElement implicitProfile = createImplicitProfileParameter(execution, p.getType()); if (implicitProfile != null) { implicitProfile.getModifiers().add(PRIVATE); implicitProfile.getModifiers().add(FINAL); @@ -449,27 +604,35 @@ clazz.addOptional(createIsSameMethod(specialization)); clazz.addOptional(createIsIdenticalMethod(specialization)); - TypeData returnType = specialization.getReturnType().getTypeSystemType(); - int signatureSize = specialization.getSignatureSize(); - - clazz.add(createFastPathExecuteMethod(specialization, null, signatureSize)); - - if (isTypeBoxingEliminated(specialization)) { - clazz.add(createFastPathExecuteMethod(specialization, returnType, 0)); - - if (signatureSize > 0 && !returnType.isGeneric()) { - clazz.add(createFastPathWrapExecuteMethod(genericType, returnType)); + // get types that should get implemented + List types = new ArrayList<>(); + for (ExecutableTypeData type : node.getExecutableTypes()) { + if (shouldImplementExecutableType(specialization, type)) { + types.add(type); } - - ExecutableTypeData voidExecutableType = node.findExecutableType(typeSystem.getVoidType(), 0); - if (voidExecutableType != null && isTypeBoxingOptimized(options.voidBoxingOptimization(), returnType)) { - clazz.add(createFastPathWrapVoidMethod(returnType)); - } + } + for (ExecutableTypeData type : types) { + clazz.add(createFastPathExecuteMethod(specialization, type, types)); } return clazz; } + public static List getDynamicParameters(TemplateMethod method) { + List parameters = new ArrayList<>(); + for (Parameter param : method.getReturnTypeAndParameters()) { + if (param.getSpecification().isLocal()) { + // ignore parameters passed by locals + continue; + } else if (param.getVariableElement() != null && param.getVariableElement().getAnnotation(Cached.class) != null) { + // ignore cached parameters + continue; + } + parameters.add(param); + } + return parameters; + } + private Element createDeepCopyMethod() { if (singleSpecializable) { return null; @@ -492,6 +655,7 @@ builder.startReturn().startCall(specializationStartFieldName(), "getNodeCost").end().end(); } return executable; + } private Element createIsIdenticalMethod(SpecializationData specialization) { @@ -517,7 +681,7 @@ } }; - builder.tree(createGuardAndCast(group, typeSystem.getGenericTypeData(), currentLocals, executionFactory)); + builder.tree(createGuardAndCast(group, genericType, currentLocals, executionFactory)); builder.returnFalse(); return method; } @@ -533,7 +697,7 @@ if (execution == null) { continue; } - CodeVariableElement var = createImplicitProfileParameter(execution, parameter.getTypeSystemType()); + CodeVariableElement var = createImplicitProfileParameter(execution, parameter.getType()); if (var != null) { profiles.add(var); } @@ -605,42 +769,6 @@ return executable; } - private Element createFastPathWrapVoidMethod(TypeData wrap) { - CodeExecutableElement executable = new CodeExecutableElement(modifiers(PUBLIC), typeSystem.getVoidType().getPrimitiveType(), TypeSystemNodeFactory.executeName(typeSystem.getVoidType())); - executable.addParameter(new CodeVariableElement(getType(Frame.class), FRAME_VALUE)); - executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); - CodeTreeBuilder builder = executable.createBuilder(); - builder.startStatement(); - builder.startCall(TypeSystemNodeFactory.voidBoxingExecuteName(wrap)); - builder.string(FRAME_VALUE); - builder.end(); - builder.end(); - - return executable; - } - - private Element createFastPathWrapExecuteMethod(TypeData override, TypeData wrap) { - CodeExecutableElement executable = new CodeExecutableElement(modifiers(PUBLIC), override.getPrimitiveType(), TypeSystemNodeFactory.executeName(override)); - executable.addParameter(new CodeVariableElement(getType(Frame.class), FRAME_VALUE)); - executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); - CodeTreeBuilder builder = executable.createBuilder(); - if (wrap != null) { - builder.startTryBlock(); - } - builder.startReturn(); - builder.startCall(TypeSystemNodeFactory.executeName(wrap)); - builder.string(FRAME_VALUE); - builder.end(); - builder.end(); - if (wrap != null) { - builder.end().startCatchBlock(getType(UnexpectedResultException.class), "ex"); - builder.statement("return ex.getResult()"); - builder.end(); - } - - return executable; - } - private Element createCreateFallback(Map generatedSpecializationClasses) { SpecializationData fallback = node.getGenericSpecialization(); if (fallback == null) { @@ -752,35 +880,6 @@ return null; } - private boolean isTypeBoxingEliminated(SpecializationData specialization) { - if (specialization.getMethod() == null) { - return false; - } - - TypeBoxingOptimization optimization = options.monomorphicTypeBoxingOptimization(); - if (isTypeBoxingOptimized(optimization, specialization.getReturnType().getTypeSystemType())) { - return true; - } - for (Parameter p : specialization.getSignatureParameters()) { - if (isTypeBoxingOptimized(optimization, p.getTypeSystemType())) { - return true; - } - } - return false; - - } - - private Set getEvaluatedCounts() { - Set evaluatedCount = new TreeSet<>(); - Collection returnSpecializedTypes = node.findSpecializedReturnTypes(); - for (ExecutableTypeData execType : node.getExecutableTypes()) { - if (shouldImplementExecutableType(returnSpecializedTypes, execType)) { - evaluatedCount.add(execType.getEvaluatedCount()); - } - } - return evaluatedCount; - } - private Element createUnsupported() { SpecializationData fallback = node.getGenericSpecialization(); if (fallback == null || optimizeFallback(fallback) || fallback.getMethod() == null) { @@ -788,7 +887,7 @@ } LocalContext locals = LocalContext.load(this); - CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), genericType.getPrimitiveType(), "unsupported", FRAME_VALUE); + CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), genericType, "unsupported", FRAME_VALUE); method.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); CodeTreeBuilder builder = method.createBuilder(); @@ -800,7 +899,6 @@ } private boolean isSingleSpecializableImpl() { - List reachableSpecializations = getReachableSpecializations(); if (reachableSpecializations.size() != 1) { return false; } @@ -808,8 +906,8 @@ SpecializationData specialization = reachableSpecializations.get(0); for (Parameter parameter : specialization.getSignatureParameters()) { - TypeData type = parameter.getTypeSystemType(); - if (type != null && type.hasImplicitSourceTypes()) { + TypeMirror type = parameter.getType(); + if (type != null && typeSystem.hasImplicitSourceTypes(type)) { return false; } } @@ -826,7 +924,7 @@ return true; } - private List getReachableSpecializations() { + private List calculateReachableSpecializations() { List specializations = new ArrayList<>(); for (SpecializationData specialization : node.getSpecializations()) { if (specialization.isReachable() && // @@ -851,158 +949,23 @@ } } - private CodeExecutableElement createExecutableTypeOverride(List implementedExecutables, ExecutableTypeData execType) { - final String varArgsName = "args"; - final TypeData returnType = execType.getType(); - final TypeData executedType = execType.getEvaluatedCount() > 0 ? null : returnType; - - CodeExecutableElement method = cloneExecutableTypeOverride(execType, varArgsName); - LocalContext locals = LocalContext.load(this, execType.getSignatureSize(), Integer.MAX_VALUE); - - // rename varargs parameter - int signatureIndex = 0; - for (Parameter parameter : execType.getSignatureParameters()) { - LocalVariable var = locals.get(parameter, signatureIndex); - if (var != null) { - if (parameter.isTypeVarArgs()) { - var = var.accessWith(CodeTreeBuilder.singleString(varArgsName + "[" + parameter.getTypeVarArgsIndex() + "]")); - } - if (!parameter.getTypeSystemType().isGeneric()) { - var = var.newType(parameter.getTypeSystemType()); - } - locals.setValue(node.getChildExecutions().get(signatureIndex), var); - } - - signatureIndex++; - } - - Parameter frame = execType.getFrame(); + private CodeExecutableElement createExecutableTypeOverride(List usedExecutables, ExecutableTypeData execType) { + LocalContext locals = LocalContext.load(this, execType.getEvaluatedCount(), Integer.MAX_VALUE); + CodeExecutableElement method = createExecuteMethod(null, execType, locals, true); + CodeTreeBuilder builder = method.createBuilder(); if (singleSpecializable) { - LocalVariable frameVar = null; - if (frame != null) { - frameVar = locals.get(FRAME_VALUE).newType(frame.getType()); - } - method.getThrownTypes().clear(); - locals.set(FRAME_VALUE, frameVar); - - SpecializationData specialization = getReachableSpecializations().iterator().next(); - ExecutableTypeData wrappedExecutableType = findWrappedExecutable(specialization, implementedExecutables, execType); - if (wrappedExecutableType != null) { - builder.startReturn().tree(callTemplateMethod(null, wrappedExecutableType, locals)).end(); - } else { - builder.tree(createFastPath(builder, specialization, execType.getType(), locals)); - } + SpecializationData specialization = reachableSpecializations.iterator().next(); + builder.tree(createFastPath(builder, specialization, execType, usedExecutables, locals)); } else { // create acceptAndExecute - CodeTreeBuilder executeBuilder = builder.create(); - executeBuilder.startCall(specializationStartFieldName(), TypeSystemNodeFactory.executeName(executedType)); - if (frame == null) { - executeBuilder.nullLiteral(); - } else { - executeBuilder.string(frame.getLocalName()); - } - locals.addReferencesTo(executeBuilder); - executeBuilder.end(); - - boolean hasExecutedUnexpected = executedType != null && !executedType.isGeneric() && !executedType.isVoid(); - - CodeTreeBuilder contentBuilder = builder.create(); - contentBuilder.startReturn(); - if (!hasExecutedUnexpected && !execType.hasUnexpectedValue(context)) { - if (executedType == null || executedType.needsCastTo(returnType)) { - contentBuilder.cast(returnType.getPrimitiveType(), executeBuilder.build()); - } else { - contentBuilder.tree(executeBuilder.build()); - } - } else { - contentBuilder.tree(TypeSystemCodeGenerator.expect(executedType, returnType, executeBuilder.build())); - } - contentBuilder.end(); - // try catch assert if unexpected value is not expected - CodeTree content = contentBuilder.build(); - if (!execType.hasUnexpectedValue(context) && hasExecutedUnexpected) { - content = wrapTryCatchUnexpected(content); - } - builder.tree(content); + ExecutableTypeData delegate = execType; + CodeTree receiver = CodeTreeBuilder.singleString(specializationStartFieldName()); + builder.tree(createCallDelegateExecute(builder, receiver, locals, execType, delegate)); } return method; } - private CodeTree wrapTryCatchUnexpected(CodeTree content) { - CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); - builder.startTryBlock(); - builder.tree(content); - builder.end().startCatchBlock(getType(UnexpectedResultException.class), "ex"); - builder.startThrow().startNew(getType(AssertionError.class)).end().end(); - builder.end(); - return builder.build(); - } - - private static ExecutableTypeData findWrappedExecutable(SpecializationData specialization, List implementedExecutables, ExecutableTypeData executedType) { - if (specialization.getReturnType().getTypeSystemType() == executedType.getType()) { - return null; - } - for (ExecutableTypeData otherType : implementedExecutables) { - if (otherType != executedType && // - otherType.getType() == specialization.getReturnType().getTypeSystemType() && // - otherType.getEvaluatedCount() == executedType.getEvaluatedCount()) { - return otherType; - } - } - return null; - } - - private CodeExecutableElement cloneExecutableTypeOverride(ExecutableTypeData execType, final String varArgsName) throws AssertionError { - CodeExecutableElement method = CodeExecutableElement.clone(context.getEnvironment(), execType.getMethod()); - - method.getAnnotationMirrors().clear(); - method.getModifiers().remove(Modifier.ABSTRACT); - - if (!execType.getMethod().isVarArgs() && execType.getParameters().size() != method.getParameters().size()) { - throw new AssertionError("Should be verified in the parser"); - } - - // align argument names - int index = 0; - for (Parameter parameter : execType.getParameters()) { - CodeVariableElement var = (CodeVariableElement) method.getParameters().get(index); - if (parameter.isTypeVarArgs()) { - var.getAnnotationMirrors().clear(); - var.setName(varArgsName); - break; - } - var.setName(LocalVariable.fromParameter(parameter).createParameter().getName()); - var.getAnnotationMirrors().clear(); - index++; - } - return method; - } - - private boolean shouldImplementExecutableType(Collection specializedTypes, ExecutableTypeData execType) { - TypeData type = execType.getType(); - Set modifiers = execType.getMethod().getModifiers(); - if (modifiers.contains(FINAL) || modifiers.contains(STATIC) || modifiers.contains(PRIVATE)) { - return false; - } else if (execType.isAbstract()) { - return true; - } else if (type.isGeneric()) { - return true; - } else if (type.isVoid()) { - for (TypeData specializedType : specializedTypes) { - if (isTypeBoxingOptimized(options.voidBoxingOptimization(), specializedType)) { - return true; - } - } - return false; - } else if (!specializedTypes.contains(type)) { - return false; - } else if (!isTypeBoxingOptimized(options.monomorphicTypeBoxingOptimization(), type)) { - return false; - } - return true; - } - private Element createMethodGetSpecializationNode() { TypeMirror returntype = getType(SpecializationNode.class); CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), returntype, "getSpecializationNode"); @@ -1021,7 +984,7 @@ return childField; } - private static List resolveSpecializedExecutables(NodeExecutionData execution, Collection types, TypeBoxingOptimization optimization) { + private static List resolveSpecializedExecutables(NodeExecutionData execution, Collection types, TypeBoxingOptimization optimization) { if (optimization == TypeBoxingOptimization.NONE) { return Collections.emptyList(); } else if (types.isEmpty()) { @@ -1029,10 +992,13 @@ } List executables = new ArrayList<>(); - for (TypeData type : types) { + for (TypeMirror type : types) { if (!isTypeBoxingOptimized(optimization, type)) { continue; } + if (execution.getChild() == null) { + continue; + } ExecutableTypeData foundType = execution.getChild().getNodeData().findExecutableType(type, execution.getChild().getExecuteWith().size()); if (foundType != null) { executables.add(foundType); @@ -1041,15 +1007,15 @@ return executables; } - private static CodeTree callTemplateMethod(CodeTree receiver, TemplateMethod method, CodeTree... boundValues) { + private static CodeTree callMethod(CodeTree receiver, ExecutableElement method, CodeTree... boundValues) { CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); - if (method.getMethod().getModifiers().contains(STATIC)) { - builder.startStaticCall(method.getMethod().getEnclosingElement().asType(), method.getMethodName()); + if (method.getModifiers().contains(STATIC)) { + builder.startStaticCall(method.getEnclosingElement().asType(), method.getSimpleName().toString()); } else { - builder.startCall(receiver, method.getMethodName()); + builder.startCall(receiver, method.getSimpleName().toString()); } int index = -1; - for (Parameter parameter : method.getParameters()) { + for (VariableElement parameter : method.getParameters()) { index++; if (index < boundValues.length) { CodeTree tree = boundValues[index]; @@ -1059,13 +1025,44 @@ } } - builder.defaultValue(parameter.getType()); + builder.defaultValue(parameter.asType()); } builder.end(); return builder.build(); } - private static CodeTree callTemplateMethod(CodeTree receiver, TemplateMethod method, LocalContext currentValues) { + private CodeTree[] bindExecuteMethodParameters(NodeExecutionData execution, ExecutableTypeData method, LocalContext currentValues) { + List executeWith = execution != null ? execution.getChild().getExecuteWith() : null; + + List values = new ArrayList<>(); + if (method.getFrameParameter() != null) { + LocalVariable frameLocal = currentValues.get(FRAME_VALUE); + if (frameLocal == null) { + values.add(CodeTreeBuilder.singleString("null")); + } else { + values.add(createTypeSafeReference(frameLocal, method.getFrameParameter())); + } + } + for (int parameterIndex = 0; parameterIndex < method.getEvaluatedCount(); parameterIndex++) { + TypeMirror targetParameter = method.getEvaluatedParameters().get(parameterIndex); + LocalVariable variable; + if (executeWith != null && parameterIndex < executeWith.size()) { + variable = currentValues.getValue(executeWith.get(parameterIndex)); + } else { + variable = currentValues.getValue(parameterIndex); + } + values.add(createTypeSafeReference(variable, targetParameter)); + } + + return values.toArray(new CodeTree[values.size()]); + } + + private CodeTree callExecuteMethod(NodeExecutionData execution, ExecutableTypeData method, LocalContext currentValues) { + CodeTree receiver = execution != null ? accessParent(nodeFieldName(execution)) : null; + return callMethod(receiver, method.getMethod(), bindExecuteMethodParameters(execution, method, currentValues)); + } + + private CodeTree callTemplateMethod(CodeTree receiver, TemplateMethod method, LocalContext currentValues) { CodeTree[] bindings = new CodeTree[method.getParameters().size()]; int signatureIndex = 0; @@ -1078,24 +1075,30 @@ } if (var != null) { - CodeTree valueReference = var.createReference(); - if (parameter.getTypeSystemType() != null && var.getType() != null && var.getType().needsCastTo(parameter.getTypeSystemType())) { - valueReference = TypeSystemCodeGenerator.cast(parameter.getTypeSystemType(), valueReference); - } else if (ElementUtils.needsCastTo(var.getTypeMirror(), parameter.getType())) { - valueReference = CodeTreeBuilder.createBuilder().cast(parameter.getType(), valueReference).build(); - } - bindings[i] = valueReference; + bindings[i] = createTypeSafeReference(var, parameter.getType()); } if (parameter.getSpecification().isSignature()) { signatureIndex++; } } - return callTemplateMethod(receiver, method, bindings); + return callMethod(receiver, method.getMethod(), bindings); + } + + private CodeTree createTypeSafeReference(LocalVariable var, TypeMirror targetType) { + CodeTree valueReference = var.createReference(); + TypeMirror sourceType = var.getTypeMirror(); + if (targetType == null || sourceType == null) { + return valueReference; + } + if (needsCastTo(sourceType, targetType)) { + valueReference = TypeSystemCodeGenerator.cast(typeSystem, targetType, valueReference); + } + return valueReference; } private SpecializationGroup createSpecializationGroups() { - return SpecializationGroup.create(getReachableSpecializations()); + return SpecializationGroup.create(reachableSpecializations); } private CodeTree createSlowPathExecute(SpecializationData specialization, LocalContext currentValues) { @@ -1125,7 +1128,7 @@ String varName = name + specialization.getIndex(); TypeMirror type = assumption.getExpression().getResolvedType(); builder.declaration(type, varName, assumptions); - currentValues.set(name, new LocalVariable(null, type, varName, null, null)); + currentValues.set(name, new LocalVariable(type, varName, null, null)); } builder.startIf(); @@ -1189,14 +1192,14 @@ return builder.build(); } - private boolean hasFallthrough(SpecializationGroup group, TypeData forType, LocalContext currentValues, boolean fastPath, List ignoreGuards) { + private boolean hasFallthrough(SpecializationGroup group, TypeMirror forType, LocalContext currentValues, boolean fastPath, List ignoreGuards) { for (TypeGuard guard : group.getTypeGuards()) { if (currentValues.getValue(guard.getSignatureIndex()) == null) { // not evaluated return true; } LocalVariable value = currentValues.getValue(guard.getSignatureIndex()); - if (value.getType().needsCastTo(guard.getType())) { + if (needsCastTo(value.getTypeMirror(), guard.getType())) { return true; } } @@ -1244,6 +1247,16 @@ return false; } + private Element createGetNext(CodeTypeElement type) { + if (!nextUsed) { + return null; + } + CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, FINAL), type.asType(), "getNext"); + CodeTreeBuilder builder = method.createBuilder(); + builder.startReturn().cast(type.asType(), CodeTreeBuilder.singleString("this.next")).end(); + return method; + } + private Element createGetSuppliedChildrenMethod() { ArrayType nodeArray = context.getEnvironment().getTypeUtils().getArrayType(getType(Node.class)); @@ -1265,7 +1278,11 @@ if (execution.isShortCircuit()) { builder.nullLiteral(); } - builder.tree(accessParent(nodeFieldName(execution))); + if (execution.getChild() == null) { + builder.nullLiteral(); + } else { + builder.tree(accessParent(nodeFieldName(execution))); + } } builder.end(); return builder.build(); @@ -1289,7 +1306,7 @@ } if (currentValues != null) { for (Parameter p : specialization.getSignatureParameters()) { - CodeVariableElement var = createImplicitProfileParameter(p.getSpecification().getExecution(), p.getTypeSystemType()); + CodeVariableElement var = createImplicitProfileParameter(p.getSpecification().getExecution(), p.getType()); if (var != null) { LocalVariable variable = currentValues.get(p.getLocalName()); if (variable == null) { @@ -1370,19 +1387,19 @@ for (Parameter p : specialization.getSignatureParameters()) { NodeExecutionData execution = p.getSpecification().getExecution(); - CodeVariableElement implicitProfile = createImplicitProfileParameter(execution, p.getTypeSystemType()); + CodeVariableElement implicitProfile = createImplicitProfileParameter(execution, p.getType()); if (implicitProfile != null) { - LocalVariable var = LocalVariable.fromParameter(p).makeGeneric(); + LocalVariable var = LocalVariable.fromParameter(p).makeGeneric(context); String implicitFieldName = implicitProfile.getName(); if (options.implicitCastOptimization().isDuplicateTail()) { constructor.addParameter(var.createParameter()); - CodeTree implicitType = TypeSystemCodeGenerator.implicitType(p.getTypeSystemType(), var.createReference()); + CodeTree implicitType = TypeSystemCodeGenerator.implicitType(typeSystem, p.getType(), var.createReference()); builder.startStatement().string("this.").string(implicitFieldName).string(" = ").tree(implicitType).end(); } else if (options.implicitCastOptimization().isMergeCasts()) { // use node that supports polymorphism constructor.addParameter(var.createParameter()); - builder.startStatement().string("this.").string(implicitFieldName).string(" = ").tree(ImplicitCastNodeFactory.create(p.getTypeSystemType(), var.createReference())).end(); + builder.startStatement().string("this.").string(implicitFieldName).string(" = ").tree(ImplicitCastNodeFactory.create(typeSystem, p.getType(), var.createReference())).end(); } else { throw new AssertionError(); } @@ -1443,18 +1460,17 @@ return builder.build(); } - private CodeTree createCallNext(TypeData forType, LocalContext currentValues) { + private CodeTree createCallNext(CodeTreeBuilder parent, ExecutableTypeData currentType, ExecutableTypeData callType, LocalContext currentValues) { if (singleSpecializable) { return createThrowUnsupported(currentValues); } - CodeTreeBuilder callBuilder = CodeTreeBuilder.createBuilder(); - callBuilder.startCall("next", TypeSystemNodeFactory.executeName(null)); - currentValues.addReferencesTo(callBuilder, FRAME_VALUE); - callBuilder.end(); - return CodeTreeBuilder.createBuilder().startReturn().tree(TypeSystemCodeGenerator.expect(genericType, forType, callBuilder.build())).end().build(); + CodeTreeBuilder callBuilder = parent.create(); + callBuilder.tree(createCallDelegateExecute(callBuilder, CodeTreeBuilder.singleString("getNext()"), currentValues, currentType, callType)); + nextUsed = true; + return callBuilder.build(); } - private CodeTree createCallRemove(String reason, TypeData forType, LocalContext currentValues) { + private CodeTree createCallRemove(String reason, ExecutableTypeData forType, LocalContext currentValues) { if (singleSpecializable) { return createThrowUnsupported(currentValues); } @@ -1467,12 +1483,12 @@ builder = builder.create(); builder.startReturn(); - builder.tree(TypeSystemCodeGenerator.expect(genericType, forType, call)); + builder.tree(expectOrCast(genericType, forType, call)); builder.end(); return builder.build(); } - private static CodeTree createCallDelegate(String methodName, String reason, TypeData forType, LocalContext currentValues) { + private CodeTree createCallDelegate(String methodName, String reason, ExecutableTypeData forType, LocalContext currentValues) { CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); builder.startCall(methodName); if (reason != null) { @@ -1481,21 +1497,45 @@ currentValues.addReferencesTo(builder, FRAME_VALUE); builder.end(); - TypeData executedType = forType.getTypeSystem().getGenericTypeData(); - return TypeSystemCodeGenerator.expect(executedType, forType, builder.build()); + CodeTree expectOrCast = expectOrCast(genericType, forType, builder.build()); + return expectOrCast; + } + + private CodeTree expectOrCast(TypeMirror sourceType, ExecutableTypeData targetType, CodeTree content) { + if (needsUnexpectedResultException(targetType)) { + return expect(sourceType, targetType.getReturnType(), content); + } else { + return cast(sourceType, targetType.getReturnType(), content); + } } - private Set findSpecializedExecutableTypes(NodeExecutionData execution, TypeData type) { + private CodeTree cast(TypeMirror sourceType, TypeMirror targetType, CodeTree content) { + if (ElementUtils.needsCastTo(sourceType, targetType) && !isVoid(sourceType)) { + return TypeSystemCodeGenerator.cast(typeSystem, targetType, content); + } else { + return content; + } + } + + private CodeTree expect(TypeMirror sourceType, TypeMirror forType, CodeTree tree) { + expectedTypes.add(forType); + return TypeSystemCodeGenerator.expect(typeSystem, sourceType, forType, tree); + } + + private Set findSpecializedExecutableTypes(NodeExecutionData execution, TypeMirror type) { + if (execution.getChild() == null) { + return Collections.emptySet(); + } ExecutableTypeData executableType = resolveExecutableType(execution.getChild(), type); Set executedTypes = new HashSet<>(); executedTypes.add(executableType); - if (type.hasImplicitSourceTypes()) { - executedTypes.addAll(resolveSpecializedExecutables(execution, type.getImplicitSourceTypes(), options.implicitTypeBoxingOptimization())); + if (typeSystem.hasImplicitSourceTypes(type)) { + executedTypes.addAll(resolveSpecializedExecutables(execution, typeSystem.lookupSourceTypes(type), options.implicitTypeBoxingOptimization())); } return executedTypes; } - private ExecutableTypeData resolveExecutableType(NodeChildData child, TypeData type) { + private ExecutableTypeData resolveExecutableType(NodeChildData child, TypeMirror type) { int executeWithCount = child.getExecuteWith().size(); ExecutableTypeData executableType = child.getNodeData().findExecutableType(type, executeWithCount); if (executableType == null) { @@ -1504,79 +1544,254 @@ return executableType; } - private boolean hasUnexpectedResult(NodeExecutionData execution, TypeData type) { + private boolean hasChildUnexpectedResult(NodeExecutionData execution, TypeMirror type) { for (ExecutableTypeData executableType : findSpecializedExecutableTypes(execution, type)) { - if (executableType != null && (executableType.hasUnexpectedValue(context) || executableType.getType().needsCastTo(type))) { + if (executableType != null && (executableType.hasUnexpectedValue(context) || needsCastTo(executableType.getReturnType(), type))) { return true; } } return false; } - private Element createFastPathExecuteMethod(SpecializationData specialization, final TypeData forType, int evaluatedArguments) { - TypeData type = forType == null ? genericType : forType; - LocalContext currentLocals = LocalContext.load(this, evaluatedArguments, varArgsThreshold); + private Element createFastPathExecuteMethod(SpecializationData specialization, ExecutableTypeData executedType, List allTypes) { + LocalContext currentLocals = LocalContext.load(this, executedType.getEvaluatedCount(), varArgsThreshold); + CodeExecutableElement executable = createExecuteMethod(specialization, executedType, currentLocals, false); + CodeTreeBuilder builder = executable.createBuilder(); + if (specialization == null) { + if (executedType.getDelegatedTo() == null) { + executable.getModifiers().add(ABSTRACT); + } + } else { + executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); + } + builder.tree(createFastPath(builder, specialization, executedType, allTypes, currentLocals)); + + return executable; + } + + private CodeExecutableElement createExecuteMethod(SpecializationData specialization, ExecutableTypeData executedType, LocalContext currentLocals, boolean originalOverride) { + TypeMirror returnType = executedType.getReturnType(); + TypeMirror frame = executedType.getFrameParameter(); + List evaluatedParameters = executedType.getEvaluatedParameters(); if (specialization != null) { currentLocals.loadFastPathState(specialization); } - CodeExecutableElement executable = currentLocals.createMethod(modifiers(PUBLIC), type.getPrimitiveType(), TypeSystemNodeFactory.executeName(forType), FRAME_VALUE); - executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); - - if (!type.isGeneric()) { - executable.getThrownTypes().add(getType(UnexpectedResultException.class)); + if (frame == null) { + currentLocals.removeValue(FRAME_VALUE); + } else { + currentLocals.set(FRAME_VALUE, currentLocals.get(FRAME_VALUE).newType(frame)); + } + + for (int i = 0; i < Math.min(node.getChildExecutions().size(), evaluatedParameters.size()); i++) { + NodeExecutionData execution = node.getChildExecutions().get(i); + currentLocals.setValue(execution, currentLocals.getValue(execution).newType(evaluatedParameters.get(i))); + } + + String methodName; + if (originalOverride) { + methodName = executedType.getMethod().getSimpleName().toString(); + } else { + methodName = executedType.getUniqueName(); } - CodeTreeBuilder builder = executable.createBuilder(); - builder.tree(createFastPath(builder, specialization, type, currentLocals)); + CodeExecutableElement executable; + if (originalOverride && executedType.getMethod() != null) { + executable = CodeExecutableElement.clone(context.getEnvironment(), executedType.getMethod()); + executable.getAnnotationMirrors().clear(); + executable.getModifiers().remove(ABSTRACT); + for (VariableElement var : executable.getParameters()) { + ((CodeVariableElement) var).getAnnotationMirrors().clear(); + } + if (executedType.getFrameParameter() != null) { + ((CodeVariableElement) executable.getParameters().get(0)).setName(FRAME_VALUE); + } + + final String varArgsName = "args"; + if (executable.isVarArgs()) { + ((CodeVariableElement) executable.getParameters().get(executable.getParameters().size() - 1)).setName(varArgsName); + } + + // rename varargs parameter + int signatureIndex = 0; + for (TypeMirror parameter : executedType.getEvaluatedParameters()) { + LocalVariable var = currentLocals.getValue(signatureIndex); + if (var != null) { + int varArgsIndex = executedType.getVarArgsIndex(executedType.getParameterIndex(signatureIndex)); + if (varArgsIndex >= 0) { + var = var.accessWith(CodeTreeBuilder.singleString(varArgsName + "[" + varArgsIndex + "]")); + } else { + ((CodeVariableElement) executable.getParameters().get(executedType.getParameterIndex(signatureIndex))).setName(var.getName()); + } + if (!isObject(parameter)) { + var = var.newType(parameter); + } + currentLocals.setValue(node.getChildExecutions().get(signatureIndex), var); + } + + signatureIndex++; + } + } else { + executable = currentLocals.createMethod(modifiers(PUBLIC), returnType, methodName, FRAME_VALUE); + } + executable.getThrownTypes().clear(); + + if (needsUnexpectedResultException(executedType)) { + executable.getThrownTypes().add(context.getDeclaredType(UnexpectedResultException.class)); + } return executable; } - private CodeTree createFastPath(CodeTreeBuilder parent, SpecializationData specialization, TypeData type, LocalContext currentLocals) { + private boolean needsUnexpectedResultException(ExecutableTypeData executedType) { + if (!executedType.hasUnexpectedValue(context)) { + return false; + } + + SpecializationData polymorphicSpecialization = node.getPolymorphicSpecialization(); + if (polymorphicSpecialization != null && isSubtypeBoxed(context, polymorphicSpecialization.getReturnType().getType(), executedType.getReturnType())) { + return false; + } else { + return true; + } + } + + private CodeTree createFastPath(CodeTreeBuilder parent, SpecializationData specialization, final ExecutableTypeData executableType, List allTypes, LocalContext currentLocals) { final CodeTreeBuilder builder = parent.create(); + TypeMirror returnType = executableType.getReturnType(); + + ExecutableTypeData delegate = null; + if (specialization == null) { + delegate = executableType.getDelegatedTo(); + } + + if (delegate == null) { + delegate = findFastPathDelegate((specialization != null ? specialization.getReturnType().getType() : genericType), executableType, allTypes); + } for (NodeExecutionData execution : node.getChildExecutions()) { + if (specialization == null && delegate != null && execution.getIndex() >= delegate.getEvaluatedCount()) { + // we just evaluate children for the next delegate + continue; + } else if (specialization != null && delegate != null) { + // skip if already delegated + break; + } + LocalVariable var = currentLocals.getValue(execution); if (var == null) { - TypeData targetType; + TypeMirror targetType; if (specialization == null) { - targetType = genericType; + targetType = node.getGenericType(execution); } else { - targetType = specialization.findParameterOrDie(execution).getTypeSystemType(); + targetType = specialization.findParameterOrDie(execution).getType(); } LocalVariable shortCircuit = resolveShortCircuit(specialization, execution, currentLocals); - LocalVariable value = currentLocals.createValue(execution, targetType).nextName(); - builder.tree(createAssignExecuteChild(execution, type, value, shortCircuit, currentLocals)); - currentLocals.setValue(execution, value); + var = currentLocals.createValue(execution, targetType).nextName(); + builder.tree(createAssignExecuteChild(builder, execution, executableType, var, shortCircuit, currentLocals)); + currentLocals.setValue(execution, var); } } LocalContext originalValues = currentLocals.copy(); - if (specialization == null) { - builder.startReturn().tree(createCallDelegate("acceptAndExecute", null, type, currentLocals)).end(); + if (delegate != null) { + builder.tree(createCallDelegateExecute(builder, null, currentLocals, executableType, delegate)); + } else if (specialization == null) { + // nothing to do. abstract anyway } else if (specialization.isPolymorphic()) { - builder.tree(createCallNext(type, currentLocals)); + builder.tree(createCallNext(builder, executableType, node.getGenericExecutableType(executableType), currentLocals)); } else if (specialization.isUninitialized()) { - builder.startReturn().tree(createCallDelegate("uninitialized", null, type, currentLocals)).end(); + builder.startReturn().tree(createCallDelegate("uninitialized", null, executableType, currentLocals)).end(); } else { - final TypeData finalType = type; SpecializationGroup group = SpecializationGroup.create(specialization); SpecializationBody executionFactory = new SpecializationBody(true, true) { @Override public CodeTree createBody(SpecializationData s, LocalContext values) { - return createFastPathExecute(builder, finalType, s, values); + return createFastPathExecute(builder, executableType, s, values); } }; - builder.tree(createGuardAndCast(group, type, currentLocals, executionFactory)); - if (hasFallthrough(group, type, originalValues, true, null) || group.getSpecialization().isFallback()) { - builder.tree(createCallNext(type, originalValues)); + builder.tree(createGuardAndCast(group, returnType, currentLocals, executionFactory)); + if (hasFallthrough(group, returnType, originalValues, true, null) || group.getSpecialization().isFallback()) { + builder.tree(createCallNext(builder, executableType, node.getGenericExecutableType(executableType), originalValues)); } } return builder.build(); } + private CodeTree createCallDelegateExecute(final CodeTreeBuilder parent, CodeTree receiver, LocalContext currentLocals, ExecutableTypeData source, ExecutableTypeData delegate) { + CodeTreeBuilder callBuilder = parent.create(); + + if (singleSpecializable && delegate.getMethod() != null) { + callBuilder.startCall(receiver, delegate.getMethod().getSimpleName().toString()); + } else { + callBuilder.startCall(receiver, delegate.getUniqueName()); + } + callBuilder.trees(bindExecuteMethodParameters(null, delegate, currentLocals)); + callBuilder.end(); + CodeTree call = expectOrCast(delegate.getReturnType(), source, callBuilder.build()); + + CodeTreeBuilder returnBuilder = parent.create(); + if (isVoid(source.getReturnType())) { + returnBuilder.statement(call); + returnBuilder.returnStatement(); + } else if (isVoid(delegate.getReturnType())) { + returnBuilder.statement(call); + returnBuilder.returnDefault(); + } else { + returnBuilder.startReturn().tree(call).end(); + } + + CodeTreeBuilder builder = parent.create(); + + if (!needsUnexpectedResultException(source) && needsUnexpectedResultException(delegate)) { + builder.startTryBlock(); + builder.tree(returnBuilder.build()); + builder.end().startCatchBlock(context.getType(UnexpectedResultException.class), "ex"); + if (!isVoid(source.getReturnType())) { + builder.startReturn().tree(cast(context.getType(Object.class), source.getReturnType(), CodeTreeBuilder.singleString("ex.getResult()"))).end(); + } + builder.end(); + } else { + builder.tree(returnBuilder.build()); + } + return builder.build(); + } + + private ExecutableTypeData findFastPathDelegate(TypeMirror targetType, ExecutableTypeData executableType, List allTypes) { + if (typeEquals(executableType.getReturnType(), targetType)) { + // type matches look for even better delegates + for (ExecutableTypeData type : allTypes) { + if (typeEquals(type.getReturnType(), targetType) && executableType.sameParameters(type)) { + if (type != executableType) { + return type; + } + } + } + return null; + } else { + for (ExecutableTypeData type : allTypes) { + if (typeEquals(type.getReturnType(), targetType) && executableType.sameParameters(type)) { + return type; + } + } + int executableIndex = allTypes.indexOf(executableType); + int compareIndex = 0; + for (ExecutableTypeData type : allTypes) { + if (executableIndex != compareIndex && executableType.sameParameters(type)) { + int result = ExecutableTypeData.compareType(context, type.getReturnType(), executableType.getReturnType()); + if (result < 0) { + return type; + } else if (result == 0 && executableIndex < compareIndex) { + return type; + } + } + compareIndex++; + } + return null; + } + } + private LocalVariable resolveShortCircuit(SpecializationData specialization, NodeExecutionData execution, LocalContext currentLocals) { LocalVariable shortCircuit = null; SpecializationData resolvedSpecialization = specialization; @@ -1605,13 +1820,17 @@ return shortCircuitIndex; } - private CodeTree createFastPathExecute(CodeTreeBuilder parent, final TypeData forType, SpecializationData specialization, LocalContext currentValues) { + private CodeTree createFastPathExecute(CodeTreeBuilder parent, final ExecutableTypeData forType, SpecializationData specialization, LocalContext currentValues) { CodeTreeBuilder builder = parent.create(); int ifCount = 0; if (specialization.isFallback()) { builder.startIf().startCall("guardFallback"); if (node.isFrameUsedByAnyGuard()) { - builder.string(FRAME_VALUE); + if (currentValues.get(FRAME_VALUE) != null) { + builder.string(FRAME_VALUE); + } else { + builder.nullLiteral(); + } } currentValues.addReferencesTo(builder); @@ -1642,21 +1861,37 @@ builder.end(); } - execute.startReturn(); if (specialization.getMethod() == null) { + execute.startReturn(); execute.startCall("unsupported"); currentValues.addReferencesTo(execute, FRAME_VALUE); execute.end(); + execute.end(); } else { + boolean doReturn = !isVoid(specialization.getMethod().getReturnType()); + if (doReturn) { + execute.startReturn(); + } else { + execute.startStatement(); + } execute.tree(callTemplateMethod(accessParent(null), specialization, currentValues)); + execute.end(); + if (!doReturn) { + if (isVoid(forType.getReturnType())) { + execute.returnStatement(); + } else { + execute.startReturn(); + execute.defaultValue(forType.getReturnType()); + execute.end(); + } + } } - execute.end(); builder.tree(createFastPathTryCatchRewriteException(specialization, forType, currentValues, execute.build())); builder.end(ifCount); return builder.build(); } - private CodeTree createGuardAndCast(SpecializationGroup group, TypeData forType, LocalContext currentValues, SpecializationBody execution) { + private CodeTree createGuardAndCast(SpecializationGroup group, TypeMirror forType, LocalContext currentValues, SpecializationBody execution) { CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); Set castGuards; @@ -1780,11 +2015,11 @@ return false; } - private CodeExecutableElement createExecuteChildMethod(NodeExecutionData execution, TypeData targetType) { + private CodeExecutableElement createExecuteChildMethod(NodeExecutionData execution, TypeMirror targetType) { LocalContext locals = LocalContext.load(this, 0, varArgsThreshold); - CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), targetType.getPrimitiveType(), executeChildMethodName(execution, targetType), FRAME_VALUE); - if (hasUnexpectedResult(execution, targetType)) { + CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), targetType, executeChildMethodName(execution, targetType), FRAME_VALUE); + if (hasChildUnexpectedResult(execution, targetType)) { method.getThrownTypes().add(getType(UnexpectedResultException.class)); } @@ -1810,30 +2045,30 @@ return method; } - private CodeVariableElement createImplicitProfileParameter(NodeExecutionData execution, TypeData targetType) { - if (targetType.hasImplicitSourceTypes()) { + private CodeVariableElement createImplicitProfileParameter(NodeExecutionData execution, TypeMirror targetType) { + if (typeSystem.hasImplicitSourceTypes(targetType)) { switch (options.implicitCastOptimization()) { case NONE: return null; case DUPLICATE_TAIL: return new CodeVariableElement(getType(Class.class), implicitClassFieldName(execution)); case MERGE_CASTS: - return new CodeVariableElement(ImplicitCastNodeFactory.type(targetType), implicitNodeFieldName(execution)); + return new CodeVariableElement(ImplicitCastNodeFactory.type(typeSystem, targetType), implicitNodeFieldName(execution)); } } return null; } - private boolean isExecuteChildShared(NodeExecutionData execution, TypeData targetType) { - if (targetType.isVoid()) { + private boolean isExecuteChildShared(NodeExecutionData execution, TypeMirror targetType) { + if (isVoid(targetType)) { return false; - } else if (targetType.isGeneric()) { + } else if (isObject(targetType)) { return resolvePolymorphicExecutables(execution).size() >= 1; } else { if (!isTypeBoxingOptimized(options.monomorphicTypeBoxingOptimization(), targetType)) { return false; } - if (!targetType.hasImplicitSourceTypes()) { + if (!typeSystem.hasImplicitSourceTypes(targetType)) { return false; } @@ -1841,25 +2076,26 @@ for (SpecializationData specialization : node.getSpecializations()) { List parameters = specialization.findByExecutionData(execution); for (Parameter parameter : parameters) { - if (targetType.equals(parameter.getTypeSystemType())) { + if (targetType.equals(parameter.getType())) { uses++; } } } if (uses > 1) { - return resolveSpecializedExecutables(execution, targetType.getImplicitSourceTypes(), options.implicitTypeBoxingOptimization()).size() > 1; + return resolveSpecializedExecutables(execution, typeSystem.lookupSourceTypes(targetType), options.implicitTypeBoxingOptimization()).size() > 1; } else { return false; } } } - private CodeTree createAssignExecuteChild(NodeExecutionData execution, TypeData returnType, LocalVariable targetValue, LocalVariable shortCircuit, LocalContext currentValues) { - CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); - boolean hasUnexpected = hasUnexpectedResult(execution, targetValue.getType()); + private CodeTree createAssignExecuteChild(CodeTreeBuilder parent, NodeExecutionData execution, ExecutableTypeData type, LocalVariable targetValue, LocalVariable shortCircuit, + LocalContext currentValues) { + CodeTreeBuilder builder = parent.create(); + boolean hasUnexpected = hasChildUnexpectedResult(execution, targetValue.getTypeMirror()); CodeTree executeChild; - if (isExecuteChildShared(execution, targetValue.getType())) { + if (isExecuteChildShared(execution, targetValue.getTypeMirror())) { executeChild = createCallSharedExecuteChild(execution, targetValue, currentValues); } else { executeChild = createExecuteChild(execution, targetValue, currentValues, false); @@ -1875,21 +2111,22 @@ if (hasUnexpected) { builder.startCatchBlock(getType(UnexpectedResultException.class), "ex"); LocalContext slowPathValues = currentValues.copy(); - - slowPathValues.setValue(execution, targetValue.makeGeneric().accessWith(CodeTreeBuilder.singleString("ex.getResult()"))); + slowPathValues.setValue(execution, targetValue.makeGeneric(context).accessWith(CodeTreeBuilder.singleString("ex.getResult()"))); + + ExecutableTypeData delegateType = node.getGenericExecutableType(type); boolean found = false; for (NodeExecutionData otherExecution : node.getChildExecutions()) { if (found) { LocalVariable childEvaluatedValue = slowPathValues.createValue(otherExecution, genericType); LocalVariable genericShortCircuit = resolveShortCircuit(null, otherExecution, slowPathValues); - builder.tree(createAssignExecuteChild(otherExecution, genericType, childEvaluatedValue, genericShortCircuit, slowPathValues)); + builder.tree(createAssignExecuteChild(builder, otherExecution, delegateType, childEvaluatedValue, genericShortCircuit, slowPathValues)); slowPathValues.setValue(otherExecution, childEvaluatedValue); } else { // skip forward already evaluated found = execution == otherExecution; } } - builder.tree(createCallNext(returnType, slowPathValues)); + builder.tree(createCallNext(builder, type, delegateType, slowPathValues)); builder.end(); } @@ -1945,16 +2182,20 @@ } private CodeTree createCallSharedExecuteChild(NodeExecutionData execution, LocalVariable targetValue, LocalContext currentValues) { - if (!isExecuteChildShared(execution, targetValue.getType())) { + if (!isExecuteChildShared(execution, targetValue.getTypeMirror())) { throw new AssertionError("Execute child not shared with method but called."); } CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); builder.tree(targetValue.createReference()).string(" = "); - builder.startCall(executeChildMethodName(execution, targetValue.getType())); - builder.string(FRAME_VALUE); - - CodeVariableElement implicitProfile = createImplicitProfileParameter(execution, targetValue.getType()); + builder.startCall(executeChildMethodName(execution, targetValue.getTypeMirror())); + if (currentValues.get(FRAME_VALUE) == null) { + builder.nullLiteral(); + } else { + builder.string(FRAME_VALUE); + } + + CodeVariableElement implicitProfile = createImplicitProfileParameter(execution, targetValue.getTypeMirror()); if (implicitProfile != null) { builder.string(implicitProfile.getName()); } @@ -1970,12 +2211,12 @@ CodeTree assignment = createAssignmentStart(target, shared); - final Set executableTypes = findSpecializedExecutableTypes(execution, target.getType()); + final Set executableTypes = findSpecializedExecutableTypes(execution, target.getTypeMirror()); if (executableTypes.isEmpty()) { throw new AssertionError(); // cannot execute child - } else if (executableTypes.size() == 1 && !target.getType().hasImplicitSourceTypes()) { + } else if (executableTypes.size() == 1 && !typeSystem.hasImplicitSourceTypes(target.getTypeMirror())) { ExecutableTypeData executableType = executableTypes.iterator().next(); - if (target.getType().isGeneric() && executableType.getEvaluatedCount() == 0) { + if (isObject(target.getTypeMirror()) && executableType.getEvaluatedCount() == 0) { return createPolymorphicExecuteChild(execution, target, currentValues, shared); } else { builder.tree(assignment); @@ -1997,9 +2238,8 @@ } private CodeTree createSingleExecute(NodeExecutionData execution, LocalVariable target, LocalContext currentValues, ExecutableTypeData executableType) { - CodeTree accessChild = accessParent(nodeFieldName(execution)); - CodeTree execute = callTemplateMethod(accessChild, executableType, currentValues); - return TypeSystemCodeGenerator.expect(executableType.getType(), target.getType(), execute); + CodeTree execute = callExecuteMethod(execution, executableType, currentValues); + return expect(executableType.getReturnType(), target.getTypeMirror(), execute); } private CodeTree createPolymorphicExecuteChild(NodeExecutionData execution, LocalVariable target, LocalContext currentValues, boolean shared) throws AssertionError { @@ -2011,7 +2251,7 @@ List specializedExecutables = resolvePolymorphicExecutables(execution); Collections.sort(specializedExecutables, new Comparator() { public int compare(ExecutableTypeData o1, ExecutableTypeData o2) { - return o1.getType().compareTo(o2.getType()); + return compareType(o1.getReturnType(), o2.getReturnType()); } }); @@ -2034,7 +2274,7 @@ for (ExecutableTypeData executableType : specializedExecutables) { hasSpecializedTypes = polyChainBuilder.startIf(hasSpecializedTypes); polyChainBuilder.string(profileField); - polyChainBuilder.string(" == ").typeLiteral(executableType.getType().getPrimitiveType()); + polyChainBuilder.string(" == ").typeLiteral(executableType.getReturnType()); polyChainBuilder.end(); polyChainBuilder.startBlock(); polyChainBuilder.startStatement(); @@ -2048,20 +2288,20 @@ polyChainBuilder.startElseIf().string(profileField).string(" == null").end(); polyChainBuilder.startBlock(); polyChainBuilder.tree(createTransferToInterpreterAndInvalidate()); - polyChainBuilder.declaration(genericExecutableType.getType().getPrimitiveType(), valueFieldName, executeGeneric); + polyChainBuilder.declaration(genericExecutableType.getReturnType(), valueFieldName, executeGeneric); hasSpecializedTypes = false; for (ExecutableTypeData executableType : specializedExecutables) { hasSpecializedTypes = polyChainBuilder.startIf(hasSpecializedTypes); - polyChainBuilder.tree(TypeSystemCodeGenerator.check(executableType.getType(), CodeTreeBuilder.singleString(valueFieldName))); + polyChainBuilder.tree(TypeSystemCodeGenerator.check(typeSystem, executableType.getReturnType(), CodeTreeBuilder.singleString(valueFieldName))); polyChainBuilder.end(); polyChainBuilder.startBlock(); - polyChainBuilder.startStatement().tree(accessParent(profileField)).string(" = ").typeLiteral(executableType.getType().getPrimitiveType()).end(); + polyChainBuilder.startStatement().tree(accessParent(profileField)).string(" = ").typeLiteral(executableType.getReturnType()).end(); polyChainBuilder.end(); } polyChainBuilder.startElseBlock(); - polyChainBuilder.startStatement().tree(accessParent(profileField)).string(" = ").typeLiteral(genericType.getPrimitiveType()).end(); + polyChainBuilder.startStatement().tree(accessParent(profileField)).string(" = ").typeLiteral(genericType).end(); polyChainBuilder.end(); polyChainBuilder.startReturn().string(valueFieldName).end(); polyChainBuilder.end(); @@ -2077,7 +2317,7 @@ builder.tree(executePolymorphic); builder.end(); builder.startCatchBlock(getType(UnexpectedResultException.class), "ex"); - builder.startStatement().tree(accessParent(profileField)).string(" = ").typeLiteral(genericType.getPrimitiveType()).end(); + builder.startStatement().tree(accessParent(profileField)).string(" = ").typeLiteral(genericType).end(); builder.startReturn().string("ex.getResult()").end(); builder.end(); } else { @@ -2091,9 +2331,9 @@ if (singleSpecializable) { return Collections.emptyList(); } - Set specializedTypes = new HashSet<>(); - for (TypeData type : node.findSpecializedTypes(execution)) { - specializedTypes.addAll(type.getImplicitSourceTypes()); + Set specializedTypes = new HashSet<>(); + for (TypeMirror type : node.findSpecializedTypes(execution)) { + specializedTypes.addAll(typeSystem.lookupSourceTypes(type)); } return resolveSpecializedExecutables(execution, specializedTypes, options.polymorphicTypeBoxingElimination()); } @@ -2110,23 +2350,22 @@ private CodeTree createExecuteChildDuplicateTail(CodeTreeBuilder parent, NodeExecutionData execution, CodeTree assignment, LocalVariable target, LocalContext currentValues) { CodeTreeBuilder builder = parent.create(); - List sourceTypes = target.getType().getImplicitSourceTypes(); + List sourceTypes = typeSystem.lookupSourceTypes(target.getTypeMirror()); String implicitClassFieldName = implicitClassFieldName(execution); - String nodeFieldName = nodeFieldName(execution); List executableTypes = resolveSpecializedExecutables(execution, sourceTypes, options.implicitTypeBoxingOptimization()); boolean elseIf = false; for (ExecutableTypeData executableType : executableTypes) { elseIf = builder.startIf(elseIf); - builder.string(implicitClassFieldName).string(" == ").typeLiteral(executableType.getType().getPrimitiveType()); + builder.string(implicitClassFieldName).string(" == ").typeLiteral(executableType.getReturnType()); builder.end(); builder.startBlock(); builder.startStatement().tree(assignment); - CodeTree execute = callTemplateMethod(accessParent(nodeFieldName), executableType, currentValues); - ImplicitCastData cast = typeSystem.lookupCast(executableType.getType(), target.getType()); + CodeTree execute = callExecuteMethod(execution, executableType, currentValues); + ImplicitCastData cast = typeSystem.lookupCast(executableType.getReturnType(), target.getTypeMirror()); if (cast != null) { - execute = callTemplateMethod(null, cast, execute); + execute = callMethod(null, cast.getMethod(), execute); } builder.tree(execute); builder.end(); @@ -2137,13 +2376,13 @@ builder.startElseBlock(); } - LocalVariable genericValue = target.makeGeneric().nextName(); - builder.tree(createAssignExecuteChild(execution, genericValue.getType(), genericValue, null, currentValues)); + LocalVariable genericValue = target.makeGeneric(context).nextName(); + builder.tree(createAssignExecuteChild(builder, execution, node.getGenericExecutableType(null), genericValue, null, currentValues)); if (executableTypes.size() == sourceTypes.size()) { builder.startThrow().startNew(getType(UnexpectedResultException.class)).tree(genericValue.createReference()).end().end(); } else { builder.startStatement().tree(assignment); - builder.tree(TypeSystemCodeGenerator.implicitExpect(target.getType(), genericValue.createReference(), implicitClassFieldName)); + builder.tree(TypeSystemCodeGenerator.implicitExpect(typeSystem, target.getTypeMirror(), genericValue.createReference(), implicitClassFieldName)); builder.end(); } @@ -2153,7 +2392,7 @@ return builder.build(); } - private CodeTree createFastPathTryCatchRewriteException(SpecializationData specialization, TypeData forType, LocalContext currentValues, CodeTree execution) { + private CodeTree createFastPathTryCatchRewriteException(SpecializationData specialization, ExecutableTypeData forType, LocalContext currentValues, CodeTree execution) { if (specialization.getExceptions().isEmpty()) { return execution; } @@ -2248,8 +2487,8 @@ for (TypeGuard typeGuard : typeGuards) { int signatureIndex = typeGuard.getSignatureIndex(); LocalVariable value = currentValues.getValue(signatureIndex); - TypeData targetType = typeGuard.getType(); - if (!value.getType().needsCastTo(targetType)) { + TypeMirror targetType = typeGuard.getType(); + if (!ElementUtils.needsCastTo(value.getTypeMirror(), targetType)) { continue; } NodeExecutionData execution = node.getChildExecutions().get(signatureIndex); @@ -2264,7 +2503,7 @@ if (shortCircuit != null) { checkBuilder.string("("); CodeTreeBuilder referenceBuilder = checkBuilder.create(); - if (!shortCircuit.getType().isPrimitive()) { + if (!ElementUtils.isPrimitive(shortCircuit.getTypeMirror())) { referenceBuilder.string("(boolean) "); } referenceBuilder.tree(shortCircuit.createReference()); @@ -2276,15 +2515,15 @@ List sourceTypes = typeSystem.lookupByTargetType(targetType); CodeTree valueReference = value.createReference(); if (sourceTypes.isEmpty()) { - checkBuilder.tree(TypeSystemCodeGenerator.check(targetType, value.createReference())); - castBuilder.tree(TypeSystemCodeGenerator.cast(targetType, valueReference)); + checkBuilder.tree(TypeSystemCodeGenerator.check(typeSystem, targetType, value.createReference())); + castBuilder.tree(TypeSystemCodeGenerator.cast(typeSystem, targetType, valueReference)); } else { ImplicitCastOptimization opt = options.implicitCastOptimization(); if (specializationExecution.isFastPath() && !opt.isNone()) { if (opt.isDuplicateTail()) { String typeHintField = implicitClassFieldName(execution); - checkBuilder.tree(TypeSystemCodeGenerator.implicitCheck(targetType, valueReference, typeHintField)); - castBuilder.tree(TypeSystemCodeGenerator.implicitCast(targetType, valueReference, typeHintField)); + checkBuilder.tree(TypeSystemCodeGenerator.implicitCheck(typeSystem, targetType, valueReference, typeHintField)); + castBuilder.tree(TypeSystemCodeGenerator.implicitCast(typeSystem, targetType, valueReference, typeHintField)); } else if (opt.isMergeCasts()) { checkBuilder.tree(ImplicitCastNodeFactory.check(implicitNodeFieldName(execution), valueReference)); castBuilder.tree(ImplicitCastNodeFactory.cast(implicitNodeFieldName(execution), valueReference)); @@ -2292,14 +2531,14 @@ throw new AssertionError("implicit cast opt"); } } else { - checkBuilder.tree(TypeSystemCodeGenerator.implicitCheck(targetType, valueReference, null)); - castBuilder.tree(TypeSystemCodeGenerator.implicitCast(targetType, valueReference, null)); + checkBuilder.tree(TypeSystemCodeGenerator.implicitCheck(typeSystem, targetType, valueReference, null)); + castBuilder.tree(TypeSystemCodeGenerator.implicitCast(typeSystem, targetType, valueReference, null)); } } if (shortCircuit != null) { checkBuilder.string(")"); - castBuilder.string(" : ").defaultValue(targetType.getPrimitiveType()); + castBuilder.string(" : ").defaultValue(targetType); } if (castGuards == null || castGuards.contains(typeGuard)) { @@ -2329,7 +2568,7 @@ String varName = name + specialization.getIndex(); TypeMirror type = cache.getParameter().getType(); builder.declaration(type, varName, initializer); - currentValues.set(name, new LocalVariable(null, type, varName, null, null)); + currentValues.set(name, new LocalVariable(type, varName, null, null)); } public static final class LocalContext { @@ -2345,13 +2584,13 @@ for (CacheExpression cache : specialization.getCaches()) { Parameter cacheParameter = cache.getParameter(); String name = cacheParameter.getVariableElement().getSimpleName().toString(); - set(cacheParameter.getLocalName(), new LocalVariable(cacheParameter.getTypeSystemType(), cacheParameter.getType(), name, CodeTreeBuilder.singleString("this." + name), null)); + set(cacheParameter.getLocalName(), new LocalVariable(cacheParameter.getType(), name, CodeTreeBuilder.singleString("this." + name), null)); } for (AssumptionExpression assumption : specialization.getAssumptionExpressions()) { String name = assumptionName(assumption); TypeMirror type = assumption.getExpression().getResolvedType(); - set(name, new LocalVariable(null, type, name, CodeTreeBuilder.singleString("this." + name), null)); + set(name, new LocalVariable(type, name, CodeTreeBuilder.singleString("this." + name), null)); } } @@ -2382,12 +2621,12 @@ } @SuppressWarnings("static-method") - public LocalVariable createValue(NodeExecutionData execution, TypeData type) { - return new LocalVariable(type, type.getPrimitiveType(), valueName(execution), null, null); + public LocalVariable createValue(NodeExecutionData execution, TypeMirror type) { + return new LocalVariable(type, valueName(execution), null, null); } public LocalVariable createShortCircuitValue(NodeExecutionData execution) { - return new LocalVariable(factory.typeSystem.getBooleanType(), factory.getType(boolean.class), shortCircuitName(execution), null, null); + return new LocalVariable(factory.getType(boolean.class), shortCircuitName(execution), null, null); } private static String valueName(NodeExecutionData execution) { @@ -2424,7 +2663,12 @@ } public LocalVariable getValue(int signatureIndex) { - return getValue(factory.node.getChildExecutions().get(signatureIndex)); + List childExecutions = factory.node.getChildExecutions(); + if (signatureIndex < childExecutions.size()) { + return getValue(childExecutions.get(signatureIndex)); + } else { + return null; + } } public void removeValue(String id) { @@ -2458,11 +2702,11 @@ } private void loadValues(int evaluatedArguments, int varargsThreshold) { - values.put(FRAME_VALUE, new LocalVariable(null, factory.getType(Frame.class), FRAME_VALUE, null, null)); + values.put(FRAME_VALUE, new LocalVariable(factory.getType(Frame.class), FRAME_VALUE, null, null)); for (NodeFieldData field : factory.node.getFields()) { String fieldName = fieldValueName(field); - values.put(fieldName, new LocalVariable(null, field.getType(), fieldName, factory.accessParent(field.getName()), null)); + values.put(fieldName, new LocalVariable(field.getType(), fieldName, factory.accessParent(field.getName()), null)); } boolean varargs = needsVarargs(false, varargsThreshold); @@ -2473,7 +2717,7 @@ } NodeExecutionData execution = childExecutions.get(i); if (execution.isShortCircuit()) { - LocalVariable shortCircuit = createShortCircuitValue(execution).makeGeneric(); + LocalVariable shortCircuit = createShortCircuitValue(execution).makeGeneric(factory.context); if (varargs) { shortCircuit = shortCircuit.accessWith(createReadVarargs(i)); } @@ -2562,7 +2806,6 @@ public static final class LocalVariable { - private final TypeData type; private final TypeMirror typeMirror; private final CodeTree accessorTree; private final String name; @@ -2576,22 +2819,17 @@ } else { name = createName(execution); } - return new LocalVariable(parameter.getTypeSystemType(), parameter.getType(), name, null, null); + return new LocalVariable(parameter.getType(), name, null, null); } - private LocalVariable(TypeData type, TypeMirror typeMirror, String name, CodeTree accessorTree, LocalVariable previous) { + private LocalVariable(TypeMirror typeMirror, String name, CodeTree accessorTree, LocalVariable previous) { Objects.requireNonNull(typeMirror); this.typeMirror = typeMirror; this.accessorTree = accessorTree; - this.type = type; this.name = name; this.previous = previous; } - public TypeData getType() { - return type; - } - public String getShortCircuitName() { return "has" + ElementUtils.firstLetterUpperCase(getName()); } @@ -2631,24 +2869,20 @@ } } - public LocalVariable newType(TypeData newType) { - return new LocalVariable(newType, newType.getPrimitiveType(), name, accessorTree, this); - } - public LocalVariable newType(TypeMirror newType) { - return new LocalVariable(type, newType, name, accessorTree, this); + return new LocalVariable(newType, name, accessorTree, this); } public LocalVariable accessWith(CodeTree tree) { - return new LocalVariable(type, typeMirror, name, tree, this); + return new LocalVariable(typeMirror, name, tree, this); } public LocalVariable nextName() { - return new LocalVariable(type, typeMirror, createNextName(name), accessorTree, this); + return new LocalVariable(typeMirror, createNextName(name), accessorTree, this); } public LocalVariable makeOriginal() { - return new LocalVariable(type, typeMirror, name, accessorTree, null); + return new LocalVariable(typeMirror, name, accessorTree, null); } public LocalVariable original() { @@ -2659,8 +2893,8 @@ return variable; } - public LocalVariable makeGeneric() { - return newType(type.getTypeSystem().getGenericTypeData()); + public LocalVariable makeGeneric(ProcessorContext context) { + return newType(context.getType(Object.class)); } @Override diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/TypeSystemCodeGenerator.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/TypeSystemCodeGenerator.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/TypeSystemCodeGenerator.java Wed Apr 15 11:03:04 2015 -0700 @@ -22,12 +22,13 @@ */ package com.oracle.truffle.dsl.processor.generator; +import static com.oracle.truffle.dsl.processor.generator.GeneratorUtils.*; import static com.oracle.truffle.dsl.processor.java.ElementUtils.*; -import static com.oracle.truffle.dsl.processor.generator.GeneratorUtils.*; import static javax.lang.model.element.Modifier.*; import java.util.*; +import javax.lang.model.element.*; import javax.lang.model.type.*; import com.oracle.truffle.api.nodes.*; @@ -38,64 +39,47 @@ public class TypeSystemCodeGenerator extends CodeTypeElementFactory { - public static CodeTree cast(TypeData type, String content) { - return cast(type, CodeTreeBuilder.singleString(content)); + private static final String LOCAL_VALUE = "value"; + + public static CodeTree cast(TypeSystemData typeSystem, TypeMirror type, String content) { + return cast(typeSystem, type, CodeTreeBuilder.singleString(content)); } - public static CodeTree implicitType(TypeData type, CodeTree value) { - if (type.isGeneric()) { + public static CodeTree implicitType(TypeSystemData typeSystem, TypeMirror type, CodeTree value) { + if (ElementUtils.isObject(type)) { return value; } CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); - TypeSystemData typeSystem = type.getTypeSystem(); - builder.startStaticCall(createTypeSystemGen(typeSystem), getImplicitClass(type)).tree(value); + builder.startStaticCall(createTypeSystemGen(typeSystem), getImplicitClass(typeSystem, type)).tree(value); builder.end(); return builder.build(); } - public static CodeTree invokeImplicitCast(ImplicitCastData cast, CodeTree expression) { + public static CodeTree invokeImplicitCast(TypeSystemData typeSystem, ImplicitCastData cast, CodeTree expression) { CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); - TypeSystemData typeSystem = cast.getTargetType().getTypeSystem(); builder.startStaticCall(createTypeSystemGen(typeSystem), cast.getMethodName()).tree(expression); builder.end(); return builder.build(); } - public static CodeTree implicitCheck(TypeData type, CodeTree value, String typeHint) { - if (type.isGeneric()) { + public static CodeTree implicitCheck(TypeSystemData typeSystem, TypeMirror type, CodeTree value, String typeHint) { + return callImplictMethod(typeSystem, type, isImplicitTypeMethodName(typeSystem, type), value, typeHint); + } + + public static CodeTree implicitExpect(TypeSystemData typeSystem, TypeMirror type, CodeTree value, String typeHint) { + return callImplictMethod(typeSystem, type, expectImplicitTypeMethodName(typeSystem, type), value, typeHint); + } + + public static CodeTree implicitCast(TypeSystemData typeSystem, TypeMirror type, CodeTree value, String typeHint) { + return callImplictMethod(typeSystem, type, asImplicitTypeMethodName(typeSystem, type), value, typeHint); + } + + private static CodeTree callImplictMethod(TypeSystemData typeSystem, TypeMirror type, String methodName, CodeTree value, String typeHint) { + if (ElementUtils.isObject(type)) { return value; } CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); - TypeSystemData typeSystem = type.getTypeSystem(); - builder.startStaticCall(createTypeSystemGen(typeSystem), isImplicitTypeMethodName(type)).tree(value); - if (typeHint != null) { - builder.string(typeHint); - } - builder.end(); - return builder.build(); - } - - public static CodeTree implicitExpect(TypeData type, CodeTree value, String typeHint) { - if (type.isGeneric()) { - return value; - } - CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); - TypeSystemData typeSystem = type.getTypeSystem(); - builder.startStaticCall(createTypeSystemGen(typeSystem), expectImplicitTypeMethodName(type)).tree(value); - if (typeHint != null) { - builder.string(typeHint); - } - builder.end(); - return builder.build(); - } - - public static CodeTree implicitCast(TypeData type, CodeTree value, String typeHint) { - if (type.isGeneric()) { - return value; - } - CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); - TypeSystemData typeSystem = type.getTypeSystem(); - builder.startStaticCall(createTypeSystemGen(typeSystem), asImplicitTypeMethodName(type)).tree(value); + builder.startStaticCall(createTypeSystemGen(typeSystem), methodName).tree(value); if (typeHint != null) { builder.string(typeHint); } @@ -103,36 +87,60 @@ return builder.build(); } - public static CodeTree cast(TypeData type, CodeTree content) { - if (type.isGeneric()) { + public static CodeTree cast(TypeSystemData typeSystem, TypeMirror type, CodeTree content) { + if (ElementUtils.isObject(type)) { return content; } CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); - TypeSystemData typeSystem = type.getTypeSystem(); - if (type.isDefaultCast()) { - builder.cast(type.getPrimitiveType(), content); + TypeCastData cast = typeSystem.getCast(type); + if (cast == null) { + builder.cast(ElementUtils.fillInGenericWildcards(type), content); } else { - builder.startStaticCall(typeSystem.getTemplateType().asType(), type.getTypeCasts().get(0).getMethodName()).tree(content).end(); + builder.startStaticCall(typeSystem.getTemplateType().asType(), cast.getMethodName()).tree(content).end(); } return builder.build(); } - public static CodeTree expect(TypeData type, CodeTree content) { - if (type.isGeneric() || type.isVoid()) { + public static CodeTree expect(TypeSystemData typeSystem, TypeMirror type, CodeTree content) { + if (ElementUtils.isObject(type) || ElementUtils.isVoid(type)) { return content; } CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); - TypeSystemData typeSystem = type.getTypeSystem(); - builder.startStaticCall(createTypeSystemGen(typeSystem), expectTypeMethodName(type)).tree(content).end(); + if (typeSystem.hasType(type)) { + builder.startStaticCall(createTypeSystemGen(typeSystem), expectTypeMethodName(typeSystem, type)).tree(content).end(); + } else { + builder.startCall(expectTypeMethodName(typeSystem, type)).tree(content).end(); + } + return builder.build(); } - public static CodeTree expect(TypeData sourceType, TypeData targetType, CodeTree content) { - if (sourceType != null && !sourceType.needsCastTo(targetType)) { + public static CodeExecutableElement createExpectMethod(Modifier visibility, TypeSystemData typeSystem, TypeMirror sourceTypeOriginal, TypeMirror expectedTypeOriginal) { + TypeMirror expectedType = ElementUtils.fillInGenericWildcards(expectedTypeOriginal); + TypeMirror sourceType = ElementUtils.fillInGenericWildcards(sourceTypeOriginal); + if (ElementUtils.isObject(expectedType) || ElementUtils.isVoid(expectedType)) { + return null; + } + + CodeExecutableElement method = new CodeExecutableElement(modifiers(STATIC), expectedType, TypeSystemCodeGenerator.expectTypeMethodName(typeSystem, expectedType)); + method.setVisibility(visibility); + method.addParameter(new CodeVariableElement(sourceType, LOCAL_VALUE)); + method.addThrownType(typeSystem.getContext().getTruffleTypes().getUnexpectedValueException()); + + CodeTreeBuilder body = method.createBuilder(); + body.startIf().tree(check(typeSystem, expectedType, LOCAL_VALUE)).end().startBlock(); + body.startReturn().tree(cast(typeSystem, expectedType, LOCAL_VALUE)).end(); + body.end(); + body.startThrow().startNew(typeSystem.getContext().getTruffleTypes().getUnexpectedValueException()).string(LOCAL_VALUE).end().end(); + return method; + } + + public static CodeTree expect(TypeSystemData typeSystem, TypeMirror sourceType, TypeMirror targetType, CodeTree content) { + if (sourceType != null && !ElementUtils.needsCastTo(sourceType, targetType)) { return content; } else { - return expect(targetType, content); + return expect(typeSystem, targetType, content); } } @@ -140,51 +148,55 @@ return new GeneratedTypeMirror(ElementUtils.getPackageName(typeSystem.getTemplateType()), typeName(typeSystem)); } - public static CodeTree check(TypeData type, String content) { - return check(type, CodeTreeBuilder.singleString(content)); + public static CodeTree check(TypeSystemData typeSystem, TypeMirror type, String content) { + return check(typeSystem, type, CodeTreeBuilder.singleString(content)); } - public static CodeTree check(TypeData type, CodeTree content) { - if (type.isGeneric()) { + public static CodeTree check(TypeSystemData typeSystem, TypeMirror type, CodeTree content) { + if (ElementUtils.isObject(type)) { return content; } CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); - TypeSystemData typeSystem = type.getTypeSystem(); - if (type.isDefaultCheck()) { - builder.instanceOf(content, type.getBoxedType()); + TypeCheckData check = typeSystem.getCheck(type); + if (check == null) { + builder.instanceOf(content, ElementUtils.boxType(typeSystem.getContext(), type)); } else { - builder.startStaticCall(typeSystem.getTemplateType().asType(), type.getTypeChecks().get(0).getMethodName()).tree(content).end(); + builder.startStaticCall(typeSystem.getTemplateType().asType(), check.getMethodName()).tree(content).end(); } return builder.build(); } - public static String isTypeMethodName(TypeData type) { - return "is" + ElementUtils.getTypeId(type.getBoxedType()); + public static String isTypeMethodName(TypeSystemData typeSystem, TypeMirror type) { + return "is" + getTypeId(typeSystem, type); } - static String isImplicitTypeMethodName(TypeData type) { - return "isImplicit" + ElementUtils.getTypeId(type.getBoxedType()); + private static String getTypeId(TypeSystemData typeSystem, TypeMirror type) { + return ElementUtils.getTypeId(typeSystem.boxType(type)); } - public static String asTypeMethodName(TypeData type) { - return "as" + ElementUtils.getTypeId(type.getBoxedType()); + static String isImplicitTypeMethodName(TypeSystemData typeSystem, TypeMirror type) { + return "isImplicit" + getTypeId(typeSystem, type); } - static String asImplicitTypeMethodName(TypeData type) { - return "asImplicit" + ElementUtils.getTypeId(type.getBoxedType()); + public static String asTypeMethodName(TypeSystemData typeSystem, TypeMirror type) { + return "as" + getTypeId(typeSystem, type); + } + + static String asImplicitTypeMethodName(TypeSystemData typeSystem, TypeMirror type) { + return "asImplicit" + getTypeId(typeSystem, type); } - static String expectImplicitTypeMethodName(TypeData type) { - return "expectImplicit" + ElementUtils.getTypeId(type.getBoxedType()); + static String expectImplicitTypeMethodName(TypeSystemData typeSystem, TypeMirror type) { + return "expectImplicit" + getTypeId(typeSystem, type); } - static String getImplicitClass(TypeData type) { - return "getImplicit" + ElementUtils.getTypeId(type.getBoxedType()) + "Class"; + static String getImplicitClass(TypeSystemData typeSystem, TypeMirror type) { + return "getImplicit" + getTypeId(typeSystem, type) + "Class"; } - public static String expectTypeMethodName(TypeData type) { - return "expect" + ElementUtils.getTypeId(type.getBoxedType()); + public static String expectTypeMethodName(TypeSystemData typeSystem, TypeMirror type) { + return "expect" + getTypeId(typeSystem, type); } static String typeName(TypeSystemData typeSystem) { @@ -200,14 +212,9 @@ public CodeTypeElement create(ProcessorContext context, TypeSystemData typeSystem) { CodeTypeElement clazz = new TypeClassFactory(context, typeSystem).create(); - clazz.add(new TypeSystemNodeFactory(context, typeSystem).create()); - if (typeSystem.getOptions().implicitCastOptimization().isMergeCasts()) { - for (TypeData type : typeSystem.getTypes()) { - List sourceTypes = typeSystem.lookupSourceTypes(type); - if (sourceTypes.size() > 1) { - clazz.add(new ImplicitCastNodeFactory(context, type).create()); - } + for (TypeMirror type : typeSystem.lookupTargetTypes()) { + clazz.add(new ImplicitCastNodeFactory(context, typeSystem, type).create()); } } return clazz; @@ -215,8 +222,6 @@ private static class TypeClassFactory { - private static final String LOCAL_VALUE = "value"; - private final ProcessorContext context; private final TypeSystemData typeSystem; @@ -233,50 +238,35 @@ CodeVariableElement singleton = createSingleton(clazz); clazz.add(singleton); - for (TypeData type : typeSystem.getTypes()) { - if (type.isVoid() || type.isGeneric()) { + for (TypeMirror type : typeSystem.getLegacyTypes()) { + if (ElementUtils.isVoid(type) || ElementUtils.isObject(type)) { continue; } clazz.addOptional(createIsTypeMethod(type)); clazz.addOptional(createAsTypeMethod(type)); + clazz.addOptional(createExpectTypeMethod(type, context.getType(Object.class))); - for (TypeData sourceType : collectExpectSourceTypes(type)) { - clazz.addOptional(createExpectTypeMethod(type, sourceType)); - } + } - if (type.hasImplicitSourceTypes()) { - clazz.add(createAsImplicitTypeMethod(type, false)); - if (typeSystem.getOptions().implicitCastOptimization().isNone()) { - clazz.add(createExpectImplicitTypeMethod(type, false)); - } - clazz.add(createIsImplicitTypeMethod(type, false)); + List lookupTargetTypes = typeSystem.lookupTargetTypes(); + for (TypeMirror type : lookupTargetTypes) { + clazz.add(createAsImplicitTypeMethod(type, false)); + if (typeSystem.getOptions().implicitCastOptimization().isNone()) { + clazz.add(createExpectImplicitTypeMethod(type, false)); + } + clazz.add(createIsImplicitTypeMethod(type, false)); - if (typeSystem.getOptions().implicitCastOptimization().isDuplicateTail()) { - clazz.add(createAsImplicitTypeMethod(type, true)); - clazz.add(createExpectImplicitTypeMethod(type, true)); - clazz.add(createIsImplicitTypeMethod(type, true)); - clazz.add(createGetImplicitClass(type)); - } + if (typeSystem.getOptions().implicitCastOptimization().isDuplicateTail()) { + clazz.add(createAsImplicitTypeMethod(type, true)); + clazz.add(createExpectImplicitTypeMethod(type, true)); + clazz.add(createIsImplicitTypeMethod(type, true)); + clazz.add(createGetImplicitClass(type)); } } - return clazz; } - private static List collectExpectSourceTypes(TypeData type) { - Set sourceTypes = new HashSet<>(); - sourceTypes.add(type.getTypeSystem().getGenericTypeData()); - for (TypeCastData cast : type.getTypeCasts()) { - sourceTypes.add(cast.getSourceType()); - } - for (TypeCheckData cast : type.getTypeChecks()) { - sourceTypes.add(cast.getCheckedType()); - } - sourceTypes.remove(type); - return new ArrayList<>(sourceTypes); - } - private CodeVariableElement createSingleton(CodeTypeElement clazz) { CodeVariableElement field = new CodeVariableElement(modifiers(PUBLIC, STATIC, FINAL), clazz.asType(), singletonName(typeSystem)); field.createInitBuilder().startNew(clazz.asType()).end(); @@ -287,24 +277,24 @@ return field; } - private CodeExecutableElement createIsImplicitTypeMethod(TypeData type, boolean typed) { - CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), context.getType(boolean.class), TypeSystemCodeGenerator.isImplicitTypeMethodName(type)); + private CodeExecutableElement createIsImplicitTypeMethod(TypeMirror type, boolean typed) { + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), context.getType(boolean.class), TypeSystemCodeGenerator.isImplicitTypeMethodName(typeSystem, type)); method.addParameter(new CodeVariableElement(context.getType(Object.class), LOCAL_VALUE)); if (typed) { method.addParameter(new CodeVariableElement(context.getType(Class.class), "typeHint")); } CodeTreeBuilder builder = method.createBuilder(); - List sourceTypes = typeSystem.lookupSourceTypes(type); + List sourceTypes = typeSystem.lookupSourceTypes(type); builder.startReturn(); String sep = ""; - for (TypeData sourceType : sourceTypes) { + for (TypeMirror sourceType : sourceTypes) { builder.string(sep); if (typed) { - builder.string("(typeHint == ").typeLiteral(sourceType.getPrimitiveType()).string(" && "); + builder.string("(typeHint == ").typeLiteral(sourceType).string(" && "); } - builder.tree(check(sourceType, LOCAL_VALUE)); + builder.tree(check(typeSystem, sourceType, LOCAL_VALUE)); if (typed) { builder.string(")"); } @@ -321,24 +311,24 @@ return method; } - private CodeExecutableElement createAsImplicitTypeMethod(TypeData type, boolean useTypeHint) { - String name = asImplicitTypeMethodName(type); - CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), type.getPrimitiveType(), name); + private CodeExecutableElement createAsImplicitTypeMethod(TypeMirror type, boolean useTypeHint) { + String name = asImplicitTypeMethodName(typeSystem, type); + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), type, name); method.addParameter(new CodeVariableElement(context.getType(Object.class), LOCAL_VALUE)); if (useTypeHint) { method.addParameter(new CodeVariableElement(context.getType(Class.class), "typeHint")); } - List sourceTypes = typeSystem.lookupSourceTypes(type); + List sourceTypes = typeSystem.lookupSourceTypes(type); CodeTreeBuilder builder = method.createBuilder(); boolean elseIf = false; - for (TypeData sourceType : sourceTypes) { + for (TypeMirror sourceType : sourceTypes) { elseIf = builder.startIf(elseIf); if (useTypeHint) { - builder.string("typeHint == ").typeLiteral(sourceType.getPrimitiveType()); + builder.string("typeHint == ").typeLiteral(sourceType); } else { - builder.tree(check(sourceType, LOCAL_VALUE)); + builder.tree(check(typeSystem, sourceType, LOCAL_VALUE)); } builder.end().startBlock(); @@ -348,7 +338,7 @@ if (cast != null) { builder.startCall(cast.getMethodName()); } - builder.tree(cast(sourceType, LOCAL_VALUE)).end(); + builder.tree(cast(typeSystem, sourceType, LOCAL_VALUE)).end(); if (cast != null) { builder.end(); } @@ -363,26 +353,26 @@ return method; } - private CodeExecutableElement createExpectImplicitTypeMethod(TypeData type, boolean useTypeHint) { - String name = expectImplicitTypeMethodName(type); - CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), type.getPrimitiveType(), name); + private CodeExecutableElement createExpectImplicitTypeMethod(TypeMirror type, boolean useTypeHint) { + String name = expectImplicitTypeMethodName(typeSystem, type); + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), type, name); method.addParameter(new CodeVariableElement(context.getType(Object.class), LOCAL_VALUE)); if (useTypeHint) { method.addParameter(new CodeVariableElement(context.getType(Class.class), "typeHint")); } method.getThrownTypes().add(context.getType(UnexpectedResultException.class)); - List sourceTypes = typeSystem.lookupSourceTypes(type); + List sourceTypes = typeSystem.lookupSourceTypes(type); CodeTreeBuilder builder = method.createBuilder(); boolean elseIf = false; - for (TypeData sourceType : sourceTypes) { + for (TypeMirror sourceType : sourceTypes) { elseIf = builder.startIf(elseIf); if (useTypeHint) { - builder.string("typeHint == ").typeLiteral(sourceType.getPrimitiveType()); + builder.string("typeHint == ").typeLiteral(sourceType); builder.string(" && "); } - builder.tree(check(sourceType, LOCAL_VALUE)); + builder.tree(check(typeSystem, sourceType, LOCAL_VALUE)); builder.end().startBlock(); @@ -391,7 +381,7 @@ if (cast != null) { builder.startCall(cast.getMethodName()); } - builder.tree(cast(sourceType, LOCAL_VALUE)).end(); + builder.tree(cast(typeSystem, sourceType, LOCAL_VALUE)).end(); if (cast != null) { builder.end(); } @@ -405,18 +395,18 @@ return method; } - private CodeExecutableElement createGetImplicitClass(TypeData type) { - CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), context.getType(Class.class), TypeSystemCodeGenerator.getImplicitClass(type)); + private CodeExecutableElement createGetImplicitClass(TypeMirror type) { + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), context.getType(Class.class), TypeSystemCodeGenerator.getImplicitClass(typeSystem, type)); method.addParameter(new CodeVariableElement(context.getType(Object.class), LOCAL_VALUE)); - List sourceTypes = typeSystem.lookupSourceTypes(type); + List sourceTypes = typeSystem.lookupSourceTypes(type); CodeTreeBuilder builder = method.createBuilder(); boolean elseIf = false; - for (TypeData sourceType : sourceTypes) { + for (TypeMirror sourceType : sourceTypes) { elseIf = builder.startIf(elseIf); - builder.tree(check(sourceType, LOCAL_VALUE)).end(); + builder.tree(check(typeSystem, sourceType, LOCAL_VALUE)).end(); builder.end().startBlock(); - builder.startReturn().typeLiteral(sourceType.getPrimitiveType()).end(); + builder.startReturn().typeLiteral(sourceType).end(); builder.end(); } @@ -428,50 +418,39 @@ return method; } - private CodeExecutableElement createIsTypeMethod(TypeData type) { - if (!type.getTypeChecks().isEmpty()) { + private CodeExecutableElement createIsTypeMethod(TypeMirror type) { + if (typeSystem.getCheck(type) != null) { return null; } - CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), context.getType(boolean.class), TypeSystemCodeGenerator.isTypeMethodName(type)); + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), context.getType(boolean.class), TypeSystemCodeGenerator.isTypeMethodName(typeSystem, type)); method.addParameter(new CodeVariableElement(context.getType(Object.class), LOCAL_VALUE)); CodeTreeBuilder body = method.createBuilder(); - body.startReturn().tree(check(type, LOCAL_VALUE)).end(); + body.startReturn().tree(check(typeSystem, type, LOCAL_VALUE)).end(); return method; } - private CodeExecutableElement createAsTypeMethod(TypeData type) { - if (!type.getTypeCasts().isEmpty()) { + private CodeExecutableElement createAsTypeMethod(TypeMirror type) { + if (typeSystem.getCast(type) != null) { return null; } - CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), type.getPrimitiveType(), TypeSystemCodeGenerator.asTypeMethodName(type)); + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), type, TypeSystemCodeGenerator.asTypeMethodName(typeSystem, type)); method.addParameter(new CodeVariableElement(context.getType(Object.class), LOCAL_VALUE)); CodeTreeBuilder body = method.createBuilder(); - String assertMessage = typeName(typeSystem) + "." + asTypeMethodName(type) + ": " + ElementUtils.getSimpleName(type.getBoxedType()) + " expected"; - body.startAssert().tree(check(type, LOCAL_VALUE)).string(" : ").doubleQuote(assertMessage).end(); - body.startReturn().tree(cast(type, LOCAL_VALUE)).end(); + String assertMessage = typeName(typeSystem) + "." + asTypeMethodName(typeSystem, type) + ": " + ElementUtils.getSimpleName(type) + " expected"; + body.startAssert().tree(check(typeSystem, type, LOCAL_VALUE)).string(" : ").doubleQuote(assertMessage).end(); + body.startReturn().tree(cast(typeSystem, type, LOCAL_VALUE)).end(); return method; } - private CodeExecutableElement createExpectTypeMethod(TypeData expectedType, TypeData sourceType) { - CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), expectedType.getPrimitiveType(), TypeSystemCodeGenerator.expectTypeMethodName(expectedType)); - method.addParameter(new CodeVariableElement(sourceType.getPrimitiveType(), LOCAL_VALUE)); - method.addThrownType(context.getTruffleTypes().getUnexpectedValueException()); - - CodeTreeBuilder body = method.createBuilder(); - body.startIf().tree(check(expectedType, LOCAL_VALUE)).end().startBlock(); - body.startReturn().tree(cast(expectedType, LOCAL_VALUE)).end().end(); - body.end(); // if-block - body.startThrow().startNew(context.getTruffleTypes().getUnexpectedValueException()).string(LOCAL_VALUE).end().end(); - - return method; + private CodeExecutableElement createExpectTypeMethod(TypeMirror expectedType, TypeMirror sourceType) { + return createExpectMethod(Modifier.PUBLIC, typeSystem, sourceType, expectedType); } - } } diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/TypeSystemNodeFactory.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/TypeSystemNodeFactory.java Wed Apr 15 10:09:13 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,132 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.dsl.processor.generator; - -import static com.oracle.truffle.dsl.processor.java.ElementUtils.*; -import static javax.lang.model.element.Modifier.*; - -import javax.lang.model.element.*; -import javax.lang.model.type.*; -import javax.lang.model.util.*; - -import com.oracle.truffle.api.dsl.internal.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.dsl.processor.*; -import com.oracle.truffle.dsl.processor.java.*; -import com.oracle.truffle.dsl.processor.java.model.*; -import com.oracle.truffle.dsl.processor.model.*; - -public class TypeSystemNodeFactory { - - private final ProcessorContext context; - private final TypeSystemData typeSystem; - private final DSLOptions options; - - public TypeSystemNodeFactory(ProcessorContext context, TypeSystemData typeSystem) { - this.context = context; - this.typeSystem = typeSystem; - this.options = typeSystem.getOptions(); - } - - public static TypeMirror nodeType(TypeSystemData typeSystem) { - TypeMirror parentType = TypeSystemCodeGenerator.createTypeSystemGen(typeSystem); - return new GeneratedTypeMirror(getQualifiedName(parentType), typeName(typeSystem)); - } - - public static String typeName(TypeSystemData typeSystem) { - return getTypeId(typeSystem.getTemplateType().asType()) + "Node"; - } - - public static String acceptAndExecuteName() { - return "acceptAndExecute"; - } - - public static String executeName(TypeData type) { - if (type == null) { - return acceptAndExecuteName(); - } else if (type.isGeneric()) { - return "executeGeneric"; - } else { - return "execute" + getTypeId(type.getBoxedType()); - } - } - - public static String voidBoxingExecuteName(TypeData type) { - return executeName(type) + "Void"; - } - - public CodeTypeElement create() { - String typeName = typeName(typeSystem); - TypeMirror baseType = context.getType(SpecializationNode.class); - CodeTypeElement clazz = GeneratorUtils.createClass(typeSystem, null, modifiers(PUBLIC, ABSTRACT, STATIC), typeName, baseType); - - for (ExecutableElement constructor : ElementFilter.constructorsIn(ElementUtils.fromTypeMirror(baseType).getEnclosedElements())) { - clazz.add(GeneratorUtils.createSuperConstructor(context, clazz, constructor)); - } - - for (TypeData type : typeSystem.getTypes()) { - clazz.add(createExecuteMethod(type)); - if (GeneratorUtils.isTypeBoxingOptimized(options.voidBoxingOptimization(), type)) { - clazz.add(createVoidBoxingExecuteMethod(type)); - } - } - return clazz; - } - - private Element createVoidBoxingExecuteMethod(TypeData type) { - TypeData voidType = typeSystem.getVoidType(); - String methodName = voidBoxingExecuteName(type); - CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, FINAL), voidType.getPrimitiveType(), methodName); - method.addParameter(new CodeVariableElement(context.getType(Frame.class), "frame")); - - CodeTreeBuilder builder = method.createBuilder(); - builder.startTryBlock(); - builder.startStatement().startCall(executeName(type)).string("frame").end().end(); - builder.end(); - builder.startCatchBlock(context.getType(UnexpectedResultException.class), "e"); - builder.end(); - - return method; - } - - private Element createExecuteMethod(TypeData type) { - TypeData genericType = typeSystem.getGenericTypeData(); - String methodName = executeName(type); - CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), type.getPrimitiveType(), methodName); - method.addParameter(new CodeVariableElement(context.getType(Frame.class), "frame")); - - if (type.isGeneric()) { - method.getModifiers().add(ABSTRACT); - } else { - CodeTreeBuilder builder = method.createBuilder(); - CodeTree executeGeneric = builder.create().startCall(executeName(genericType)).string("frame").end().build(); - if (!type.isVoid()) { - method.getThrownTypes().add(context.getType(UnexpectedResultException.class)); - } - builder.startReturn().tree(TypeSystemCodeGenerator.expect(type, executeGeneric)).end(); - } - - return method; - } -} diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java Wed Apr 15 11:03:04 2015 -0700 @@ -120,6 +120,9 @@ } public static TypeMirror boxType(ProcessorContext context, TypeMirror primitiveType) { + if (primitiveType == null) { + return null; + } TypeMirror boxedType = primitiveType; if (boxedType.getKind().isPrimitive()) { boxedType = context.getEnvironment().getTypeUtils().boxedClass((PrimitiveType) boxedType).asType(); @@ -144,13 +147,14 @@ return result; } - public static TypeMirror getCommonSuperType(ProcessorContext context, TypeMirror[] types) { - if (types.length == 0) { + public static TypeMirror getCommonSuperType(ProcessorContext context, Collection types) { + if (types.isEmpty()) { return context.getType(Object.class); } - TypeMirror prev = types[0]; - for (int i = 1; i < types.length; i++) { - prev = getCommonSuperType(context, prev, types[i]); + Iterator typesIterator = types.iterator(); + TypeMirror prev = typesIterator.next(); + while (typesIterator.hasNext()) { + prev = getCommonSuperType(context, prev, typesIterator.next()); } return prev; } @@ -162,6 +166,11 @@ TypeElement element1 = fromTypeMirror(type1); TypeElement element2 = fromTypeMirror(type2); if (element1 == null || element2 == null) { + if (element1 != null) { + return type1; + } else if (element2 != null) { + return type2; + } return context.getType(Object.class); } @@ -217,6 +226,10 @@ } } + public static boolean isSubtypeBoxed(ProcessorContext context, TypeMirror from, TypeMirror to) { + return isSubtype(boxType(context, from), boxType(context, to)); + } + public static boolean isSubtype(TypeMirror type1, TypeMirror type2) { if (type1 instanceof CodeTypeMirror || type2 instanceof CodeTypeMirror) { throw new UnsupportedOperationException(); @@ -225,8 +238,14 @@ } public static boolean isAssignable(TypeMirror from, TypeMirror to) { + if (typeEquals(from, to)) { + return true; + } else if (isVoid(to)) { + return true; + } else if (isObject(to)) { + return true; + } ProcessorContext context = ProcessorContext.getInstance(); - if (!(from instanceof CodeTypeMirror) && !(to instanceof CodeTypeMirror)) { return context.getEnvironment().getTypeUtils().isAssignable(context.reloadType(from), context.reloadType(to)); } else { @@ -359,6 +378,8 @@ return getTypeId(((ArrayType) mirror).getComponentType()) + "Array"; case VOID: return "Void"; + case NULL: + return "Null"; case WILDCARD: StringBuilder b = new StringBuilder(); WildcardType type = (WildcardType) mirror; @@ -405,6 +426,8 @@ return getSimpleName(((ArrayType) mirror).getComponentType()) + "[]"; case VOID: return "void"; + case NULL: + return "null"; case WILDCARD: return getWildcardName((WildcardType) mirror); case TYPEVAR: @@ -495,6 +518,8 @@ return getQualifiedName(((ArrayType) mirror).getComponentType()); case VOID: return "void"; + case NULL: + return "null"; case TYPEVAR: return getSimpleName(mirror); case ERROR: @@ -656,6 +681,7 @@ case INT: case LONG: case VOID: + case NULL: case TYPEVAR: return null; case DECLARED: @@ -939,6 +965,13 @@ return true; } else if (kindIsIntegral(type1.getKind())) { return kindIsIntegral(type2.getKind()); + } else if (type1.getKind() == TypeKind.NULL) { + if (type2.getKind() == TypeKind.NULL) { + return false; + } + return true; + } else if (type2.getKind() == TypeKind.NULL) { + return true; } else { return false; } @@ -1122,4 +1155,82 @@ throw new AssertionError("unsupported element type"); } } + + public static List sortTypes(List list) { + Collections.sort(list, new Comparator() { + public int compare(TypeMirror o1, TypeMirror o2) { + return compareType(o1, o2); + } + }); + return list; + } + + public static int compareType(TypeMirror signature1, TypeMirror signature2) { + if (signature1 == null) { + return 1; + } else if (signature2 == null) { + return -1; + } + + if (ElementUtils.typeEquals(signature1, signature2)) { + return 0; + } + + if (signature1.getKind() == TypeKind.DECLARED && signature2.getKind() == TypeKind.DECLARED) { + TypeElement element1 = ElementUtils.fromTypeMirror(signature1); + TypeElement element2 = ElementUtils.fromTypeMirror(signature2); + + if (ElementUtils.getDirectSuperTypes(element1).contains(element2)) { + return -1; + } else if (ElementUtils.getDirectSuperTypes(element2).contains(element1)) { + return 1; + } + } + return ElementUtils.getSimpleName(signature1).compareTo(ElementUtils.getSimpleName(signature2)); + } + + public static List uniqueSortedTypes(Collection types) { + if (types.isEmpty()) { + return new ArrayList<>(0); + } else if (types.size() <= 1) { + if (types instanceof List) { + return (List) types; + } else { + return new ArrayList<>(types); + } + } + Map sourceTypes = new HashMap<>(); + for (TypeMirror type : types) { + sourceTypes.put(ElementUtils.getTypeId(type), type); + } + return sortTypes(new ArrayList<>(sourceTypes.values())); + } + + public static int compareMethod(ExecutableElement method1, ExecutableElement method2) { + List parameters1 = method1.getParameters(); + List parameters2 = method2.getParameters(); + if (parameters1.size() != parameters2.size()) { + return Integer.compare(parameters1.size(), parameters2.size()); + } + + int result = 0; + for (int i = 0; i < parameters1.size(); i++) { + VariableElement var1 = parameters1.get(i); + VariableElement var2 = parameters2.get(i); + result = compareType(var1.asType(), var2.asType()); + if (result != 0) { + return result; + } + } + + result = method1.getSimpleName().toString().compareTo(method2.getSimpleName().toString()); + if (result == 0) { + // if still no difference sort by enclosing type name + TypeElement enclosingType1 = ElementUtils.findNearestEnclosingType(method1); + TypeElement enclosingType2 = ElementUtils.findNearestEnclosingType(method2); + result = enclosingType1.getQualifiedName().toString().compareTo(enclosingType2.getQualifiedName().toString()); + } + return result; + } + } diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeExecutableElement.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeExecutableElement.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeExecutableElement.java Wed Apr 15 11:03:04 2015 -0700 @@ -58,6 +58,14 @@ } } + public void setVisibility(Modifier visibility) { + ElementUtils.setVisibility(getModifiers(), visibility); + } + + public Modifier getVisibility() { + return ElementUtils.getVisibility(getModifiers()); + } + /* Support JDK8 langtools. */ public boolean isDefault() { return false; diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeTreeBuilder.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeTreeBuilder.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeTreeBuilder.java Wed Apr 15 11:03:04 2015 -0700 @@ -316,6 +316,13 @@ } } + public CodeTreeBuilder trees(CodeTree... trees) { + for (CodeTree tree : trees) { + tree(tree); + } + return this; + } + public CodeTreeBuilder string(String chunk1, String chunk2, String chunk3, String chunk4, String... chunks) { push(GROUP).string(chunk1).string(chunk2).string(chunk3).string(chunk4); for (int i = 0; i < chunks.length; i++) { @@ -861,4 +868,15 @@ } } + public CodeTreeBuilder returnDefault() { + ExecutableElement method = findMethod(); + if (ElementUtils.isVoid(method.getReturnType())) { + returnStatement(); + } else { + startReturn().defaultValue(method.getReturnType()).end(); + } + return this; + + } + } diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/transform/AbstractCodeWriter.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/transform/AbstractCodeWriter.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/transform/AbstractCodeWriter.java Wed Apr 15 11:03:04 2015 -0700 @@ -258,7 +258,7 @@ init = ((CodeVariableElement) f).getInit(); } - if (parent.getKind() == ElementKind.ENUM && f.getModifiers().contains(Modifier.STATIC)) { + if (parent != null && parent.getKind() == ElementKind.ENUM && f.getModifiers().contains(Modifier.STATIC)) { write(f.getSimpleName()); if (init != null) { write("("); @@ -266,12 +266,11 @@ write(")"); } } else { - Element enclosing = f.getEnclosingElement(); writeModifiers(f.getModifiers(), true); boolean varArgs = false; - if (enclosing.getKind() == ElementKind.METHOD) { - ExecutableElement method = (ExecutableElement) enclosing; + if (parent != null && parent.getKind() == ElementKind.METHOD) { + ExecutableElement method = (ExecutableElement) parent; if (method.isVarArgs() && method.getParameters().indexOf(f) == method.getParameters().size() - 1) { varArgs = true; } diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ExecutableTypeData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ExecutableTypeData.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ExecutableTypeData.java Wed Apr 15 11:03:04 2015 -0700 @@ -22,67 +22,309 @@ */ package com.oracle.truffle.dsl.processor.model; +import java.util.*; + +import static com.oracle.truffle.dsl.processor.java.ElementUtils.*; + import javax.lang.model.element.*; +import javax.lang.model.type.*; import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.dsl.processor.*; import com.oracle.truffle.dsl.processor.java.*; -public class ExecutableTypeData extends TemplateMethod { +public class ExecutableTypeData extends MessageContainer implements Comparable { - private final TypeSystemData typeSystem; - private final TypeData type; + private final ExecutableElement method; + private final TypeMirror returnType; + private final TypeMirror frameParameter; + private final List evaluatedParameters; + private ExecutableTypeData delegatedTo; + private final List delegatedFrom = new ArrayList<>(); - public ExecutableTypeData(TemplateMethod method, ExecutableElement executable, TypeSystemData typeSystem, TypeData type) { - super(method, executable); - this.typeSystem = typeSystem; - this.type = type; - if (executable.getParameters().size() < method.getMethod().getParameters().size()) { - throw new IllegalArgumentException(String.format("Method parameter count mismatch %s != %s.", executable.getParameters(), method.getMethod().getParameters())); - } + private String uniqueName; + + public ExecutableTypeData(TypeMirror returnType, String uniqueName, TypeMirror frameParameter, List evaluatedParameters) { + this.returnType = returnType; + this.frameParameter = frameParameter; + this.evaluatedParameters = evaluatedParameters; + this.uniqueName = uniqueName; + this.method = null; } - public TypeData getType() { - return type; + public ExecutableTypeData(ExecutableElement method, int signatureSize, List frameTypes) { + this.method = method; + this.returnType = method.getReturnType(); + TypeMirror foundFrameParameter = null; + List parameters = method.getParameters(); + + int parameterIndex = 0; + evaluatedParameters = new ArrayList<>(); + if (!parameters.isEmpty()) { + TypeMirror firstParameter = parameters.get(0).asType(); + for (TypeMirror frameType : frameTypes) { + if (ElementUtils.typeEquals(firstParameter, frameType)) { + foundFrameParameter = firstParameter; + parameterIndex++; + break; + } + } + } + + int numberParameters = Math.max(parameters.size() - parameterIndex, signatureSize); + for (int i = 0; i < numberParameters; i++) { + TypeMirror parameter; + if (method.isVarArgs() && parameterIndex >= parameters.size() - 1) { + ArrayType varArgsArray = (ArrayType) parameters.get(parameters.size() - 1).asType(); + parameter = varArgsArray.getComponentType(); + } else if (parameterIndex < parameters.size()) { + parameter = parameters.get(parameterIndex).asType(); + } else { + break; + } + parameterIndex++; + evaluatedParameters.add(parameter); + } + this.frameParameter = foundFrameParameter; + this.uniqueName = "execute" + (ElementUtils.isObject(getReturnType()) ? "" : ElementUtils.getTypeId(getReturnType())); + } + + public void addDelegatedFrom(ExecutableTypeData child) { + this.delegatedFrom.add(child); + child.delegatedTo = this; } - public TypeSystemData getTypeSystem() { - return typeSystem; + public List getDelegatedFrom() { + return delegatedFrom; + } + + public ExecutableTypeData getDelegatedTo() { + return delegatedTo; + } + + public ExecutableElement getMethod() { + return method; + } + + public String getUniqueName() { + return uniqueName; + } + + public void setUniqueName(String name) { + this.uniqueName = name; + } + + @Override + public Element getMessageElement() { + return method; + } + + public List getEvaluatedParameters() { + return evaluatedParameters; + } + + public int getVarArgsIndex(int parameterIndex) { + if (method.isVarArgs()) { + int index = parameterIndex - (method.getParameters().size() - 1); + return index; + } + return -1; + } + + public int getParameterIndex(int signatureIndex) { + return frameParameter != null ? signatureIndex + 1 : signatureIndex; + } + + public TypeMirror getFrameParameter() { + return frameParameter; + } + + public TypeMirror getReturnType() { + return returnType; } public boolean hasUnexpectedValue(ProcessorContext context) { - return ElementUtils.canThrowType(getMethod().getThrownTypes(), context.getType(UnexpectedResultException.class)); + return method == null ? false : ElementUtils.canThrowType(method.getThrownTypes(), context.getType(UnexpectedResultException.class)); } public boolean isFinal() { - return getMethod().getModifiers().contains(Modifier.FINAL); + return method == null ? false : method.getModifiers().contains(Modifier.FINAL); } public boolean isAbstract() { - return getMethod().getModifiers().contains(Modifier.ABSTRACT); + return method == null ? false : method.getModifiers().contains(Modifier.ABSTRACT); } public int getEvaluatedCount() { - int count = 0; - for (Parameter parameter : getParameters()) { - if (parameter.getSpecification().isSignature()) { - count++; + return evaluatedParameters.size(); + } + + public boolean canDelegateTo(NodeData node, ExecutableTypeData to) { + ExecutableTypeData from = this; + if (to.getEvaluatedCount() < from.getEvaluatedCount()) { + return false; + } + + ProcessorContext context = node.getContext(); + + // we cannot delegate from generic to unexpected + if (!from.hasUnexpectedValue(context) && to.hasUnexpectedValue(context)) { + return false; + } + + // we can skip the return type check for void. everything is assignable to void. + if (!isVoid(from.getReturnType())) { + if (!isSubtypeBoxed(context, from.getReturnType(), to.getReturnType()) && !isSubtypeBoxed(context, to.getReturnType(), from.getReturnType())) { + return false; + } + } + if (from.getFrameParameter() != to.getFrameParameter() && from.getFrameParameter() != null && to.getFrameParameter() != null && + !isSubtypeBoxed(context, from.getFrameParameter(), to.getFrameParameter())) { + return false; + } + + for (int i = 0; i < from.getEvaluatedCount(); i++) { + if (!isSubtypeBoxed(context, from.getEvaluatedParameters().get(i), to.getEvaluatedParameters().get(i))) { + return false; + } + } + + for (int i = from.getEvaluatedCount(); i < to.getEvaluatedCount(); i++) { + TypeMirror delegateToParameter = to.getEvaluatedParameters().get(i); + if (i < node.getChildExecutions().size()) { + TypeMirror genericType = node.getGenericType(node.getChildExecutions().get(i)); + if (!isSubtypeBoxed(context, genericType, delegateToParameter)) { + return false; + } } } - return count; + + return true; + } + + public int compareTo(ExecutableTypeData o2) { + ExecutableTypeData o1 = this; + ProcessorContext context = ProcessorContext.getInstance(); + + int result = Integer.compare(o2.getEvaluatedCount(), o1.getEvaluatedCount()); + if (result != 0) { + return result; + } + + result = Boolean.compare(o1.hasUnexpectedValue(context), o2.hasUnexpectedValue(context)); + if (result != 0) { + return result; + } + + result = compareType(context, o1.getReturnType(), o2.getReturnType()); + if (result != 0) { + return result; + } + result = compareType(context, o1.getFrameParameter(), o2.getFrameParameter()); + if (result != 0) { + return result; + } + + for (int i = 0; i < o1.getEvaluatedCount(); i++) { + result = compareType(context, o1.getEvaluatedParameters().get(i), o2.getEvaluatedParameters().get(i)); + if (result != 0) { + return result; + } + } + + result = o1.getUniqueName().compareTo(o2.getUniqueName()); + if (result != 0) { + return result; + } + + if (o1.getMethod() != null && o2.getMethod() != null) { + result = ElementUtils.compareMethod(o1.getMethod(), o2.getMethod()); + if (result != 0) { + return result; + } + } + return 0; + } + + public static int compareType(ProcessorContext context, TypeMirror signature1, TypeMirror signature2) { + if (signature1 == null) { + if (signature2 == null) { + return 0; + } + return -1; + } else if (signature2 == null) { + return 1; + } + if (ElementUtils.typeEquals(signature1, signature2)) { + return 0; + } + if (isVoid(signature1)) { + if (isVoid(signature2)) { + return 0; + } + return 1; + } else if (isVoid(signature2)) { + return -1; + } + + TypeMirror boxedType1 = ElementUtils.boxType(context, signature1); + TypeMirror boxedType2 = ElementUtils.boxType(context, signature2); + + if (ElementUtils.isSubtype(boxedType1, boxedType2)) { + if (ElementUtils.isSubtype(boxedType2, boxedType1)) { + return 0; + } + return 1; + } else if (ElementUtils.isSubtype(boxedType2, boxedType1)) { + return -1; + } else { + return ElementUtils.getSimpleName(signature1).compareTo(ElementUtils.getSimpleName(signature2)); + } } @Override - public int hashCode() { - return type.hashCode(); + public String toString() { + return method != null ? ElementUtils.createReferenceName(method) : getUniqueName() + evaluatedParameters.toString(); + } + + public boolean sameParameters(ExecutableTypeData other) { + if (!typeEquals(other.getFrameParameter(), getFrameParameter())) { + return false; + } + + if (getEvaluatedCount() != other.getEvaluatedCount()) { + return false; + } + + for (int i = 0; i < getEvaluatedCount(); i++) { + if (!typeEquals(getEvaluatedParameters().get(i), other.getEvaluatedParameters().get(i))) { + return false; + } + } + return true; } - @Override - public boolean equals(Object obj) { - if (obj instanceof ExecutableTypeData) { - return type.equals(((ExecutableTypeData) obj).type); + public boolean sameSignature(ExecutableTypeData other) { + if (!typeEquals(other.getReturnType(), getReturnType())) { + return false; + } + + if (other.getFrameParameter() != null) { + if (!typeEquals(getFrameParameter(), other.getFrameParameter())) { + return false; + } } - return super.equals(obj); + + if (getEvaluatedCount() != other.getEvaluatedCount()) { + return false; + } + + for (int i = 0; i < getEvaluatedCount(); i++) { + if (!typeEquals(getEvaluatedParameters().get(i), other.getEvaluatedParameters().get(i))) { + return false; + } + } + + return true; } - } diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ImplicitCastData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ImplicitCastData.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ImplicitCastData.java Wed Apr 15 11:03:04 2015 -0700 @@ -22,35 +22,29 @@ */ package com.oracle.truffle.dsl.processor.model; +import javax.lang.model.type.*; + public class ImplicitCastData extends TemplateMethod { - private final TypeData sourceType; - private final TypeData targetType; + private final TypeMirror sourceType; + private final TypeMirror targetType; - public ImplicitCastData(TemplateMethod method, TypeData sourceType, TypeData targetType) { + public ImplicitCastData(TemplateMethod method, TypeMirror sourceType, TypeMirror targetType) { super(method); this.sourceType = sourceType; this.targetType = targetType; } - public TypeData getSourceType() { + public TypeMirror getSourceType() { return sourceType; } - public TypeData getTargetType() { + public TypeMirror getTargetType() { return targetType; } @Override public int compareTo(TemplateMethod o) { - if (o instanceof ImplicitCastData && sourceType != null) { - // implicit casts are ordered by source type since - // its also the order in which they are checked. - TypeData otherSourceType = ((ImplicitCastData) o).getSourceType(); - if (otherSourceType != null) { - return this.sourceType.compareTo(otherSourceType); - } - } return super.compareTo(o); } } diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/MessageContainer.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/MessageContainer.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/MessageContainer.java Wed Apr 15 11:03:04 2015 -0700 @@ -106,7 +106,7 @@ visitedSinks.add(this); List foundMessages = new ArrayList<>(); - if (ElementUtils.typeEquals(getMessageElement().asType(), e.asType())) { + if (getMessageElement() != null && ElementUtils.typeEquals(getMessageElement().asType(), e.asType())) { foundMessages.addAll(getMessages()); } for (MessageContainer sink : findChildContainers()) { @@ -119,14 +119,16 @@ TypeElement expectError = context.getTruffleTypes().getExpectError(); if (expectError != null) { Element element = getMessageElement(); - AnnotationMirror mirror = ElementUtils.findAnnotationMirror(element.getAnnotationMirrors(), expectError.asType()); - if (mirror != null) { - List values = ElementUtils.getAnnotationValueList(String.class, mirror, "value"); - if (values == null) { - values = Collections.emptyList(); - } - if (values.size() != msgs.size()) { - log.message(Kind.ERROR, element, mirror, ElementUtils.getAnnotationValue(mirror, "value"), String.format("Error count expected %s but was %s.", values.size(), msgs.size())); + if (element != null) { + AnnotationMirror mirror = ElementUtils.findAnnotationMirror(element.getAnnotationMirrors(), expectError.asType()); + if (mirror != null) { + List values = ElementUtils.getAnnotationValueList(String.class, mirror, "value"); + if (values == null) { + values = Collections.emptyList(); + } + if (values.size() != msgs.size()) { + log.message(Kind.ERROR, element, mirror, ElementUtils.getAnnotationValue(mirror, "value"), String.format("Error count expected %s but was %s.", values.size(), msgs.size())); + } } } } diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/MethodSpec.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/MethodSpec.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/MethodSpec.java Wed Apr 15 11:03:04 2015 -0700 @@ -103,8 +103,8 @@ int defIndex = 0; for (ParameterSpec spec : getAll()) { - List allowedTypes = spec.getAllowedTypes(); - List types = spec.getAllowedTypes(); + Collection allowedTypes = spec.getAllowedTypes(); + Collection types = spec.getAllowedTypes(); if (types != null && allowedTypes.size() > 1) { TypeDef foundDef = null; for (TypeDef def : typeDefs) { @@ -189,7 +189,7 @@ if (foundTypeDef != null) { builder.append("<" + foundTypeDef.getName() + ">"); } else if (spec.getAllowedTypes().size() >= 1) { - builder.append(ElementUtils.getSimpleName(spec.getAllowedTypes().get(0))); + builder.append(ElementUtils.getSimpleName(spec.getAllowedTypes().iterator().next())); } else { builder.append("void"); } @@ -207,15 +207,15 @@ static final class TypeDef { - private final List types; + private final Collection types; private final String name; - private TypeDef(List types, String name) { + private TypeDef(Collection types, String name) { this.types = types; this.name = name; } - public List getTypes() { + public Collection getTypes() { return types; } diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeChildData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeChildData.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeChildData.java Wed Apr 15 11:03:04 2015 -0700 @@ -74,7 +74,7 @@ this.executeWith = executeWith; } - public ExecutableTypeData findExecutableType(TypeData targetType) { + public ExecutableTypeData findExecutableType(TypeMirror targetType) { return childNode.findExecutableType(targetType, getExecuteWith().size()); } diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeData.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeData.java Wed Apr 15 11:03:04 2015 -0700 @@ -48,7 +48,7 @@ private final List specializations = new ArrayList<>(); private final List shortCircuits = new ArrayList<>(); private final List casts = new ArrayList<>(); - private Map> executableTypes; + private final List executableTypes = new ArrayList<>(); private final NodeExecutionData thisExecution; private final boolean generateFactory; @@ -63,7 +63,7 @@ this.fields = new ArrayList<>(); this.children = new ArrayList<>(); this.childExecutions = new ArrayList<>(); - this.thisExecution = new NodeExecutionData(new NodeChildData(null, null, "this", getNodeType(), getNodeType(), null, Cardinality.ONE), -1, false); + this.thisExecution = new NodeExecutionData(new NodeChildData(null, null, "this", getNodeType(), getNodeType(), null, Cardinality.ONE), -1, -1, false); this.thisExecution.getChild().setNode(this); this.generateFactory = generateFactory; } @@ -105,15 +105,15 @@ return childExecutions; } - public Set findSpecializedTypes(NodeExecutionData execution) { - Set types = new HashSet<>(); + public Set findSpecializedTypes(NodeExecutionData execution) { + Set types = new HashSet<>(); for (SpecializationData specialization : getSpecializations()) { if (!specialization.isSpecialized()) { continue; } List parameters = specialization.findByExecutionData(execution); for (Parameter parameter : parameters) { - TypeData type = parameter.getTypeSystemType(); + TypeMirror type = parameter.getType(); if (type == null) { throw new AssertionError(); } @@ -123,22 +123,19 @@ return types; } - public Collection findSpecializedReturnTypes() { - Set types = new HashSet<>(); + public Collection findSpecializedReturnTypes() { + Set types = new HashSet<>(); for (SpecializationData specialization : getSpecializations()) { if (!specialization.isSpecialized()) { continue; } - types.add(specialization.getReturnType().getTypeSystemType()); + types.add(specialization.getReturnType().getType()); } return types; } public int getSignatureSize() { - if (getSpecializations() != null && !getSpecializations().isEmpty()) { - return getSpecializations().get(0).getSignatureSize(); - } - return 0; + return getChildExecutions().size(); } public boolean isFrameUsedByAnyGuard() { @@ -146,8 +143,18 @@ if (!specialization.isReachable()) { continue; } - if (specialization.isFrameUsed()) { - return true; + Parameter frame = specialization.getFrame(); + if (frame != null) { + for (GuardExpression guard : specialization.getGuards()) { + if (guard.getExpression().findBoundVariableElements().contains(frame.getVariableElement())) { + return true; + } + } + for (CacheExpression cache : specialization.getCaches()) { + if (cache.getExpression().findBoundVariableElements().contains(frame.getVariableElement())) { + return true; + } + } } } return false; @@ -233,7 +240,7 @@ public boolean supportsFrame() { if (executableTypes != null) { for (ExecutableTypeData execType : getExecutableTypes(-1)) { - if (execType.findParameter(TemplateMethod.FRAME_NAME) == null) { + if (execType.getFrameParameter() == null) { return false; } } @@ -258,7 +265,7 @@ } for (NodeExecutionData execution : childExecutions) { - if (execution.getName().equals(childName) && (execution.getIndex() == -1 || execution.getIndex() == index)) { + if (execution.getName().equals(childName) && (execution.getChildIndex() == -1 || execution.getChildIndex() == index)) { return execution; } } @@ -284,17 +291,26 @@ return enclosingNodes; } - public List getAllTemplateMethods() { - List methods = new ArrayList<>(); + public List getAllTemplateMethods() { + List methods = new ArrayList<>(); for (SpecializationData specialization : getSpecializations()) { - methods.add(specialization); + methods.add(specialization.getMethod()); } - methods.addAll(getExecutableTypes()); - methods.addAll(getShortCircuits()); + for (ExecutableTypeData execType : getExecutableTypes()) { + if (execType.getMethod() != null) { + methods.add(execType.getMethod()); + } + } + for (ShortCircuitData shortcircuit : getShortCircuits()) { + methods.add(shortcircuit.getMethod()); + } + if (getCasts() != null) { - methods.addAll(getCasts()); + for (CreateCastData castData : getCasts()) { + methods.add(castData.getMethod()); + } } return methods; @@ -303,13 +319,13 @@ public ExecutableTypeData findAnyGenericExecutableType(ProcessorContext context, int evaluatedCount) { List types = findGenericExecutableTypes(context, evaluatedCount); for (ExecutableTypeData type : types) { - if (type.getType().isGeneric()) { + if (context.isType(type.getReturnType(), Object.class)) { return type; } } for (ExecutableTypeData type : types) { - if (!type.getType().isVoid()) { + if (!context.isType(type.getReturnType(), void.class)) { return type; } } @@ -321,21 +337,16 @@ } public List getExecutableTypes(int evaluatedCount) { - if (executableTypes == null) { - return Collections.emptyList(); - } if (evaluatedCount == -1) { - List typeData = new ArrayList<>(); - for (int currentEvaluationCount : executableTypes.keySet()) { - typeData.addAll(executableTypes.get(currentEvaluationCount)); + return executableTypes; + } else { + List filteredTypes = new ArrayList<>(); + for (ExecutableTypeData type : executableTypes) { + if (type.getEvaluatedCount() == evaluatedCount) { + filteredTypes.add(type); + } } - return typeData; - } else { - List types = executableTypes.get(evaluatedCount); - if (types == null) { - return Collections.emptyList(); - } - return types; + return filteredTypes; } } @@ -349,9 +360,9 @@ return types; } - public ExecutableTypeData findExecutableType(TypeData prmitiveType, int evaluatedCount) { + public ExecutableTypeData findExecutableType(TypeMirror primitiveType, int evaluatedCount) { for (ExecutableTypeData type : getExecutableTypes(evaluatedCount)) { - if (ElementUtils.typeEquals(type.getType().getPrimitiveType(), prmitiveType.getPrimitiveType())) { + if (ElementUtils.typeEquals(type.getReturnType(), primitiveType)) { return type; } } @@ -488,6 +499,25 @@ return specializations; } + public ExecutableTypeData getGenericExecutableType(ExecutableTypeData typeHint) { + ExecutableTypeData polymorphicDelegate = null; + if (typeHint != null) { + polymorphicDelegate = typeHint; + while (polymorphicDelegate.getDelegatedTo() != null && polymorphicDelegate.getEvaluatedCount() != getSignatureSize()) { + polymorphicDelegate = polymorphicDelegate.getDelegatedTo(); + } + } + if (polymorphicDelegate == null) { + for (ExecutableTypeData type : getExecutableTypes()) { + if (type.getDelegatedTo() == null && type.getEvaluatedCount() == getSignatureSize()) { + polymorphicDelegate = type; + break; + } + } + } + return polymorphicDelegate; + } + public List getExecutableTypes() { return getExecutableTypes(-1); } @@ -496,8 +526,12 @@ return shortCircuits; } - public void setExecutableTypes(Map> executableTypes) { - this.executableTypes = executableTypes; + public int getMinimalEvaluatedParameters() { + int minimalEvaluatedParameters = Integer.MAX_VALUE; + for (ExecutableTypeData type : getExecutableTypes()) { + minimalEvaluatedParameters = Math.min(minimalEvaluatedParameters, type.getEvaluatedCount()); + } + return minimalEvaluatedParameters; } @Override @@ -520,4 +554,38 @@ return getNodeId().compareTo(o.getNodeId()); } + public TypeMirror getGenericType(NodeExecutionData execution) { + return ElementUtils.getCommonSuperType(getContext(), getGenericTypes(execution)); + } + + public List getGenericTypes(NodeExecutionData execution) { + List types = new ArrayList<>(); + + // add types possible through return types and evaluated parameters in execute methods + if (execution.getChild() != null) { + for (ExecutableTypeData executable : execution.getChild().getNodeData().getExecutableTypes()) { + if (executable.hasUnexpectedValue(getContext())) { + continue; + } + if (!typeSystem.hasImplicitSourceTypes(executable.getReturnType())) { + types.add(executable.getReturnType()); + } + } + } + + int executionIndex = execution.getIndex(); + if (executionIndex >= 0) { + for (ExecutableTypeData typeData : getExecutableTypes()) { + if (executionIndex < typeData.getEvaluatedCount()) { + TypeMirror genericType = typeData.getEvaluatedParameters().get(executionIndex); + if (!typeSystem.hasImplicitSourceTypes(genericType)) { + types.add(genericType); + } + } + } + } + + return ElementUtils.uniqueSortedTypes(types); + } + } diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeExecutionData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeExecutionData.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeExecutionData.java Wed Apr 15 11:03:04 2015 -0700 @@ -22,6 +22,8 @@ */ package com.oracle.truffle.dsl.processor.model; +import java.util.*; + import javax.lang.model.type.*; import com.oracle.truffle.dsl.processor.model.NodeChildData.Cardinality; @@ -31,17 +33,28 @@ private final NodeChildData child; private final String name; private final int index; + private final int childIndex; private final boolean shortCircuit; + private final List typeRestrictions = new ArrayList<>(); - public NodeExecutionData(NodeChildData child, int index, boolean shortCircuit) { + public NodeExecutionData(NodeChildData child, int index, int childIndex, boolean shortCircuit) { this.child = child; this.index = index; + this.childIndex = childIndex; this.shortCircuit = shortCircuit; this.name = createName(); } private String createName() { - return createName(child.getName(), index); + return child != null ? createName(child.getName(), childIndex) : ("arg" + index); + } + + public int getIndex() { + return index; + } + + public List getTypeRestrictions() { + return typeRestrictions; } public TypeMirror getNodeType() { @@ -62,12 +75,12 @@ return child; } - public int getIndex() { - return index; + public int getChildIndex() { + return childIndex; } public boolean isIndexed() { - return index > -1; + return childIndex > -1; } public boolean isShortCircuit() { @@ -75,7 +88,7 @@ } public String getIndexedName() { - return createIndexedName(child, index); + return createIndexedName(child, childIndex); } public static String createIndexedName(NodeChildData child, int varArgsIndex) { diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/Parameter.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/Parameter.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/Parameter.java Wed Apr 15 11:03:04 2015 -0700 @@ -28,19 +28,17 @@ public final class Parameter { private final ParameterSpec specification; - private TypeData typeSystemType; private TemplateMethod method; private String localName; private final int specificationVarArgsIndex; private final int typeVarArgsIndex; - private final VariableElement variableElement; + private final TypeMirror type; public Parameter(ParameterSpec specification, VariableElement variableElement, int specificationVarArgsIndex, int typeVarArgsIndex) { this.specification = specification; this.variableElement = variableElement; - this.typeSystemType = null; - + this.type = variableElement.asType(); this.specificationVarArgsIndex = specificationVarArgsIndex; String valueName = specification.getName() + "Value"; @@ -51,22 +49,22 @@ this.localName = valueName; } - public Parameter(ParameterSpec specification, TypeData actualType, VariableElement variableElement, int specificationIndex, int varArgsIndex) { - this(specification, variableElement, specificationIndex, varArgsIndex); - this.typeSystemType = actualType; - } - - public Parameter(Parameter parameter, TypeData otherType) { - this(parameter.specification, otherType, parameter.variableElement, parameter.specificationVarArgsIndex, parameter.typeVarArgsIndex); - } - public Parameter(Parameter parameter) { this.specification = parameter.specification; - this.typeSystemType = parameter.typeSystemType; this.specificationVarArgsIndex = parameter.specificationVarArgsIndex; this.localName = parameter.localName; this.typeVarArgsIndex = parameter.typeVarArgsIndex; this.variableElement = parameter.variableElement; + this.type = parameter.type; + } + + public Parameter(Parameter parameter, TypeMirror newType) { + this.specification = parameter.specification; + this.specificationVarArgsIndex = parameter.specificationVarArgsIndex; + this.localName = parameter.localName; + this.typeVarArgsIndex = parameter.typeVarArgsIndex; + this.variableElement = parameter.variableElement; + this.type = newType; } public void setLocalName(String localName) { @@ -102,11 +100,7 @@ } public TypeMirror getType() { - return variableElement.asType(); - } - - public TypeData getTypeSystemType() { - return typeSystemType; + return type; } public boolean isTypeVarArgs() { diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ParameterSpec.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ParameterSpec.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ParameterSpec.java Wed Apr 15 11:03:04 2015 -0700 @@ -27,51 +27,53 @@ import javax.lang.model.element.*; import javax.lang.model.type.*; +import com.oracle.truffle.dsl.processor.*; import com.oracle.truffle.dsl.processor.java.*; import com.oracle.truffle.dsl.processor.model.MethodSpec.TypeDef; public class ParameterSpec { private final String name; - private final List allowedTypes; - private final Set allowedTypesIdentifier; + private final Collection allowedTypes; + private final boolean anyType; /** Type is bound to local final variable. */ private boolean local; private boolean signature; + private boolean allowSubclasses = true; /** Optional bound execution of node. */ private NodeExecutionData execution; private TypeDef typeDefinition; - public ParameterSpec(String name, List allowedTypes, Set typeIdentifiers) { + public ParameterSpec(String name, Collection allowedTypes) { this.name = name; this.allowedTypes = allowedTypes; - this.allowedTypesIdentifier = typeIdentifiers; + boolean anyTypeTemp = false; + for (TypeMirror type : allowedTypes) { + if (ElementUtils.isObject(type)) { + anyTypeTemp = true; + break; + } + } + this.anyType = anyTypeTemp; } - public ParameterSpec(String name, List allowedTypes) { - this.name = name; - this.allowedTypes = allowedTypes; - Set typeIdentifiers = new HashSet<>(); - for (TypeMirror type : allowedTypes) { - typeIdentifiers.add(ElementUtils.getUniqueIdentifier(type)); - } - this.allowedTypesIdentifier = typeIdentifiers; + public ParameterSpec(ParameterSpec original, TypeMirror newType) { + this(original.name, newType); + this.local = original.local; + this.signature = original.signature; + this.execution = original.execution; + this.typeDefinition = original.typeDefinition; + this.allowSubclasses = original.allowSubclasses; } public ParameterSpec(String name, TypeMirror type) { - this(name, Arrays.asList(type), new HashSet<>(Arrays.asList(ElementUtils.getUniqueIdentifier(type)))); + this(name, Arrays.asList(type)); } - public ParameterSpec(ParameterSpec o, List allowedTypes, Set typeIdentifiers) { - this.name = o.name; - this.local = o.local; - this.typeDefinition = o.typeDefinition; - this.execution = o.execution; - this.signature = o.signature; - this.allowedTypes = allowedTypes; - this.allowedTypesIdentifier = typeIdentifiers; + public void setAllowSubclasses(boolean allowSubclasses) { + this.allowSubclasses = allowSubclasses; } public NodeExecutionData getExecution() { @@ -111,15 +113,28 @@ return name; } - public List getAllowedTypes() { + public Collection getAllowedTypes() { return allowedTypes; } public boolean matches(VariableElement variable) { - if (allowedTypesIdentifier != null) { - return allowedTypesIdentifier.contains(ElementUtils.getUniqueIdentifier(variable.asType())); + if (anyType) { + return true; + } else { + for (TypeMirror type : allowedTypes) { + if (ElementUtils.typeEquals(variable.asType(), type)) { + return true; + } + } + if (allowSubclasses) { + for (TypeMirror type : allowedTypes) { + if (ElementUtils.isSubtypeBoxed(ProcessorContext.getInstance(), variable.asType(), type)) { + return true; + } + } + } } - return true; + return false; } @Override @@ -132,7 +147,7 @@ if (typeDefinition != null) { builder.append("<" + typeDefinition.getName() + ">"); } else if (getAllowedTypes().size() >= 1) { - builder.append(ElementUtils.getSimpleName(getAllowedTypes().get(0))); + builder.append(ElementUtils.getSimpleName(getAllowedTypes().iterator().next())); } else { builder.append("void"); } diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/SpecializationData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/SpecializationData.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/SpecializationData.java Wed Apr 15 11:03:04 2015 -0700 @@ -25,6 +25,7 @@ import java.util.*; import javax.lang.model.element.*; +import javax.lang.model.type.*; import com.oracle.truffle.dsl.processor.*; import com.oracle.truffle.dsl.processor.expression.*; @@ -40,7 +41,7 @@ } private final NodeData node; - private final SpecializationKind kind; + private SpecializationKind kind; private final List exceptions; private List guards = Collections.emptyList(); private List caches = Collections.emptyList(); @@ -91,6 +92,10 @@ return false; } + public void setKind(SpecializationKind kind) { + this.kind = kind; + } + public boolean isDynamicParameterBound(DSLExpression expression) { Set boundVariables = expression.findBoundVariableElements(); for (Parameter parameter : getDynamicParameters()) { @@ -201,17 +206,18 @@ for (Parameter parameter : getSignatureParameters()) { NodeChildData child = parameter.getSpecification().getExecution().getChild(); - ExecutableTypeData type = child.findExecutableType(parameter.getTypeSystemType()); - if (type == null) { - type = child.findAnyGenericExecutableType(context); + if (child != null) { + ExecutableTypeData type = child.findExecutableType(parameter.getType()); + if (type == null) { + type = child.findAnyGenericExecutableType(context); + } + if (type.hasUnexpectedValue(context)) { + return true; + } + if (ElementUtils.needsCastTo(type.getReturnType(), parameter.getType())) { + return true; + } } - if (type.hasUnexpectedValue(context)) { - return true; - } - if (type.getReturnType().getTypeSystemType().needsCastTo(parameter.getTypeSystemType())) { - return true; - } - } return false; } @@ -356,11 +362,12 @@ Iterator currentSignature = getSignatureParameters().iterator(); Iterator prevSignature = prev.getSignatureParameters().iterator(); + TypeSystemData typeSystem = prev.getNode().getTypeSystem(); while (currentSignature.hasNext() && prevSignature.hasNext()) { - TypeData currentType = currentSignature.next().getTypeSystemType(); - TypeData prevType = prevSignature.next().getTypeSystemType(); + TypeMirror currentType = currentSignature.next().getType(); + TypeMirror prevType = prevSignature.next().getType(); - if (!currentType.isImplicitSubtypeOf(prevType)) { + if (!typeSystem.isImplicitSubtypeOf(currentType, prevType)) { return true; } } diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TemplateMethod.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TemplateMethod.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TemplateMethod.java Wed Apr 15 11:03:04 2015 -0700 @@ -73,6 +73,18 @@ return findParameter(FRAME_NAME); } + public void removeParameter(Parameter p) { + this.parameters.remove(p); + this.parameterCache.remove(p.getLocalName()); + p.setMethod(this); + } + + public void addParameter(int index, Parameter p) { + this.parameters.add(index, p); + this.parameterCache.put(p.getLocalName(), p); + p.setMethod(this); + } + public String createReferenceName() { if (getMethod() == null) { return "-"; @@ -132,12 +144,13 @@ public void replaceParameter(String localName, Parameter newParameter) { if (returnType.getLocalName().equals(localName)) { returnType = newParameter; - returnType.setMethod(this); } else { Parameter local = findParameter(localName); int index = parameters.indexOf(local); parameters.set(index, newParameter); } + parameterCache.put(newParameter.getLocalName(), newParameter); + newParameter.setMethod(this); } public Iterable getSignatureParameters() { @@ -228,9 +241,9 @@ public TypeSignature getTypeSignature() { TypeSignature signature = new TypeSignature(); - signature.types.add(getReturnType().getTypeSystemType()); + signature.types.add(getReturnType().getType()); for (Parameter parameter : getSignatureParameters()) { - TypeData typeData = parameter.getTypeSystemType(); + TypeMirror typeData = parameter.getType(); if (typeData != null) { signature.types.add(typeData); } @@ -250,8 +263,8 @@ if (signatureIndex >= signature.size()) { break; } - TypeData newType = signature.get(signatureIndex++); - if (!parameter.getTypeSystemType().equals(newType)) { + TypeMirror newType = signature.get(signatureIndex++); + if (!ElementUtils.typeEquals(newType, parameter.getType())) { replaceParameter(parameter.getLocalName(), new Parameter(parameter, newType)); } } @@ -278,11 +291,6 @@ } public int compareBySignature(TemplateMethod compareMethod) { - final TypeSystemData typeSystem = getTemplate().getTypeSystem(); - if (typeSystem != compareMethod.getTemplate().getTypeSystem()) { - throw new IllegalStateException("Cannot compare two methods with different type systems."); - } - List signature1 = getSignatureTypes(this); List signature2 = getSignatureTypes(compareMethod); @@ -290,7 +298,7 @@ for (int i = 0; i < Math.max(signature1.size(), signature2.size()); i++) { TypeMirror t1 = i < signature1.size() ? signature1.get(i) : null; TypeMirror t2 = i < signature2.size() ? signature2.get(i) : null; - result = compareParameter(typeSystem, t1, t2); + result = ElementUtils.compareType(t1, t2); if (result != 0) { break; } @@ -299,37 +307,6 @@ return result; } - protected static int compareParameter(TypeSystemData data, TypeMirror signature1, TypeMirror signature2) { - if (signature1 == null) { - return 1; - } else if (signature2 == null) { - return -1; - } - - if (ElementUtils.typeEquals(signature1, signature2)) { - return 0; - } - - int index1 = data.findType(signature1); - int index2 = data.findType(signature2); - if (index1 != -1 && index2 != -1) { - return index1 - index2; - } - - // TODO this version if subclass of should be improved. - if (signature1.getKind() == TypeKind.DECLARED && signature2.getKind() == TypeKind.DECLARED) { - TypeElement element1 = ElementUtils.fromTypeMirror(signature1); - TypeElement element2 = ElementUtils.fromTypeMirror(signature2); - - if (ElementUtils.getDirectSuperTypes(element1).contains(element2)) { - return -1; - } else if (ElementUtils.getDirectSuperTypes(element2).contains(element1)) { - return 1; - } - } - return ElementUtils.getSimpleName(signature1).compareTo(ElementUtils.getSimpleName(signature2)); - } - public static List getSignatureTypes(TemplateMethod method) { List types = new ArrayList<>(); for (Parameter param : method.getSignatureParameters()) { @@ -338,15 +315,15 @@ return types; } - public static class TypeSignature implements Iterable, Comparable { + public static class TypeSignature implements Iterable { - private final List types; + private final List types; public TypeSignature() { this.types = new ArrayList<>(); } - public TypeSignature(List signature) { + public TypeSignature(List signature) { this.types = signature; } @@ -359,32 +336,10 @@ return types.size(); } - public TypeData get(int index) { + public TypeMirror get(int index) { return types.get(index); } - public int compareTo(TypeSignature other) { - if (this == other) { - return 0; - } else if (types.size() != other.types.size()) { - return types.size() - other.types.size(); - } else if (types.isEmpty()) { - return 0; - } - - for (int i = 0; i < types.size(); i++) { - TypeData type1 = types.get(i); - TypeData type2 = other.types.get(i); - - int comparison = type1.compareTo(type2); - if (comparison != 0) { - return comparison; - } - } - - return 0; - } - @Override public boolean equals(Object obj) { if (obj instanceof TypeSignature) { @@ -393,7 +348,7 @@ return super.equals(obj); } - public Iterator iterator() { + public Iterator iterator() { return types.iterator(); } diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TypeCastData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TypeCastData.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TypeCastData.java Wed Apr 15 11:03:04 2015 -0700 @@ -22,26 +22,24 @@ */ package com.oracle.truffle.dsl.processor.model; +import javax.lang.model.type.*; + public class TypeCastData extends TemplateMethod { - private final TypeData targetType; - private final TypeData sourceType; + private final TypeMirror targetType; + private final TypeMirror sourceType; - public TypeCastData(TemplateMethod method, TypeData sourceType, TypeData targetType) { + public TypeCastData(TemplateMethod method, TypeMirror sourceType, TypeMirror targetType) { super(method); this.sourceType = sourceType; this.targetType = targetType; } - public boolean isGeneric() { - return sourceType.isGeneric(); - } - - public TypeData getSourceType() { + public TypeMirror getSourceType() { return sourceType; } - public TypeData getTargetType() { + public TypeMirror getTargetType() { return targetType; } } diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TypeCheckData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TypeCheckData.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TypeCheckData.java Wed Apr 15 11:03:04 2015 -0700 @@ -22,26 +22,24 @@ */ package com.oracle.truffle.dsl.processor.model; +import javax.lang.model.type.*; + public class TypeCheckData extends TemplateMethod { - private final TypeData checkedType; - private final TypeData valueType; + private final TypeMirror checkedType; + private final TypeMirror valueType; - public TypeCheckData(TemplateMethod method, TypeData checkedType, TypeData valueType) { + public TypeCheckData(TemplateMethod method, TypeMirror checkedType, TypeMirror valueType) { super(method); this.checkedType = checkedType; this.valueType = valueType; } - public boolean isGeneric() { - return valueType.isGeneric(); - } - - public TypeData getCheckedType() { + public TypeMirror getCheckedType() { return checkedType; } - public TypeData getValueType() { + public TypeMirror getValueType() { return valueType; } diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TypeData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TypeData.java Wed Apr 15 10:09:13 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,181 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.dsl.processor.model; - -import java.util.*; - -import javax.lang.model.element.*; -import javax.lang.model.type.*; - -import com.oracle.truffle.dsl.processor.java.*; - -public class TypeData extends MessageContainer implements Comparable { - - private final TypeSystemData typeSystem; - private final AnnotationValue annotationValue; - private final TypeMirror primitiveType; - private final TypeMirror boxedType; - - private final int index; - private final List typeCasts = new ArrayList<>(); - private final List typeChecks = new ArrayList<>(); - - public TypeData(TypeSystemData typeSystem, int index, AnnotationValue value, TypeMirror primitiveType, TypeMirror boxedType) { - this.index = index; - this.typeSystem = typeSystem; - this.annotationValue = value; - this.primitiveType = primitiveType; - this.boxedType = boxedType; - } - - public int getIndex() { - return index; - } - - public boolean isDefaultCast() { - return getTypeCasts().isEmpty(); - } - - public boolean isDefaultCheck() { - return getTypeChecks().isEmpty(); - } - - @Override - public Element getMessageElement() { - return typeSystem.getMessageElement(); - } - - @Override - public AnnotationMirror getMessageAnnotation() { - return typeSystem.getMessageAnnotation(); - } - - @Override - public AnnotationValue getMessageAnnotationValue() { - return annotationValue; - } - - public void addTypeCast(TypeCastData typeCast) { - this.typeCasts.add(typeCast); - } - - public void addTypeCheck(TypeCheckData typeCheck) { - this.typeChecks.add(typeCheck); - } - - public List getTypeCasts() { - return typeCasts; - } - - public List getTypeChecks() { - return typeChecks; - } - - public TypeSystemData getTypeSystem() { - return typeSystem; - } - - public TypeMirror getPrimitiveType() { - return primitiveType; - } - - public TypeMirror getBoxedType() { - return boxedType; - } - - public boolean isGeneric() { - return ElementUtils.typeEquals(boxedType, getTypeSystem().getGenericType()); - } - - public boolean isVoid() { - if (getTypeSystem().getVoidType() == null) { - return false; - } - return ElementUtils.typeEquals(boxedType, getTypeSystem().getVoidType().getBoxedType()); - } - - public int compareTo(TypeData o) { - if (this.equals(o)) { - return 0; - } - return index - o.index; - } - - @Override - public int hashCode() { - return Objects.hash(index, primitiveType); - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof TypeData)) { - return false; - } - TypeData otherType = (TypeData) obj; - return index == otherType.index && ElementUtils.typeEquals(primitiveType, otherType.primitiveType); - } - - @Override - public String toString() { - return getClass().getSimpleName() + "[" + ElementUtils.getSimpleName(primitiveType) + "]"; - } - - public boolean equalsType(TypeData actualTypeData) { - return ElementUtils.typeEquals(boxedType, actualTypeData.boxedType); - } - - public boolean needsCastTo(TypeData targetType) { - return ElementUtils.needsCastTo(getPrimitiveType(), targetType.getPrimitiveType()); - } - - public boolean needsCastTo(TypeMirror targetType) { - return ElementUtils.needsCastTo(getPrimitiveType(), targetType); - } - - public boolean isPrimitive() { - return ElementUtils.isPrimitive(getPrimitiveType()); - } - - public List getImplicitSourceTypes() { - return getTypeSystem().lookupSourceTypes(this); - } - - public boolean hasImplicitSourceTypes() { - return getTypeSystem().hasImplicitSourceTypes(this); - } - - public boolean isImplicitSubtypeOf(TypeData other) { - List casts = other.getTypeSystem().lookupByTargetType(other); - for (ImplicitCastData cast : casts) { - if (isSubtypeOf(cast.getSourceType())) { - return true; - } - } - return isSubtypeOf(other); - } - - public boolean isSubtypeOf(TypeData other) { - return ElementUtils.isSubtype(boxedType, other.boxedType); - } - -} diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TypeSystemData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TypeSystemData.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TypeSystemData.java Wed Apr 15 11:03:04 2015 -0700 @@ -33,24 +33,24 @@ public class TypeSystemData extends Template { - private List types; - private List primitiveTypeMirrors = new ArrayList<>(); - private List boxedTypeMirrors = new ArrayList<>(); - private Map cachedTypes = new HashMap<>(); + private final List implicitCasts = new ArrayList<>(); + private final List casts = new ArrayList<>(); + private final List checks = new ArrayList<>(); + private final List legacyTypes = new ArrayList<>(); - private List implicitCasts; - private List casts; - private List checks; + private Set legacyTypeIds; - private TypeMirror genericType; - private TypeData booleanType; - private TypeData voidType; + private final boolean isDefault; + private final DSLOptions options; - private DSLOptions options; - - public TypeSystemData(ProcessorContext context, TypeElement templateType, AnnotationMirror annotation, DSLOptions options) { + public TypeSystemData(ProcessorContext context, TypeElement templateType, AnnotationMirror annotation, DSLOptions options, boolean isDefault) { super(context, templateType, annotation); this.options = options; + this.isDefault = isDefault; + } + + public boolean isDefault() { + return isDefault; } public DSLOptions getOptions() { @@ -62,48 +62,43 @@ return this; } - public void setTypes(List types) { - this.types = types; - if (types != null) { - for (TypeData typeData : types) { - primitiveTypeMirrors.add(typeData.getPrimitiveType()); - boxedTypeMirrors.add(typeData.getBoxedType()); - cachedTypes.put(ElementUtils.getUniqueIdentifier(typeData.getPrimitiveType()), typeData); - cachedTypes.put(ElementUtils.getUniqueIdentifier(typeData.getBoxedType()), typeData); + public List getLegacyTypes() { + return legacyTypes; + } + + public TypeCastData getCast(TypeMirror targetType) { + for (TypeCastData cast : casts) { + if (ElementUtils.typeEquals(cast.getTargetType(), targetType)) { + return cast; } } + return null; } - public void setImplicitCasts(List implicitCasts) { - this.implicitCasts = implicitCasts; + public TypeCheckData getCheck(TypeMirror type) { + for (TypeCheckData check : checks) { + if (ElementUtils.typeEquals(check.getCheckedType(), type)) { + return check; + } + } + return null; } public List getImplicitCasts() { return implicitCasts; } - public void setCasts(List casts) { - this.casts = casts; + public List getCasts() { + return casts; } - public void setChecks(List checks) { - this.checks = checks; - } - - public void setGenericType(TypeMirror genericType) { - this.genericType = genericType; - } - - public void setVoidType(TypeData voidType) { - this.voidType = voidType; + public List getChecks() { + return checks; } @Override protected List findChildContainers() { List sinks = new ArrayList<>(); - if (types != null) { - sinks.addAll(types); - } if (checks != null) { sinks.addAll(checks); } @@ -116,75 +111,25 @@ return sinks; } - public TypeData getVoidType() { - return voidType; - } - - public List getBoxedTypeMirrors() { - return boxedTypeMirrors; - } - - public List getPrimitiveTypeMirrors() { - return primitiveTypeMirrors; - } - - public Set getTypeIdentifiers() { - return cachedTypes.keySet(); - } - - public List getTypes() { - return types; - } - - public TypeMirror getGenericType() { - return genericType; + @Override + public String toString() { + return getClass().getSimpleName() + "[template = " + ElementUtils.getSimpleName(getTemplateType()) + "]"; } - public TypeData getGenericTypeData() { - TypeData result = types.get(types.size() - 2); - assert result.getBoxedType() == genericType; - return result; - } - - public TypeData findTypeData(TypeMirror type) { - if (ElementUtils.typeEquals(voidType.getPrimitiveType(), type)) { - return voidType; - } - - int index = findType(type); - if (index == -1) { - return null; - } - return types.get(index); - } - - public int findType(TypeMirror type) { - TypeData data = cachedTypes.get(ElementUtils.getUniqueIdentifier(type)); - if (data != null) { - return data.getIndex(); - } - return -1; - } - - @Override - public String toString() { - return getClass().getSimpleName() + "[template = " + ElementUtils.getSimpleName(getTemplateType()) + ", types = " + types + "]"; - } - - public List lookupByTargetType(TypeData targetType) { + public List lookupByTargetType(TypeMirror targetType) { if (getImplicitCasts() == null) { return Collections.emptyList(); } List foundCasts = new ArrayList<>(); for (ImplicitCastData cast : getImplicitCasts()) { - if (cast.getTargetType().equals(targetType)) { + if (ElementUtils.typeEquals(cast.getTargetType(), targetType)) { foundCasts.add(cast); } } return foundCasts; } - public ImplicitCastData lookupCast(TypeData sourceType, TypeData targetType) { + public ImplicitCastData lookupCast(TypeMirror sourceType, TypeMirror targetType) { if (getImplicitCasts() == null) { return null; } @@ -196,38 +141,59 @@ return null; } - public boolean hasImplicitSourceTypes(TypeData targetType) { + public boolean hasImplicitSourceTypes(TypeMirror targetType) { if (getImplicitCasts() == null) { return false; } for (ImplicitCastData cast : getImplicitCasts()) { - if (cast.getTargetType() == targetType) { + if (ElementUtils.typeEquals(cast.getTargetType(), targetType)) { return true; } } return false; } - public List lookupSourceTypes(TypeData type) { - List sourceTypes = new ArrayList<>(); - sourceTypes.add(type); - if (getImplicitCasts() != null) { - for (ImplicitCastData cast : getImplicitCasts()) { - if (cast.getTargetType() == type) { - sourceTypes.add(cast.getSourceType()); - } + public List lookupTargetTypes() { + List sourceTypes = new ArrayList<>(); + for (ImplicitCastData cast : getImplicitCasts()) { + sourceTypes.add(cast.getTargetType()); + } + return ElementUtils.uniqueSortedTypes(sourceTypes); + } + + public List lookupSourceTypes(TypeMirror targetType) { + List sourceTypes = new ArrayList<>(); + sourceTypes.add(targetType); + for (ImplicitCastData cast : getImplicitCasts()) { + if (ElementUtils.typeEquals(cast.getTargetType(), targetType)) { + sourceTypes.add(cast.getSourceType()); } } - Collections.sort(sourceTypes); return sourceTypes; } - public TypeData getBooleanType() { - return booleanType; + public boolean isImplicitSubtypeOf(TypeMirror source, TypeMirror target) { + List targetCasts = lookupByTargetType(target); + for (ImplicitCastData cast : targetCasts) { + if (ElementUtils.isSubtype(boxType(source), boxType(cast.getSourceType()))) { + return true; + } + } + return ElementUtils.isSubtype(boxType(source), boxType(target)); } - public void setBooleanType(TypeData booleanType) { - this.booleanType = booleanType; + public TypeMirror boxType(TypeMirror type) { + return ElementUtils.boxType(getContext(), type); + } + + public boolean hasType(TypeMirror type) { + if (legacyTypeIds == null) { + legacyTypeIds = new HashSet<>(); + for (TypeMirror legacyType : legacyTypes) { + legacyTypeIds.add(ElementUtils.getTypeId(legacyType)); + } + } + return legacyTypeIds.contains(ElementUtils.getTypeId(type)); } } diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/CreateCastParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/CreateCastParser.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/CreateCastParser.java Wed Apr 15 11:03:04 2015 -0700 @@ -59,7 +59,7 @@ baseType = foundChild.getOriginalType(); } - MethodSpec spec = new MethodSpec(new InheritsParameterSpec("child", baseType)); + MethodSpec spec = new MethodSpec(new ParameterSpec("child", baseType)); addDefaultFieldMethodSpec(spec); ParameterSpec childSpec = new ParameterSpec("castedChild", baseType); childSpec.setSignature(true); @@ -96,22 +96,4 @@ return cast; } - private static class InheritsParameterSpec extends ParameterSpec { - - public InheritsParameterSpec(String name, TypeMirror... allowedTypes) { - super(name, Arrays.asList(allowedTypes), null); - } - - @Override - public boolean matches(VariableElement variable) { - boolean found = false; - for (TypeMirror specType : getAllowedTypes()) { - if (ElementUtils.isAssignable(variable.asType(), specType)) { - found = true; - break; - } - } - return found; - } - } } diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/ExecutableTypeMethodParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/ExecutableTypeMethodParser.java Wed Apr 15 10:09:13 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,122 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.dsl.processor.parser; - -import java.lang.annotation.*; -import java.util.*; - -import javax.lang.model.element.*; -import javax.lang.model.type.*; - -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.dsl.processor.*; -import com.oracle.truffle.dsl.processor.java.*; -import com.oracle.truffle.dsl.processor.model.*; - -public class ExecutableTypeMethodParser extends NodeMethodParser { - - private final List frameTypes; - private final NodeChildData child; - - public ExecutableTypeMethodParser(ProcessorContext context, NodeData node, NodeChildData child, List frameTypes) { - super(context, node); - this.child = child; - this.frameTypes = frameTypes; - setParseNullOnError(false); - getParser().setEmitErrors(false); - getParser().setUseVarArgs(true); - } - - @Override - public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { - MethodSpec spec = createDefaultMethodSpec(method, mirror, false, null); - List requiredSpecs = new ArrayList<>(spec.getRequired()); - spec.getRequired().clear(); - - TypeSystemData typeSystem = getNode().getTypeSystem(); - List allowedTypes = typeSystem.getPrimitiveTypeMirrors(); - Set allowedIdentifiers = typeSystem.getTypeIdentifiers(); - - if (child != null) { - for (NodeExecutionData executeWith : child.getExecuteWith()) { - ParameterSpec parameter = spec.addRequired(new ParameterSpec(executeWith.getName(), allowedTypes, allowedIdentifiers)); - parameter.setExecution(executeWith); - parameter.setSignature(true); - } - } else { - for (ParameterSpec originalSpec : requiredSpecs) { - spec.addRequired(new ParameterSpec(originalSpec, allowedTypes, allowedIdentifiers)); - } - } - - spec.setIgnoreAdditionalSpecifications(true); - spec.setIgnoreAdditionalParameters(true); - spec.setVariableRequiredParameters(true); - // varargs - ParameterSpec otherParameters = new ParameterSpec("other", allowedTypes, allowedIdentifiers); - otherParameters.setSignature(true); - spec.addRequired(otherParameters); - return spec; - } - - @Override - protected void addDefaultFrame(MethodSpec methodSpec) { - methodSpec.addOptional(new ParameterSpec("frame", frameTypes)); - } - - @Override - protected List nodeTypeMirrors(NodeData nodeData) { - return getNode().getTypeSystem().getPrimitiveTypeMirrors(); - } - - @Override - protected Set nodeTypeIdentifiers(NodeData nodeData) { - return getNode().getTypeSystem().getTypeIdentifiers(); - } - - @Override - public final boolean isParsable(ExecutableElement method) { - if (method.getModifiers().contains(Modifier.STATIC)) { - return false; - } else if (method.getModifiers().contains(Modifier.NATIVE)) { - return false; - } else if (ElementUtils.findAnnotationMirror(getContext().getEnvironment(), method, Specialization.class) != null) { - return false; - } else if (method.getModifiers().contains(Modifier.PRIVATE)) { - return false; - } - return method.getSimpleName().toString().startsWith("execute"); - } - - @Override - public ExecutableTypeData create(TemplateMethod method, boolean invalid) { - TypeData resolvedType = method.getReturnType().getTypeSystemType(); - return new ExecutableTypeData(method, method.getMethod(), getNode().getTypeSystem(), resolvedType); - } - - @Override - public Class getAnnotationType() { - return null; - } - -} diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/FallbackParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/FallbackParser.java Wed Apr 15 11:03:04 2015 -0700 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.dsl.processor.parser; + +import java.lang.annotation.*; + +import javax.lang.model.element.*; + +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.dsl.processor.*; +import com.oracle.truffle.dsl.processor.model.*; +import com.oracle.truffle.dsl.processor.model.SpecializationData.SpecializationKind; + +public class FallbackParser extends NodeMethodParser { + + public FallbackParser(ProcessorContext context, NodeData node) { + super(context, node); + } + + @Override + public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { + return createDefaultMethodSpec(method, mirror, true, null); + } + + @Override + protected ParameterSpec createValueParameterSpec(NodeExecutionData execution) { + ParameterSpec parameterSpec = super.createValueParameterSpec(execution); + parameterSpec.setAllowSubclasses(false); + return parameterSpec; + } + + @Override + public SpecializationData create(TemplateMethod method, boolean invalid) { + return new SpecializationData(getNode(), method, SpecializationKind.FALLBACK); + } + + @Override + public Class getAnnotationType() { + return Fallback.class; + } + +} diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/GenericParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/GenericParser.java Wed Apr 15 10:09:13 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.dsl.processor.parser; - -import java.lang.annotation.*; -import java.util.*; - -import javax.lang.model.element.*; -import javax.lang.model.type.*; - -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.dsl.processor.*; -import com.oracle.truffle.dsl.processor.java.*; -import com.oracle.truffle.dsl.processor.model.*; -import com.oracle.truffle.dsl.processor.model.SpecializationData.SpecializationKind; - -public class GenericParser extends NodeMethodParser { - - public GenericParser(ProcessorContext context, NodeData node) { - super(context, node); - } - - @Override - public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { - return createDefaultMethodSpec(method, mirror, true, null); - } - - @Override - protected ParameterSpec createValueParameterSpec(NodeExecutionData execution) { - List execTypes = execution.getChild().findGenericExecutableTypes(getContext()); - List types = new ArrayList<>(); - Set typeIds = new HashSet<>(); - for (ExecutableTypeData type : execTypes) { - TypeMirror typeMirror = type.getType().getPrimitiveType(); - types.add(typeMirror); - typeIds.add(ElementUtils.getUniqueIdentifier(typeMirror)); - } - ParameterSpec spec = new ParameterSpec(execution.getName(), types, typeIds); - spec.setExecution(execution); - return spec; - } - - @Override - public SpecializationData create(TemplateMethod method, boolean invalid) { - return new SpecializationData(getNode(), method, SpecializationKind.FALLBACK); - } - - @Override - public Class getAnnotationType() { - return Fallback.class; - } - -} diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/ImplicitCastParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/ImplicitCastParser.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/ImplicitCastParser.java Wed Apr 15 11:03:04 2015 -0700 @@ -23,13 +23,13 @@ package com.oracle.truffle.dsl.processor.parser; import java.lang.annotation.*; -import java.util.*; import javax.lang.model.element.*; import javax.lang.model.type.*; import com.oracle.truffle.api.dsl.*; import com.oracle.truffle.dsl.processor.*; +import com.oracle.truffle.dsl.processor.java.*; import com.oracle.truffle.dsl.processor.model.*; public class ImplicitCastParser extends TypeSystemMethodParser { @@ -45,10 +45,8 @@ @Override public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { - List types = getTypeSystem().getPrimitiveTypeMirrors(); - Set identifiers = getTypeSystem().getTypeIdentifiers(); - MethodSpec spec = new MethodSpec(new ParameterSpec("target", types, identifiers)); - spec.addRequired(new ParameterSpec("source", types, identifiers)).setSignature(true); + MethodSpec spec = new MethodSpec(new ParameterSpec("target", getContext().getType(Object.class))); + spec.addRequired(new ParameterSpec("source", getContext().getType(Object.class))).setSignature(true); return spec; } @@ -61,10 +59,10 @@ Parameter target = method.findParameter("targetValue"); Parameter source = method.findParameter("sourceValue"); - TypeData targetType = target.getTypeSystemType(); - TypeData sourceType = source.getTypeSystemType(); + TypeMirror targetType = target.getType(); + TypeMirror sourceType = source.getType(); - if (targetType.equals(sourceType)) { + if (ElementUtils.typeEquals(targetType, sourceType)) { method.addError("Target type and source type of an @%s must not be the same type.", ImplicitCast.class.getSimpleName()); } diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/MethodSpecParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/MethodSpecParser.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/MethodSpecParser.java Wed Apr 15 11:03:04 2015 -0700 @@ -48,10 +48,6 @@ return template; } - public TypeSystemData getTypeSystem() { - return template.getTypeSystem(); - } - public boolean isEmitErrors() { return emitErrors; } @@ -85,7 +81,7 @@ ParameterSpec returnTypeSpec = methodSpecification.getReturnType(); Parameter returnTypeMirror = matchParameter(returnTypeSpec, new CodeVariableElement(returnType, "returnType"), -1, -1); if (returnTypeMirror == null) { - if (emitErrors) { + if (isEmitErrors() && method != null) { TemplateMethod invalidMethod = new TemplateMethod(id, naturalOrder, template, methodSpecification, method, annotation, returnTypeMirror, Collections. emptyList()); String expectedReturnType = returnTypeSpec.toSignatureString(true); String actualReturnType = ElementUtils.getSimpleName(returnType); @@ -135,7 +131,7 @@ * end matching the required arguments, parsing fails. Parameters prior to the parsed required * ones are cut and used to parse the optional parameters. */ - private List parseParameters(MethodSpec spec, List parameterTypes, boolean varArgs) { + private static List parseParameters(MethodSpec spec, List parameterTypes, boolean varArgs) { List parsedRequired = null; int offset = 0; for (; offset <= parameterTypes.size(); offset++) { @@ -166,7 +162,7 @@ return finalParameters; } - private List parseParametersOptional(MethodSpec spec, List types) { + private static List parseParametersOptional(MethodSpec spec, List types) { List parsedParams = new ArrayList<>(); int typeStartIndex = 0; @@ -191,7 +187,7 @@ return parsedParams; } - private List parseParametersRequired(MethodSpec spec, List types, boolean typeVarArgs) { + private static List parseParametersRequired(MethodSpec spec, List types, boolean typeVarArgs) { List parsedParams = new ArrayList<>(); List specifications = spec.getRequired(); boolean specVarArgs = spec.isVariableRequiredParameters(); @@ -248,7 +244,7 @@ return parsedParams; } - private Parameter matchAnnotatedParameter(MethodSpec spec, VariableElement variable) { + private static Parameter matchAnnotatedParameter(MethodSpec spec, VariableElement variable) { for (ParameterSpec parameterSpec : spec.getAnnotations()) { if (parameterSpec.matches(variable)) { Parameter matchedParameter = matchParameter(parameterSpec, variable, -1, -1); @@ -286,7 +282,7 @@ } } - private Parameter matchParameter(ParameterSpec specification, VariableElement variable, int specificationIndex, int varArgsIndex) { + private static Parameter matchParameter(ParameterSpec specification, VariableElement variable, int specificationIndex, int varArgsIndex) { TypeMirror resolvedType = variable.asType(); if (hasError(resolvedType)) { return null; @@ -296,12 +292,6 @@ return null; } - TypeData resolvedTypeData = getTypeSystem().findTypeData(resolvedType); - if (resolvedTypeData != null) { - return new Parameter(specification, resolvedTypeData, variable, specificationIndex, varArgsIndex); - } else { - return new Parameter(specification, variable, specificationIndex, varArgsIndex); - } + return new Parameter(specification, variable, specificationIndex, varArgsIndex); } - } diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeMethodParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeMethodParser.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeMethodParser.java Wed Apr 15 11:03:04 2015 -0700 @@ -42,26 +42,25 @@ } protected ParameterSpec createValueParameterSpec(NodeExecutionData execution) { - NodeData childNode = execution.getChild().getNodeData(); - ParameterSpec spec = new ParameterSpec(execution.getName(), nodeTypeMirrors(childNode), nodeTypeIdentifiers(childNode)); + ParameterSpec spec = new ParameterSpec(execution.getName(), getPossibleParameterTypes(execution)); spec.setExecution(execution); return spec; } - protected List nodeTypeMirrors(NodeData nodeData) { - return nodeData.getTypeSystem().getPrimitiveTypeMirrors(); - } - - protected Set nodeTypeIdentifiers(NodeData nodeData) { - return nodeData.getTypeSystem().getTypeIdentifiers(); + protected Collection getPossibleParameterTypes(NodeExecutionData execution) { + return getNode().getGenericTypes(execution); } protected ParameterSpec createReturnParameterSpec() { - ParameterSpec returnValue = new ParameterSpec("returnValue", nodeTypeMirrors(getNode()), nodeTypeIdentifiers(getNode())); + ParameterSpec returnValue = new ParameterSpec("returnValue", getPossibleReturnTypes()); returnValue.setExecution(getNode().getThisExecution()); return returnValue; } + protected Collection getPossibleReturnTypes() { + return Arrays.asList(getNode().getGenericType(getNode().getThisExecution())); + } + @Override public boolean isParsable(ExecutableElement method) { if (getAnnotationType() != null) { diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java Wed Apr 15 11:03:04 2015 -0700 @@ -32,7 +32,8 @@ import com.oracle.truffle.api.*; import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.dsl.NodeField; +import com.oracle.truffle.api.dsl.internal.*; +import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.dsl.processor.*; import com.oracle.truffle.dsl.processor.expression.*; @@ -43,8 +44,8 @@ import com.oracle.truffle.dsl.processor.model.*; import com.oracle.truffle.dsl.processor.model.NodeChildData.Cardinality; import com.oracle.truffle.dsl.processor.model.SpecializationData.SpecializationKind; -import com.oracle.truffle.dsl.processor.model.TemplateMethod.TypeSignature; +@DSLOptions public class NodeParser extends AbstractParser { public static final List> ANNOTATIONS = Arrays.asList(Fallback.class, TypeSystemReference.class, ShortCircuit.class, Specialization.class, NodeChild.class, @@ -103,8 +104,9 @@ } catch (CompileErrorException e) { throw e; } catch (Throwable e) { - e.addSuppressed(new RuntimeException(String.format("Parsing of Node %s failed.", ElementUtils.getQualifiedName(rootType)), e)); - throw e; + RuntimeException e2 = new RuntimeException(String.format("Parsing of Node %s failed.", ElementUtils.getQualifiedName(rootType))); + e2.addSuppressed(e); + throw e2; } if (node == null && !enclosedNodes.isEmpty()) { node = new NodeData(context, rootType); @@ -145,33 +147,33 @@ node.getFields().addAll(parseFields(lookupTypes, members)); node.getChildren().addAll(parseChildren(lookupTypes, members)); - node.getChildExecutions().addAll(parseExecutions(node.getChildren(), members)); - node.setExecutableTypes(groupExecutableTypes(new ExecutableTypeMethodParser(context, node, null, context.getFrameTypes()).parse(members))); + node.getChildExecutions().addAll(parseExecutions(node.getFields(), node.getChildren(), members)); + node.getExecutableTypes().addAll(parseExecutableTypeData(members, node.getChildExecutions().size(), context.getFrameTypes(), false)); initializeExecutableTypes(node); initializeImportGuards(node, lookupTypes, members); - - if (node.hasErrors()) { - return node; // error sync point - } - initializeChildren(node); if (node.hasErrors()) { return node; // error sync point } + if (node.hasErrors()) { + return node; // error sync point + } + node.getSpecializations().addAll(new SpecializationMethodParser(context, node).parse(members)); - node.getSpecializations().addAll(new GenericParser(context, node).parse(members)); + node.getSpecializations().addAll(new FallbackParser(context, node).parse(members)); node.getCasts().addAll(new CreateCastParser(context, node).parse(members)); node.getShortCircuits().addAll(new ShortCircuitParser(context, node).parse(members)); if (node.hasErrors()) { return node; // error sync point } + initializeSpecializations(members, node); + initializeExecutableTypeHierarchy(node); verifySpecializationSameLength(node); - initializeSpecializations(members, node); initializeShortCircuits(node); // requires specializations and polymorphic specializations verifyVisibilities(node); @@ -182,6 +184,67 @@ return node; } + private static void initializeExecutableTypeHierarchy(NodeData node) { + SpecializationData polymorphic = node.getPolymorphicSpecialization(); + if (polymorphic != null) { + boolean polymorphicSignatureFound = false; + TypeMirror frame = polymorphic.getFrame() != null ? polymorphic.getFrame().getType() : null; + ExecutableTypeData polymorphicType = new ExecutableTypeData(polymorphic.getReturnType().getType(), "execute", frame, TemplateMethod.getSignatureTypes(polymorphic)); + for (ExecutableTypeData type : node.getExecutableTypes()) { + if (polymorphicType.sameSignature(type)) { + polymorphicSignatureFound = true; + break; + } + } + + if (!polymorphicSignatureFound) { + node.getExecutableTypes().add(polymorphicType); + } + } + + List rootTypes = buildExecutableHierarchy(node); + List additionalAbstractRootTypes = new ArrayList<>(); + for (int i = 1; i < rootTypes.size(); i++) { + ExecutableTypeData rootType = rootTypes.get(i); + if (rootType.isAbstract()) { + // cannot implemement root + additionalAbstractRootTypes.add(rootType); + } else { + node.getExecutableTypes().remove(rootType); + } + } + if (!additionalAbstractRootTypes.isEmpty()) { + node.addError("Incompatible abstract execute methods found %s.", rootTypes); + } + + } + + private static List buildExecutableHierarchy(NodeData node) { + List executes = node.getExecutableTypes(); + if (executes.isEmpty()) { + return Collections.emptyList(); + } + List hierarchyExecutes = new ArrayList<>(executes); + Collections.sort(hierarchyExecutes); + ExecutableTypeData parent = hierarchyExecutes.get(0); + ListIterator executesIterator = hierarchyExecutes.listIterator(1); + buildExecutableHierarchy(node, parent, executesIterator); + return hierarchyExecutes; + } + + private static void buildExecutableHierarchy(NodeData node, ExecutableTypeData parent, ListIterator executesIterator) { + while (executesIterator.hasNext()) { + ExecutableTypeData other = executesIterator.next(); + if (other.canDelegateTo(node, parent)) { + parent.addDelegatedFrom(other); + executesIterator.remove(); + } + } + for (int i = 1; i < parent.getDelegatedFrom().size(); i++) { + buildExecutableHierarchy(node, parent.getDelegatedFrom().get(i - 1), parent.getDelegatedFrom().listIterator(i)); + } + } + private List loadMembers(TypeElement templateType) { List members = new ArrayList<>(CompilerFactory.getCompiler(templateType).getAllMembersInDeclarationOrder(context.getEnvironment(), templateType)); @@ -256,20 +319,19 @@ private NodeData parseNodeData(TypeElement templateType, List typeHierarchy) { AnnotationMirror typeSystemMirror = findFirstAnnotation(typeHierarchy, TypeSystemReference.class); - if (typeSystemMirror == null) { - NodeData nodeData = new NodeData(context, templateType); - nodeData.addError("No @%s annotation found in type hierarchy of %s.", TypeSystemReference.class.getSimpleName(), ElementUtils.getQualifiedName(templateType)); - return nodeData; + TypeSystemData typeSystem = null; + if (typeSystemMirror != null) { + TypeMirror typeSystemType = ElementUtils.getAnnotationValue(TypeMirror.class, typeSystemMirror, "value"); + typeSystem = (TypeSystemData) context.getTemplate(typeSystemType, true); + if (typeSystem == null) { + NodeData nodeData = new NodeData(context, templateType); + nodeData.addError("The used type system '%s' is invalid. Fix errors in the type system first.", ElementUtils.getQualifiedName(typeSystemType)); + return nodeData; + } + } else { + // default dummy type system + typeSystem = new TypeSystemData(context, templateType, null, NodeParser.class.getAnnotation(DSLOptions.class), true); } - - TypeMirror typeSystemType = ElementUtils.getAnnotationValue(TypeMirror.class, typeSystemMirror, "value"); - final TypeSystemData typeSystem = (TypeSystemData) context.getTemplate(typeSystemType, true); - if (typeSystem == null) { - NodeData nodeData = new NodeData(context, templateType); - nodeData.addError("The used type system '%s' is invalid. Fix errors in the type system first.", ElementUtils.getQualifiedName(typeSystemType)); - return nodeData; - } - AnnotationMirror nodeInfoMirror = findFirstAnnotation(typeHierarchy, NodeInfo.class); String shortName = null; if (nodeInfoMirror != null) { @@ -406,11 +468,7 @@ return filteredChildren; } - private List parseExecutions(List children, List elements) { - if (children == null) { - return null; - } - + private List parseExecutions(List fields, List children, List elements) { // pre-parse short circuits Set shortCircuits = new HashSet<>(); List methods = ElementFilter.methodsIn(elements); @@ -433,6 +491,13 @@ } } + List nonGetterFields = new ArrayList<>(); + for (NodeFieldData field : fields) { + if (field.getGetter() == null && field.isGenerated()) { + nonGetterFields.add(field); + } + } + TypeMirror cacheAnnotation = context.getType(Cached.class); List frameTypes = context.getFrameTypes(); // pre-parse specializations to find signature size @@ -443,34 +508,40 @@ } int currentArgumentIndex = 0; boolean skipShortCircuit = false; - outer: for (VariableElement var : method.getParameters()) { + parameter: for (VariableElement var : method.getParameters()) { + if (skipShortCircuit) { + skipShortCircuit = false; + continue parameter; + } TypeMirror type = var.asType(); if (currentArgumentIndex == 0) { // skip optionals for (TypeMirror frameType : frameTypes) { if (ElementUtils.typeEquals(type, frameType)) { - continue outer; + continue parameter; + } + } + } + + if (currentArgumentIndex < nonGetterFields.size()) { + for (NodeFieldData field : nonGetterFields) { + if (ElementUtils.typeEquals(var.asType(), field.getType())) { + continue parameter; } } } if (ElementUtils.findAnnotationMirror(var.getAnnotationMirrors(), cacheAnnotation) != null) { - continue outer; + continue parameter; } int childIndex = currentArgumentIndex < children.size() ? currentArgumentIndex : children.size() - 1; - if (childIndex == -1) { - continue; - } - if (!skipShortCircuit) { + if (childIndex != -1) { NodeChildData child = children.get(childIndex); if (shortCircuits.contains(NodeExecutionData.createIndexedName(child, currentArgumentIndex - childIndex))) { skipShortCircuit = true; - continue; } - } else { - skipShortCircuit = false; } currentArgumentIndex++; @@ -480,24 +551,82 @@ List executions = new ArrayList<>(); for (int i = 0; i < maxSignatureSize; i++) { + boolean varArgParameter = false; int childIndex = i; - boolean varArg = false; - if (childIndex >= children.size() - 1) { + if (i >= children.size() - 1) { if (hasVarArgs) { - childIndex = children.size() - 1; - varArg = hasVarArgs; - } else if (childIndex >= children.size()) { - break; + varArgParameter = hasVarArgs; + childIndex = Math.min(i, children.size() - 1); + } else if (i >= children.size()) { + childIndex = -1; } } - int varArgsIndex = varArg ? Math.abs(childIndex - i) : -1; - NodeChildData child = children.get(childIndex); - boolean shortCircuit = shortCircuits.contains(NodeExecutionData.createIndexedName(child, varArgsIndex)); - executions.add(new NodeExecutionData(child, varArgsIndex, shortCircuit)); + int varArgsIndex = -1; + boolean shortCircuit = false; + NodeChildData child = null; + if (childIndex != -1) { + varArgsIndex = varArgParameter ? Math.abs(childIndex - i) : -1; + child = children.get(childIndex); + shortCircuit = shortCircuits.contains(NodeExecutionData.createIndexedName(child, varArgsIndex)); + } + executions.add(new NodeExecutionData(child, i, varArgsIndex, shortCircuit)); } return executions; } + private List parseExecutableTypeData(List elements, int signatureSize, List frameTypes, boolean includeFinals) { + List typeData = new ArrayList<>(); + for (ExecutableElement method : ElementFilter.methodsIn(elements)) { + Set modifiers = method.getModifiers(); + if (modifiers.contains(Modifier.PRIVATE) || modifiers.contains(Modifier.STATIC)) { + continue; + } + if (!includeFinals && modifiers.contains(Modifier.FINAL)) { + continue; + } + + if (!method.getSimpleName().toString().startsWith("execute")) { + continue; + } + if (ElementUtils.findAnnotationMirror(context.getEnvironment(), method, Specialization.class) != null) { + continue; + } + + ExecutableTypeData executableType = new ExecutableTypeData(method, signatureSize, context.getFrameTypes()); + + if (executableType.getFrameParameter() != null) { + boolean supportedType = false; + for (TypeMirror type : frameTypes) { + if (ElementUtils.isAssignable(type, executableType.getFrameParameter())) { + supportedType = true; + break; + } + } + if (!supportedType) { + continue; + } + } + + typeData.add(executableType); + } + + Collections.sort(typeData); + + List names = new ArrayList<>(); + for (ExecutableTypeData type : typeData) { + names.add(type.getUniqueName()); + } + while (renameDuplicateIds(names)) { + // fix point + } + + for (int i = 0; i < typeData.size(); i++) { + typeData.get(i).setUniqueName(names.get(i)); + } + + return typeData; + } + private void initializeExecutableTypes(NodeData node) { List allExecutes = node.getExecutableTypes(); @@ -507,10 +636,10 @@ for (ExecutableTypeData execute : allExecutes) { evaluatedCounts.add(execute.getEvaluatedCount()); - Parameter frame = execute.getFrame(); + TypeMirror frame = execute.getFrameParameter(); TypeMirror resolvedFrameType; if (frame != null) { - resolvedFrameType = frame.getType(); + resolvedFrameType = frame; if (frameType == null) { frameType = resolvedFrameType; } else if (!ElementUtils.typeEquals(frameType, resolvedFrameType)) { @@ -532,70 +661,49 @@ node.setFrameType(frameType); - int totalGenericCount = 0; - int totalVoidCount = 0; - for (Integer evaluatedCount : evaluatedCounts) { - List genericExecutes = node.findGenericExecutableTypes(context, evaluatedCount); - int genericCount = 0; - int voidCount = 0; - for (ExecutableTypeData executableTypeData : genericExecutes) { - if (!executableTypeData.getMethod().getModifiers().contains(Modifier.FINAL)) { - if (ElementUtils.isVoid(executableTypeData.getReturnType().getType())) { - voidCount++; - } else { - genericCount++; - } - } + boolean genericFound = false; + for (ExecutableTypeData type : node.getExecutableTypes()) { + if (!type.hasUnexpectedValue(context)) { + genericFound = true; + break; } - // multiple generic execute - if (evaluatedCount == 0) { - if (voidCount > 1) { - List methodSignatures = new ArrayList<>(); - for (ExecutableTypeData type : genericExecutes) { - if (type.getType().isVoid()) { - methodSignatures.add(type.createReferenceName()); - } - } - node.addWarning("Multiple accessible and overridable generic execute methods found %s. Remove all but one or mark all but one as final.", methodSignatures); - } else if (genericCount > 1) { - List methodSignatures = new ArrayList<>(); - for (ExecutableTypeData type : genericExecutes) { - if (!type.getType().isVoid()) { - methodSignatures.add(type.createReferenceName()); - } - } - node.addWarning("Multiple accessible and overridable generic execute methods found %s. Remove all but one or mark all but one as final.", methodSignatures); - } - } - totalGenericCount += genericCount; - totalVoidCount += voidCount; } // no generic executes - if (totalGenericCount + totalVoidCount == 0) { + if (!genericFound) { node.addError("No accessible and overridable generic execute method found. Generic execute methods usually have the " + "signature 'public abstract {Type} execute(VirtualFrame)' and must not throw any checked exceptions."); } - } - - private static Map> groupExecutableTypes(List executableTypes) { - Map> groupedTypes = new TreeMap<>(); - for (ExecutableTypeData type : executableTypes) { - int evaluatedCount = type.getEvaluatedCount(); - - List types = groupedTypes.get(evaluatedCount); - if (types == null) { - types = new ArrayList<>(); - groupedTypes.put(evaluatedCount, types); + int nodeChildDeclarations = 0; + int nodeChildDeclarationsRequired = 0; + List executions = node.getChildExecutions(); + for (NodeExecutionData execution : executions) { + if (execution.getChild() == null) { + nodeChildDeclarationsRequired = execution.getIndex() + 1; + } else { + nodeChildDeclarations++; } - types.add(type); } - for (List types : groupedTypes.values()) { - Collections.sort(types); + List requireNodeChildDeclarations = new ArrayList<>(); + for (ExecutableTypeData type : allExecutes) { + if (type.getEvaluatedCount() < nodeChildDeclarationsRequired) { + requireNodeChildDeclarations.add(ElementUtils.createReferenceName(type.getMethod())); + } } - return groupedTypes; + + if (!requireNodeChildDeclarations.isEmpty()) { + node.addError("Not enough child node declarations found. Please annotate the node class with addtional @NodeChild annotations or remove all execute methods that do not provide all evaluated values. " + + "The following execute methods do not provide all evaluated values for the expected signature size %s: %s.", executions.size(), requireNodeChildDeclarations); + } + + if (nodeChildDeclarations > 0 && executions.size() == node.getMinimalEvaluatedParameters()) { + for (NodeChildData child : node.getChildren()) { + child.addError("Unnecessary @NodeChild declaration. All evaluated child values are provided as parameters in execute methods."); + } + } + } private void initializeChildren(NodeData node) { @@ -608,10 +716,6 @@ child.setNode(fieldNodeData); if (fieldNodeData == null || fieldNodeData.hasErrors()) { child.addError("Node type '%s' is invalid or not a subclass of Node.", ElementUtils.getQualifiedName(nodeType)); - } else if (!ElementUtils.typeEquals(fieldNodeData.getTypeSystem().getTemplateType().asType(), (node.getTypeSystem().getTemplateType().asType()))) { - child.addError("The @%s of the node and the @%s of the @%s does not match. %s != %s. ", TypeSystem.class.getSimpleName(), TypeSystem.class.getSimpleName(), - NodeChild.class.getSimpleName(), ElementUtils.getSimpleName(node.getTypeSystem().getTemplateType()), - ElementUtils.getSimpleName(fieldNodeData.getTypeSystem().getTemplateType())); } else { List types = child.findGenericExecutableTypes(context); if (types.isEmpty()) { @@ -680,7 +784,11 @@ if (node.hasErrors()) { return node; } - node.setExecutableTypes(groupExecutableTypes(new ExecutableTypeMethodParser(context, node, child, createAllowedChildFrameTypes(parentNode)).parse(members))); + List frameTypes = Collections.emptyList(); + if (parentNode.getFrameType() != null) { + frameTypes = Arrays.asList(parentNode.getFrameType()); + } + node.getExecutableTypes().addAll(parseExecutableTypeData(members, child.getExecuteWith().size(), frameTypes, true)); node.setFrameType(parentNode.getFrameType()); return node; } @@ -1153,19 +1261,19 @@ } private SpecializationData createGenericSpecialization(final NodeData node) { - GenericParser parser = new GenericParser(context, node); + FallbackParser parser = new FallbackParser(context, node); MethodSpec specification = parser.createDefaultMethodSpec(node.getSpecializations().iterator().next().getMethod(), null, true, null); List parameterTypes = new ArrayList<>(); int signatureIndex = 1; for (ParameterSpec spec : specification.getRequired()) { - parameterTypes.add(new CodeVariableElement(createGenericType(spec, node.getSpecializations(), signatureIndex), "arg" + signatureIndex)); + parameterTypes.add(new CodeVariableElement(createGenericType(node, spec), "arg" + signatureIndex)); if (spec.isSignature()) { signatureIndex++; } } - TypeMirror returnType = createGenericType(specification.getReturnType(), node.getSpecializations(), 0); + TypeMirror returnType = createGenericType(node, specification.getReturnType()); SpecializationData generic = parser.create("Generic", TemplateMethod.NO_NATURAL_ORDER, null, null, returnType, parameterTypes); if (generic == null) { throw new RuntimeException("Unable to create generic signature for node " + node.getNodeId() + " with " + parameterTypes + ". Specification " + specification + "."); @@ -1174,41 +1282,22 @@ return generic; } - private TypeMirror createGenericType(ParameterSpec spec, List specializations, int signatureIndex) { + private TypeMirror createGenericType(NodeData node, ParameterSpec spec) { NodeExecutionData execution = spec.getExecution(); + Collection allowedTypes; if (execution == null) { - if (spec.getAllowedTypes().size() == 1) { - return spec.getAllowedTypes().get(0); - } else { - return ElementUtils.getCommonSuperType(context, spec.getAllowedTypes().toArray(new TypeMirror[0])); - } + allowedTypes = spec.getAllowedTypes(); } else { - Set types = new HashSet<>(); - for (SpecializationData specialization : specializations) { - types.add(specialization.getTypeSignature().get(signatureIndex)); - } - - NodeChildData child = execution.getChild(); - TypeData genericType = null; - if (types.size() == 1) { - TypeData singleType = types.iterator().next(); - ExecutableTypeData executable = child.findExecutableType(singleType); - if (executable != null && (signatureIndex == 0 || !executable.hasUnexpectedValue(context))) { - genericType = singleType; - } - } - if (genericType == null) { - ExecutableTypeData type = child.findAnyGenericExecutableType(context); - if (type == null) { - throw new AssertionError("No generic type not yet catched by parser."); - } - genericType = type.getType(); - } - return genericType.getPrimitiveType(); + allowedTypes = Arrays.asList(node.getGenericType(execution)); + } + if (allowedTypes.size() == 1) { + return allowedTypes.iterator().next(); + } else { + return ElementUtils.getCommonSuperType(context, allowedTypes); } } - private static void initializeUninitialized(final NodeData node) { + private void initializeUninitialized(final NodeData node) { SpecializationData generic = node.getGenericSpecialization(); if (generic == null) { return; @@ -1225,7 +1314,7 @@ } } if (types.size() > 1) { - generic.replaceParameter(parameter.getLocalName(), new Parameter(parameter, node.getTypeSystem().getGenericTypeData())); + generic.replaceParameter(parameter.getLocalName(), new Parameter(parameter, context.getType(Object.class))); } } TemplateMethod uninializedMethod = new TemplateMethod("Uninitialized", -1, node, generic.getSpecification(), null, null, generic.getReturnType(), generic.getParameters()); @@ -1241,36 +1330,74 @@ SpecializationData generic = node.getGenericSpecialization(); - List polymorphicSignature = new ArrayList<>(); - List updatePolymorphic = Arrays.asList(); - for (Parameter genericParameter : updatePolymorphic) { - if (!genericParameter.getSpecification().isSignature()) { + List types = new ArrayList<>(); + + Collection frameTypes = new HashSet<>(); + for (SpecializationData specialization : node.getSpecializations()) { + if (specialization.getFrame() != null) { + frameTypes.add(specialization.getFrame().getType()); + } + } + if (!frameTypes.isEmpty()) { + frameTypes = ElementUtils.uniqueSortedTypes(frameTypes); + TypeMirror frameType; + if (frameTypes.size() == 1) { + frameType = frameTypes.iterator().next(); + } else { + frameType = context.getType(Frame.class); + } + types.add(new CodeVariableElement(frameType, TemplateMethod.FRAME_NAME)); + } + + TypeMirror returnType = null; + int index = 0; + for (Parameter genericParameter : generic.getReturnTypeAndParameters()) { + TypeMirror polymorphicType; + if (genericParameter.getLocalName().equals(TemplateMethod.FRAME_NAME)) { continue; } - - Set usedTypes = new HashSet<>(); - for (SpecializationData specialization : node.getSpecializations()) { - if (!specialization.isSpecialized()) { - continue; - } - Parameter parameter = specialization.findParameter(genericParameter.getLocalName()); - if (parameter == null) { - throw new AssertionError("Parameter existed in generic specialization but not in specialized. param = " + genericParameter.getLocalName()); + boolean isReturnParameter = genericParameter == generic.getReturnType(); + if (!genericParameter.getSpecification().isSignature()) { + polymorphicType = genericParameter.getType(); + } else { + Collection usedTypes = new HashSet<>(); + for (SpecializationData specialization : node.getSpecializations()) { + if (specialization.isUninitialized()) { + continue; + } + Parameter parameter = specialization.findParameter(genericParameter.getLocalName()); + if (parameter == specialization.getReturnType() && specialization.isFallback() && specialization.getMethod() == null) { + continue; + } + if (parameter == null) { + throw new AssertionError("Parameter existed in generic specialization but not in specialized. param = " + genericParameter.getLocalName()); + } + usedTypes.add(parameter.getType()); } - usedTypes.add(parameter.getTypeSystemType()); - } + usedTypes = ElementUtils.uniqueSortedTypes(usedTypes); + + if (usedTypes.size() == 1) { + polymorphicType = usedTypes.iterator().next(); - TypeData polymorphicType; - if (usedTypes.size() == 1) { - polymorphicType = usedTypes.iterator().next(); + if (!isReturnParameter && node.getTypeSystem().hasImplicitSourceTypes(polymorphicType)) { + polymorphicType = context.getType(Object.class); + } + } else { + polymorphicType = context.getType(Object.class); + } + } + if (isReturnParameter) { + returnType = polymorphicType; } else { - polymorphicType = node.getTypeSystem().getGenericTypeData(); + types.add(new CodeVariableElement(polymorphicType, "param" + index)); } - polymorphicSignature.add(polymorphicType); + index++; } - SpecializationData polymorphic = new SpecializationData(node, generic, SpecializationKind.POLYMORPHIC); - polymorphic.updateSignature(new TypeSignature(polymorphicSignature)); + SpecializationMethodParser parser = new SpecializationMethodParser(context, node); + + SpecializationData polymorphic = parser.create("Polymorphic", TemplateMethod.NO_NATURAL_ORDER, null, null, returnType, types); + polymorphic.setKind(SpecializationKind.POLYMORPHIC); node.getSpecializations().add(polymorphic); } @@ -1370,7 +1497,7 @@ ExecutableTypeData found = null; List executableElements = execution.getChild().findGenericExecutableTypes(context); for (ExecutableTypeData executable : executableElements) { - if (executable.getType().equalsType(parameter.getTypeSystemType())) { + if (ElementUtils.typeEquals(executable.getReturnType(), parameter.getType())) { found = executable; break; } @@ -1429,8 +1556,8 @@ List elements = new ArrayList<>(originalElements); Set unusedElements = new HashSet<>(elements); - for (TemplateMethod method : nodeData.getAllTemplateMethods()) { - unusedElements.remove(method.getMethod()); + for (ExecutableElement method : nodeData.getAllTemplateMethods()) { + unusedElements.remove(method); } for (NodeFieldData field : nodeData.getFields()) { diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationGroup.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationGroup.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationGroup.java Wed Apr 15 11:03:04 2015 -0700 @@ -24,6 +24,8 @@ import java.util.*; +import javax.lang.model.type.*; + import com.oracle.truffle.dsl.processor.model.*; import com.oracle.truffle.dsl.processor.model.TemplateMethod.TypeSignature; @@ -299,9 +301,9 @@ public static final class TypeGuard { private final int signatureIndex; - private final TypeData type; + private final TypeMirror type; - public TypeGuard(TypeData type, int signatureIndex) { + public TypeGuard(TypeMirror type, int signatureIndex) { this.type = type; this.signatureIndex = signatureIndex; } @@ -338,7 +340,7 @@ return signatureIndex; } - public TypeData getType() { + public TypeMirror getType() { return type; } } diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationMethodParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationMethodParser.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationMethodParser.java Wed Apr 15 11:03:04 2015 -0700 @@ -58,55 +58,59 @@ } private SpecializationData parseSpecialization(TemplateMethod method) { - AnnotationValue rewriteValue = ElementUtils.getAnnotationValue(method.getMarkerAnnotation(), "rewriteOn"); - List exceptionTypes = ElementUtils.getAnnotationValueList(TypeMirror.class, method.getMarkerAnnotation(), "rewriteOn"); List exceptionData = new ArrayList<>(); - List rewriteOnTypes = new ArrayList<>(); - for (TypeMirror exceptionType : exceptionTypes) { - SpecializationThrowsData throwsData = new SpecializationThrowsData(method.getMarkerAnnotation(), rewriteValue, exceptionType); - if (!ElementUtils.canThrowType(method.getMethod().getThrownTypes(), exceptionType)) { - method.addError("A rewriteOn checked exception was specified but not thrown in the method's throws clause. The @%s method must specify a throws clause with the exception type '%s'.", - Specialization.class.getSimpleName(), ElementUtils.getQualifiedName(exceptionType)); + if (method.getMethod() != null) { + AnnotationValue rewriteValue = ElementUtils.getAnnotationValue(method.getMarkerAnnotation(), "rewriteOn"); + List exceptionTypes = ElementUtils.getAnnotationValueList(TypeMirror.class, method.getMarkerAnnotation(), "rewriteOn"); + List rewriteOnTypes = new ArrayList<>(); + for (TypeMirror exceptionType : exceptionTypes) { + SpecializationThrowsData throwsData = new SpecializationThrowsData(method.getMarkerAnnotation(), rewriteValue, exceptionType); + if (!ElementUtils.canThrowType(method.getMethod().getThrownTypes(), exceptionType)) { + method.addError("A rewriteOn checked exception was specified but not thrown in the method's throws clause. The @%s method must specify a throws clause with the exception type '%s'.", + Specialization.class.getSimpleName(), ElementUtils.getQualifiedName(exceptionType)); + } + rewriteOnTypes.add(throwsData.getJavaClass()); + exceptionData.add(throwsData); } - rewriteOnTypes.add(throwsData.getJavaClass()); - exceptionData.add(throwsData); - } - - for (TypeMirror typeMirror : method.getMethod().getThrownTypes()) { - if (!ElementUtils.canThrowType(rewriteOnTypes, typeMirror)) { - method.addError(rewriteValue, - "A checked exception '%s' is thrown but is not specified using the rewriteOn property. Checked exceptions that are not used for rewriting are not handled by the DSL. Use RuntimeExceptions for this purpose instead.", - ElementUtils.getQualifiedName(typeMirror)); - } - } - Collections.sort(exceptionData, new Comparator() { - - @Override - public int compare(SpecializationThrowsData o1, SpecializationThrowsData o2) { - return ElementUtils.compareByTypeHierarchy(o1.getJavaClass(), o2.getJavaClass()); - } - }); - SpecializationData specialization = new SpecializationData(getNode(), method, SpecializationKind.SPECIALIZED, exceptionData); - - String insertBeforeName = ElementUtils.getAnnotationValue(String.class, method.getMarkerAnnotation(), "insertBefore"); - if (!insertBeforeName.equals("")) { - specialization.setInsertBeforeName(insertBeforeName); - } - - List containsDefs = ElementUtils.getAnnotationValueList(String.class, specialization.getMarkerAnnotation(), "contains"); - Set containsNames = specialization.getContainsNames(); - containsNames.clear(); - if (containsDefs != null) { - for (String include : containsDefs) { - if (!containsNames.contains(include)) { - specialization.getContainsNames().add(include); - } else { - AnnotationValue value = ElementUtils.getAnnotationValue(specialization.getMarkerAnnotation(), "contains"); - specialization.addError(value, "Duplicate contains declaration '%s'.", include); + for (TypeMirror typeMirror : method.getMethod().getThrownTypes()) { + if (!ElementUtils.canThrowType(rewriteOnTypes, typeMirror)) { + method.addError(rewriteValue, "A checked exception '%s' is thrown but is not specified using the rewriteOn property. " + + "Checked exceptions that are not used for rewriting are not handled by the DSL. Use RuntimeExceptions for this purpose instead.", + ElementUtils.getQualifiedName(typeMirror)); } } + Collections.sort(exceptionData, new Comparator() { + + @Override + public int compare(SpecializationThrowsData o1, SpecializationThrowsData o2) { + return ElementUtils.compareByTypeHierarchy(o1.getJavaClass(), o2.getJavaClass()); + } + }); + } + SpecializationData specialization = new SpecializationData(getNode(), method, SpecializationKind.SPECIALIZED, exceptionData); + + if (method.getMethod() != null) { + String insertBeforeName = ElementUtils.getAnnotationValue(String.class, method.getMarkerAnnotation(), "insertBefore"); + if (!insertBeforeName.equals("")) { + specialization.setInsertBeforeName(insertBeforeName); + } + + List containsDefs = ElementUtils.getAnnotationValueList(String.class, specialization.getMarkerAnnotation(), "contains"); + Set containsNames = specialization.getContainsNames(); + containsNames.clear(); + if (containsDefs != null) { + for (String include : containsDefs) { + if (!containsNames.contains(include)) { + specialization.getContainsNames().add(include); + } else { + AnnotationValue value = ElementUtils.getAnnotationValue(specialization.getMarkerAnnotation(), "contains"); + specialization.addError(value, "Duplicate contains declaration '%s'.", include); + } + } + + } } return specialization; diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeCastParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeCastParser.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeCastParser.java Wed Apr 15 11:03:04 2015 -0700 @@ -41,15 +41,17 @@ @Override public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { TypeMirror targetTypeMirror = ElementUtils.getAnnotationValue(TypeMirror.class, mirror, "value"); - MethodSpec spec = new MethodSpec(new ParameterSpec("returnType", targetTypeMirror)); - spec.addRequired(new ParameterSpec("value", getTypeSystem().getGenericType())); + ParameterSpec returnTypeSpec = new ParameterSpec("returnType", targetTypeMirror); + returnTypeSpec.setAllowSubclasses(false); + MethodSpec spec = new MethodSpec(returnTypeSpec); + spec.addRequired(new ParameterSpec("value", getContext().getType(Object.class))); return spec; } @Override public TypeCastData create(TemplateMethod method, boolean invalid) { - TypeData targetType = resolveCastOrCheck(method); - TypeData sourceType = getTypeSystem().getGenericTypeData(); + TypeMirror targetType = resolveCastOrCheck(method); + TypeMirror sourceType = getContext().getType(Object.class); return new TypeCastData(method, sourceType, targetType); } diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeCheckParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeCheckParser.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeCheckParser.java Wed Apr 15 11:03:04 2015 -0700 @@ -25,6 +25,7 @@ import java.lang.annotation.*; import javax.lang.model.element.*; +import javax.lang.model.type.*; import com.oracle.truffle.api.dsl.*; import com.oracle.truffle.dsl.processor.*; @@ -39,13 +40,13 @@ @Override public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { MethodSpec spec = new MethodSpec(new ParameterSpec("returnType", getContext().getType(boolean.class))); - spec.addRequired(new ParameterSpec("value", getTypeSystem().getGenericType())); + spec.addRequired(new ParameterSpec("value", getContext().getType(Object.class))); return spec; } @Override public TypeCheckData create(TemplateMethod method, boolean invalid) { - TypeData targetType = resolveCastOrCheck(method); + TypeMirror targetType = resolveCastOrCheck(method); return new TypeCheckData(method, targetType, targetType); } diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeSystemMethodParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeSystemMethodParser.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeSystemMethodParser.java Wed Apr 15 11:03:04 2015 -0700 @@ -25,7 +25,6 @@ import javax.lang.model.element.*; import javax.lang.model.type.*; -import com.oracle.truffle.api.dsl.*; import com.oracle.truffle.dsl.processor.*; import com.oracle.truffle.dsl.processor.java.*; import com.oracle.truffle.dsl.processor.model.*; @@ -41,18 +40,13 @@ return ElementUtils.findAnnotationMirror(getContext().getEnvironment(), method, getAnnotationType()) != null; } - protected final TypeData resolveCastOrCheck(TemplateMethod method) { + protected final TypeMirror resolveCastOrCheck(TemplateMethod method) { Class annotationType = getAnnotationType(); TypeMirror targetTypeMirror = ElementUtils.getAnnotationValue(TypeMirror.class, method.getMessageAnnotation(), "value"); - TypeData targetType = getTypeSystem().findTypeData(targetTypeMirror); - if (targetType == null) { - method.addError("The type '%s' is not declared in the @%s.", ElementUtils.getSimpleName(targetTypeMirror), TypeSystem.class.getSimpleName()); - return null; - } if (!method.getMethod().getModifiers().contains(Modifier.PUBLIC) || !method.getMethod().getModifiers().contains(Modifier.STATIC)) { method.addError("@%s annotated method %s must be public and static.", annotationType.getSimpleName(), method.getMethodName()); } - return targetType; + return targetTypeMirror; } } diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeSystemParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeSystemParser.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeSystemParser.java Wed Apr 15 11:03:04 2015 -0700 @@ -22,8 +22,6 @@ */ package com.oracle.truffle.dsl.processor.parser; -import static com.oracle.truffle.dsl.processor.java.ElementUtils.*; - import java.lang.annotation.*; import java.util.*; @@ -33,7 +31,6 @@ import com.oracle.truffle.api.dsl.*; import com.oracle.truffle.api.dsl.internal.*; -import com.oracle.truffle.dsl.processor.generator.*; import com.oracle.truffle.dsl.processor.java.*; import com.oracle.truffle.dsl.processor.model.*; @@ -57,7 +54,7 @@ } assert options != null; - TypeSystemData typeSystem = new TypeSystemData(context, templateType, templateTypeAnnotation, options); + TypeSystemData typeSystem = new TypeSystemData(context, templateType, templateTypeAnnotation, options, false); // annotation type on class path!? TypeElement annotationTypeElement = processingEnv.getElementUtils().getTypeElement(getAnnotationType().getCanonicalName()); @@ -75,24 +72,9 @@ return typeSystem; } - List types = parseTypes(typeSystem); - - TypeMirror genericType = context.getType(Object.class); - TypeData voidType = new TypeData(typeSystem, types.size(), null, context.getType(void.class), context.getType(Void.class)); - types.add(voidType); - - typeSystem.setTypes(types); if (typeSystem.hasErrors()) { return typeSystem; } - typeSystem.setGenericType(genericType); - typeSystem.setVoidType(voidType); - - TypeData booleanType = typeSystem.findTypeData(context.getType(boolean.class)); - if (booleanType == null) { - booleanType = new TypeData(typeSystem, types.size(), null, context.getType(boolean.class), context.getType(Boolean.class)); - } - typeSystem.setBooleanType(booleanType); verifyExclusiveMethodAnnotation(typeSystem, TypeCast.class, TypeCheck.class); @@ -105,25 +87,24 @@ return typeSystem; } - typeSystem.setImplicitCasts(implicitCasts); - typeSystem.setCasts(casts); - typeSystem.setChecks(checks); + List legacyTypes = ElementUtils.getAnnotationValueList(TypeMirror.class, typeSystem.getTemplateTypeAnnotation(), "value"); + for (int i = 0; i < legacyTypes.size(); i++) { + legacyTypes.set(i, ElementUtils.fillInGenericWildcards(legacyTypes.get(i))); + } + + typeSystem.getLegacyTypes().addAll(legacyTypes); + verifyTypes(typeSystem); + typeSystem.getLegacyTypes().add(context.getType(Object.class)); + typeSystem.getLegacyTypes().add(context.getType(void.class)); + verifyNamesUnique(typeSystem); + + typeSystem.getImplicitCasts().addAll(implicitCasts); + typeSystem.getCasts().addAll(casts); + typeSystem.getChecks().addAll(checks); if (typeSystem.hasErrors()) { return typeSystem; } - - for (TypeCheckData check : checks) { - check.getCheckedType().addTypeCheck(check); - } - - for (TypeCastData cast : casts) { - cast.getTargetType().addTypeCast(cast); - } - - verifyMethodSignatures(typeSystem); - verifyNamesUnique(typeSystem); - return typeSystem; } @@ -149,50 +130,28 @@ } } - private List parseTypes(TypeSystemData typeSystem) { - List types = new ArrayList<>(); - List typeMirrors = ElementUtils.getAnnotationValueList(TypeMirror.class, typeSystem.getTemplateTypeAnnotation(), "value"); - if (typeMirrors.isEmpty()) { - typeSystem.addError("At least one type must be defined."); - return types; - } - - final AnnotationValue annotationValue = ElementUtils.getAnnotationValue(typeSystem.getTemplateTypeAnnotation(), "value"); - final TypeMirror objectType = context.getType(Object.class); - - int index = 0; - for (TypeMirror primitiveType : typeMirrors) { - TypeMirror primitive = ElementUtils.fillInGenericWildcards(primitiveType); - - TypeMirror boxedType = ElementUtils.boxType(context, primitive); - TypeData typeData = new TypeData(typeSystem, index, annotationValue, primitive, boxedType); - - if (isPrimitiveWrapper(primitive)) { - typeData.addError("Types must not contain primitive wrapper types."); + private void verifyTypes(TypeSystemData typeSystem) { + for (TypeMirror type : typeSystem.getLegacyTypes()) { + if (isPrimitiveWrapper(type)) { + typeSystem.addError("Types must not contain primitive wrapper types."); } - if (ElementUtils.typeEquals(boxedType, objectType)) { - typeData.addError("Types must not contain the generic type java.lang.Object."); + if (ElementUtils.typeEquals(type, context.getType(Object.class))) { + typeSystem.addError("Types must not contain the generic type java.lang.Object."); } - - types.add(typeData); - index++; } - verifyTypeOrder(types); - - types.add(new TypeData(typeSystem, index, annotationValue, objectType, objectType)); - return types; + verifyTypeOrder(typeSystem); } - private static void verifyTypeOrder(List types) { + private static void verifyTypeOrder(TypeSystemData typeSystem) { Map> invalidTypes = new HashMap<>(); - for (int i = types.size() - 1; i >= 0; i--) { - TypeData typeData = types.get(i); - TypeMirror type = typeData.getBoxedType(); + for (int i = typeSystem.getLegacyTypes().size() - 1; i >= 0; i--) { + TypeMirror typeData = typeSystem.getLegacyTypes().get(i); + TypeMirror type = typeSystem.boxType(typeData); if (invalidTypes.containsKey(ElementUtils.getQualifiedName(type))) { - typeData.addError("Invalid type order. The type(s) %s are inherited from a earlier defined type %s.", invalidTypes.get(ElementUtils.getQualifiedName(type)), + typeSystem.addError("Invalid type order. The type(s) %s are inherited from a earlier defined type %s.", invalidTypes.get(ElementUtils.getQualifiedName(type)), ElementUtils.getQualifiedName(type)); } TypeElement element = ElementUtils.fromTypeMirror(type); @@ -200,7 +159,7 @@ if (element != null) { nextInvalidTypes.addAll(ElementUtils.getQualifiedSuperTypeNames(element)); } - nextInvalidTypes.add(getQualifiedName(type)); + nextInvalidTypes.add(ElementUtils.getQualifiedName(type)); for (String qualifiedName : nextInvalidTypes) { List inheritedTypes = invalidTypes.get(qualifiedName); @@ -208,7 +167,7 @@ inheritedTypes = new ArrayList<>(); invalidTypes.put(qualifiedName, inheritedTypes); } - inheritedTypes.add(ElementUtils.getQualifiedName(typeData.getBoxedType())); + inheritedTypes.add(ElementUtils.getQualifiedName(typeSystem.boxType(typeData))); } } } @@ -226,64 +185,11 @@ return false; } - private void verifyMethodSignatures(TypeSystemData typeSystem) { - Set generatedIsMethodNames = new HashSet<>(); - Set generatedAsMethodNames = new HashSet<>(); - Set generatedExpectMethodNames = new HashSet<>(); - - for (TypeData typeData : typeSystem.getTypes()) { - generatedIsMethodNames.add(TypeSystemCodeGenerator.isTypeMethodName(typeData)); - generatedAsMethodNames.add(TypeSystemCodeGenerator.asTypeMethodName(typeData)); - generatedExpectMethodNames.add(TypeSystemCodeGenerator.expectTypeMethodName(typeData)); - } - - List methods = ElementFilter.methodsIn(typeSystem.getTemplateType().getEnclosedElements()); - for (ExecutableElement method : methods) { - if (method.getModifiers().contains(Modifier.PRIVATE)) { - // will not conflict overridden methods - continue; - } else if (method.getParameters().size() != 1) { - continue; - } - String methodName = method.getSimpleName().toString(); - if (generatedIsMethodNames.contains(methodName)) { - verifyIsMethod(typeSystem, method); - } else if (generatedAsMethodNames.contains(methodName)) { - verifyAsMethod(typeSystem, method); - } else if (generatedExpectMethodNames.contains(methodName)) { - verifyExpectMethod(typeSystem); - } - } - } - - private boolean verifyIsMethod(TypeSystemData typeSystem, ExecutableElement method) { - AnnotationMirror mirror = ElementUtils.findAnnotationMirror(processingEnv, method, TypeCheck.class); - if (mirror == null) { - typeSystem.addError("Method starting with the pattern is${typeName} must be annotated with @%s.", TypeCheck.class.getSimpleName()); - return false; - } - return true; - } - - private boolean verifyAsMethod(TypeSystemData typeSystem, ExecutableElement method) { - AnnotationMirror mirror = ElementUtils.findAnnotationMirror(processingEnv, method, TypeCast.class); - if (mirror == null) { - typeSystem.addError("Method starting with the pattern as${typeName} must be annotated with @%s.", TypeCast.class.getSimpleName()); - return false; - } - return true; - } - - private static boolean verifyExpectMethod(TypeSystemData typeSystem) { - typeSystem.addError("Method starting with the pattern expect${typeName} must not be declared manually."); - return false; - } - private static void verifyNamesUnique(TypeSystemData typeSystem) { Set usedNames = new HashSet<>(); - for (TypeData type : typeSystem.getTypes()) { - String boxedName = ElementUtils.getSimpleName(type.getBoxedType()); - String primitiveName = ElementUtils.getSimpleName(type.getPrimitiveType()); + for (TypeMirror type : typeSystem.getLegacyTypes()) { + String boxedName = ElementUtils.getSimpleName(typeSystem.boxType(type)); + String primitiveName = ElementUtils.getSimpleName(type); if (usedNames.contains(boxedName)) { typeSystem.addError("Two types result in the same boxed name: %s.", boxedName); } else if (usedNames.contains(primitiveName)) { @@ -293,4 +199,5 @@ usedNames.add(primitiveName); } } + } diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java Wed Apr 15 11:03:04 2015 -0700 @@ -86,7 +86,7 @@ * {@link SLWhileNode while} with {@link SLBreakNode break} and {@link SLContinueNode continue}, * {@link SLReturnNode return}. *

    • Function calls: {@link SLInvokeNode invocations} are efficiently implemented with - * {@link SLAbstractDispatchNode polymorphic inline caches}. + * {@link SLDispatchNode polymorphic inline caches}. *
    * *

    diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLExpressionNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLExpressionNode.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLExpressionNode.java Wed Apr 15 11:03:04 2015 -0700 @@ -22,8 +22,6 @@ */ package com.oracle.truffle.sl.nodes; -import java.math.*; - import com.oracle.truffle.api.dsl.*; import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.instrument.ProbeNode.WrapperNode; @@ -70,26 +68,14 @@ return SLTypesGen.expectLong(executeGeneric(frame)); } - public BigInteger executeBigInteger(VirtualFrame frame) throws UnexpectedResultException { - return SLTypesGen.expectBigInteger(executeGeneric(frame)); + public SLFunction executeFunction(VirtualFrame frame) throws UnexpectedResultException { + return SLTypesGen.expectSLFunction(executeGeneric(frame)); } public boolean executeBoolean(VirtualFrame frame) throws UnexpectedResultException { return SLTypesGen.expectBoolean(executeGeneric(frame)); } - public String executeString(VirtualFrame frame) throws UnexpectedResultException { - return SLTypesGen.expectString(executeGeneric(frame)); - } - - public SLFunction executeFunction(VirtualFrame frame) throws UnexpectedResultException { - return SLTypesGen.expectSLFunction(executeGeneric(frame)); - } - - public SLNull executeNull(VirtualFrame frame) throws UnexpectedResultException { - return SLTypesGen.expectSLNull(executeGeneric(frame)); - } - @Override public boolean isInstrumentable() { return true; diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/access/SLReadPropertyCacheNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/access/SLReadPropertyCacheNode.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/access/SLReadPropertyCacheNode.java Wed Apr 15 11:03:04 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,170 +22,90 @@ */ package com.oracle.truffle.sl.nodes.access; -import com.oracle.truffle.api.*; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.dsl.*; import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.api.object.*; -import com.oracle.truffle.sl.nodes.*; import com.oracle.truffle.sl.runtime.*; -/** - * The node for accessing a property of an object. When executed, this node first evaluates the - * object expression on the left side of the dot operator and then reads the named property. - */ public abstract class SLReadPropertyCacheNode extends Node { + protected static final int CACHE_LIMIT = 3; + + protected final String propertyName; + + public SLReadPropertyCacheNode(String propertyName) { + this.propertyName = propertyName; + } + public static SLReadPropertyCacheNode create(String propertyName) { - return new SLUninitializedReadObjectPropertyNode(propertyName); + return SLReadPropertyCacheNodeGen.create(propertyName); } public abstract Object executeObject(DynamicObject receiver); public abstract long executeLong(DynamicObject receiver) throws UnexpectedResultException; - protected abstract static class SLReadPropertyCacheChainNode extends SLReadPropertyCacheNode { - protected final Shape shape; - @Child protected SLReadPropertyCacheNode next; - - public SLReadPropertyCacheChainNode(Shape shape, SLReadPropertyCacheNode next) { - this.shape = shape; - this.next = next; - } - - @Override - public final Object executeObject(DynamicObject receiver) { - try { - // if this assumption fails, the object needs to be updated to a valid shape - shape.getValidAssumption().check(); - } catch (InvalidAssumptionException e) { - return this.replace(next).executeObject(receiver); - } - - boolean condition = shape.check(receiver); + /* + * We use a separate long specialization to avoid boxing for long. + */ + @Specialization(limit = "CACHE_LIMIT", guards = {"longLocation != null", "shape.check(receiver)"}, assumptions = "shape.getValidAssumption()") + @SuppressWarnings("unused") + protected long doCachedLong(DynamicObject receiver, // + @Cached("receiver.getShape()") Shape shape, // + @Cached("getLongLocation(shape)") LongLocation longLocation) { + return longLocation.getLong(receiver, true); + } - if (condition) { - return executeObjectUnchecked(receiver, condition); - } else { - return next.executeObject(receiver); - } + protected LongLocation getLongLocation(Shape shape) { + Property property = shape.getProperty(propertyName); + if (property != null && property.getLocation() instanceof LongLocation) { + return (LongLocation) property.getLocation(); } + return null; + } - @Override - public final long executeLong(DynamicObject receiver) throws UnexpectedResultException { - try { - // if this assumption fails, the object needs to be updated to a valid shape - shape.getValidAssumption().check(); - } catch (InvalidAssumptionException e) { - return this.replace(next).executeLong(receiver); - } - - boolean condition = shape.check(receiver); - - if (condition) { - return executeLongUnchecked(receiver, condition); - } else { - return next.executeLong(receiver); - } - } - - protected abstract Object executeObjectUnchecked(DynamicObject receiver, boolean condition); - - protected long executeLongUnchecked(DynamicObject receiver, boolean condition) throws UnexpectedResultException { - return SLTypesGen.expectLong(executeObjectUnchecked(receiver, condition)); + /* + * As soon as we have seen an object read, we cannot avoid boxing long anymore therefore we can + * contain all long cache entries. + */ + @Specialization(limit = "CACHE_LIMIT", contains = "doCachedLong", guards = "shape.check(receiver)", assumptions = "shape.getValidAssumption()") + protected static Object doCachedObject(DynamicObject receiver, // + @Cached("receiver.getShape()") Shape shape, // + @Cached("shape.getProperty(propertyName)") Property property) { + if (property == null) { + return SLNull.SINGLETON; + } else { + return property.get(receiver, shape); } } - protected static class SLReadObjectPropertyNode extends SLReadPropertyCacheChainNode { - private final Location location; - - protected SLReadObjectPropertyNode(Shape shape, Location location, SLReadPropertyCacheNode next) { - super(shape, next); - this.location = location; - } - - @Override - protected Object executeObjectUnchecked(DynamicObject receiver, boolean condition) { - return location.get(receiver, condition); - } - } - - protected static class SLReadBooleanPropertyNode extends SLReadPropertyCacheChainNode { - private final BooleanLocation location; - - protected SLReadBooleanPropertyNode(Shape shape, BooleanLocation location, SLReadPropertyCacheNode next) { - super(shape, next); - this.location = location; - } - - @Override - protected Object executeObjectUnchecked(DynamicObject receiver, boolean condition) { - return location.getBoolean(receiver, condition); + /* + * The generic case is used if the number of shapes accessed overflows the limit. + */ + @Specialization(contains = "doCachedObject") + @TruffleBoundary + protected Object doGeneric(DynamicObject receiver, @Cached("new()") LRUPropertyLookup lruCache) { + if (!lruCache.shape.check(receiver)) { + Shape receiverShape = receiver.getShape(); + lruCache.shape = receiverShape; + lruCache.property = receiverShape.getProperty(propertyName); } - } - - protected static class SLReadLongPropertyNode extends SLReadPropertyCacheChainNode { - private final LongLocation location; - - protected SLReadLongPropertyNode(Shape shape, LongLocation location, SLReadPropertyCacheNode next) { - super(shape, next); - this.location = location; - } - - @Override - protected Object executeObjectUnchecked(DynamicObject receiver, boolean condition) { - return location.getLong(receiver, condition); - } - - @Override - protected long executeLongUnchecked(DynamicObject receiver, boolean condition) throws UnexpectedResultException { - return location.getLong(receiver, condition); - } - } - - protected static class SLReadMissingPropertyNode extends SLReadPropertyCacheChainNode { - protected SLReadMissingPropertyNode(Shape shape, SLReadPropertyCacheNode next) { - super(shape, next); - } - - @Override - protected Object executeObjectUnchecked(DynamicObject receiver, boolean condition) { - // The property was not found in the object, return null + if (lruCache.property != null) { + return lruCache.property.get(receiver, true); + } else { return SLNull.SINGLETON; } } - protected static class SLUninitializedReadObjectPropertyNode extends SLReadPropertyCacheNode { - protected final String propertyName; + protected static class LRUPropertyLookup { - protected SLUninitializedReadObjectPropertyNode(String propertyName) { - this.propertyName = propertyName; + private Shape shape; + private Property property; + + public LRUPropertyLookup() { } - @Override - public Object executeObject(DynamicObject receiver) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - - receiver.updateShape(); - - Shape shape = receiver.getShape(); - Property property = shape.getProperty(propertyName); + } - final SLReadPropertyCacheNode resolvedNode; - if (property == null) { - resolvedNode = new SLReadMissingPropertyNode(shape, this); - } else if (property.getLocation() instanceof LongLocation) { - resolvedNode = new SLReadLongPropertyNode(shape, (LongLocation) property.getLocation(), this); - } else if (property.getLocation() instanceof BooleanLocation) { - resolvedNode = new SLReadBooleanPropertyNode(shape, (BooleanLocation) property.getLocation(), this); - } else { - resolvedNode = new SLReadObjectPropertyNode(shape, property.getLocation(), this); - } - - return this.replace(resolvedNode, "resolved '" + propertyName + "'").executeObject(receiver); - } - - @Override - public long executeLong(DynamicObject receiver) throws UnexpectedResultException { - return SLTypesGen.expectLong(executeObject(receiver)); - } - } } diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/access/SLReadPropertyNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/access/SLReadPropertyNode.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/access/SLReadPropertyNode.java Wed Apr 15 11:03:04 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,16 +41,14 @@ return new SLReadPropertyNode(src, receiverNode, propertyName); } - @Child protected SLExpressionNode receiverNode; - protected final String propertyName; - @Child protected SLReadPropertyCacheNode cacheNode; + @Child private SLExpressionNode receiverNode; + @Child private SLReadPropertyCacheNode cacheNode; private final ConditionProfile receiverTypeCondition = ConditionProfile.createBinaryProfile(); private SLReadPropertyNode(SourceSection src, SLExpressionNode receiverNode, String propertyName) { super(src); this.receiverNode = receiverNode; - this.propertyName = propertyName; - this.cacheNode = SLReadPropertyCacheNode.create(propertyName); + this.cacheNode = SLReadPropertyCacheNodeGen.create(propertyName); } @Override diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/access/SLWritePropertyCacheNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/access/SLWritePropertyCacheNode.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/access/SLWritePropertyCacheNode.java Wed Apr 15 11:03:04 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,276 +23,120 @@ package com.oracle.truffle.sl.nodes.access; import com.oracle.truffle.api.*; +import com.oracle.truffle.api.CompilerDirectives.*; +import com.oracle.truffle.api.dsl.*; import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.api.object.*; -/** - * The node for accessing a property of an object. When executed, this node first evaluates the - * object expression on the left side of the dot operator and then reads the named property. - */ public abstract class SLWritePropertyCacheNode extends Node { - public static SLWritePropertyCacheNode create(String propertyName) { - return new SLUninitializedWritePropertyNode(propertyName); + protected final String propertyName; + + public SLWritePropertyCacheNode(String propertyName) { + this.propertyName = propertyName; } public abstract void executeObject(DynamicObject receiver, Object value); - public abstract void executeLong(DynamicObject receiver, long value); - - public abstract void executeBoolean(DynamicObject receiver, boolean value); - - protected abstract static class SLWritePropertyCacheChainNode extends SLWritePropertyCacheNode { - protected final Shape oldShape; - protected final Shape newShape; - @Child protected SLWritePropertyCacheNode next; - - public SLWritePropertyCacheChainNode(Shape oldShape, Shape newShape, SLWritePropertyCacheNode next) { - this.oldShape = oldShape; - this.newShape = newShape; - this.next = next; + @Specialization(guards = "location.isValid(receiver, value)", assumptions = "location.getAssumptions()") + public void writeCached(DynamicObject receiver, Object value, // + @Cached("createCachedWrite(receiver, value)") CachedWriteLocation location) { + if (location.writeUnchecked(receiver, value)) { + // write successful + } else { + executeObject(receiver, value); } - - @Override - public final void executeObject(DynamicObject receiver, Object value) { - try { - // if this assumption fails, the object needs to be updated to a valid shape - oldShape.getValidAssumption().check(); - newShape.getValidAssumption().check(); - } catch (InvalidAssumptionException e) { - this.replace(next).executeObject(receiver, value); - return; - } - - boolean condition = oldShape.check(receiver) && checkValue(receiver, value); - - if (condition) { - executeObjectUnchecked(receiver, value); - } else { - next.executeObject(receiver, value); - } - } + } - @Override - public final void executeLong(DynamicObject receiver, long value) { - try { - // if this assumption fails, the object needs to be updated to a valid shape - oldShape.getValidAssumption().check(); - newShape.getValidAssumption().check(); - } catch (InvalidAssumptionException e) { - this.replace(next).executeLong(receiver, value); - return; - } - - boolean condition = oldShape.check(receiver) && checkValue(receiver, value); - - if (condition) { - executeLongUnchecked(receiver, value); - } else { - next.executeLong(receiver, value); - } + @Specialization(contains = "writeCached") + @TruffleBoundary + public void writeGeneric(DynamicObject receiver, Object value, // + @Cached("new(createCachedWrite(receiver, value))") LRUCachedWriteLocation lru) { + CachedWriteLocation location = lru.location; + if (!location.isValid(receiver, value) || !location.areAssumptionsValid()) { + location = createCachedWrite(receiver, value); + lru.location = location; } - - @Override - public final void executeBoolean(DynamicObject receiver, boolean value) { - try { - // if this assumption fails, the object needs to be updated to a valid shape - oldShape.getValidAssumption().check(); - newShape.getValidAssumption().check(); - } catch (InvalidAssumptionException e) { - this.replace(next).executeBoolean(receiver, value); - return; - } - - boolean condition = oldShape.check(receiver) && checkValue(receiver, value); - - if (condition) { - executeBooleanUnchecked(receiver, value); - } else { - next.executeBoolean(receiver, value); - } - } - - @SuppressWarnings("unused") - protected boolean checkValue(DynamicObject receiver, Object value) { - return true; - } - - protected abstract void executeObjectUnchecked(DynamicObject receiver, Object value); - - protected void executeLongUnchecked(DynamicObject receiver, long value) { - executeObjectUnchecked(receiver, value); - } - - protected void executeBooleanUnchecked(DynamicObject receiver, boolean value) { - executeObjectUnchecked(receiver, value); + if (location.writeUnchecked(receiver, value)) { + // write successful + } else { + executeObject(receiver, value); } } - protected static class SLWriteObjectPropertyNode extends SLWritePropertyCacheChainNode { - private final Location location; + protected CachedWriteLocation createCachedWrite(DynamicObject receiver, Object value) { + while (receiver.updateShape()) { + // multiple shape updates might be needed. + } + + Shape oldShape = receiver.getShape(); + Shape newShape; + Property property = oldShape.getProperty(propertyName); + + if (property != null && property.getLocation().canSet(receiver, value)) { + newShape = oldShape; + } else { + receiver.define(propertyName, value, 0); + newShape = receiver.getShape(); + property = newShape.getProperty(propertyName); + } - protected SLWriteObjectPropertyNode(Shape oldShape, Shape newShape, Location location, SLWritePropertyCacheNode next) { - super(oldShape, newShape, next); + if (!oldShape.check(receiver)) { + return createCachedWrite(receiver, value); + } + + return new CachedWriteLocation(oldShape, newShape, property.getLocation()); + + } + + protected static final class CachedWriteLocation { + + private final Shape oldShape; + private final Shape newShape; + private final Location location; + private final Assumption validLocation = Truffle.getRuntime().createAssumption(); + + public CachedWriteLocation(Shape oldShape, Shape newShape, Location location) { + this.oldShape = oldShape; + this.newShape = newShape; this.location = location; } - @Override - protected void executeObjectUnchecked(DynamicObject receiver, Object value) { + public boolean areAssumptionsValid() { + return validLocation.isValid() && oldShape.getValidAssumption().isValid() && newShape.getValidAssumption().isValid(); + } + + public Assumption[] getAssumptions() { + return new Assumption[]{oldShape.getValidAssumption(), newShape.getValidAssumption(), validLocation}; + } + + public boolean isValid(DynamicObject receiver, Object value) { + return oldShape.check(receiver) && location.canSet(receiver, value); + } + + public boolean writeUnchecked(DynamicObject receiver, Object value) { try { if (oldShape == newShape) { location.set(receiver, value, oldShape); } else { location.set(receiver, value, oldShape, newShape); } + return true; } catch (IncompatibleLocationException | FinalLocationException e) { - replace(next).executeObject(receiver, value); + validLocation.invalidate(); + return false; } } - - @Override - protected boolean checkValue(DynamicObject receiver, Object value) { - return location.canSet(receiver, value); - } } - protected static class SLWriteBooleanPropertyNode extends SLWritePropertyCacheChainNode { - private final BooleanLocation location; - - protected SLWriteBooleanPropertyNode(Shape oldShape, Shape newShape, BooleanLocation location, SLWritePropertyCacheNode next) { - super(oldShape, newShape, next); - this.location = location; - } - - @Override - protected void executeObjectUnchecked(DynamicObject receiver, Object value) { - try { - if (oldShape == newShape) { - location.set(receiver, value, oldShape); - } else { - location.set(receiver, value, oldShape, newShape); - } - } catch (IncompatibleLocationException | FinalLocationException e) { - replace(next).executeObject(receiver, value); - } - } + protected static final class LRUCachedWriteLocation { - @Override - protected void executeBooleanUnchecked(DynamicObject receiver, boolean value) { - try { - if (oldShape == newShape) { - location.setBoolean(receiver, value, oldShape); - } else { - location.setBoolean(receiver, value, oldShape, newShape); - } - } catch (FinalLocationException e) { - replace(next).executeBoolean(receiver, value); - } - } + private CachedWriteLocation location; - @Override - protected boolean checkValue(DynamicObject receiver, Object value) { - return value instanceof Boolean; - } - } - - protected static class SLWriteLongPropertyNode extends SLWritePropertyCacheChainNode { - private final LongLocation location; - - protected SLWriteLongPropertyNode(Shape oldShape, Shape newShape, LongLocation location, SLWritePropertyCacheNode next) { - super(oldShape, newShape, next); + public LRUCachedWriteLocation(CachedWriteLocation location) { this.location = location; } - @Override - protected void executeObjectUnchecked(DynamicObject receiver, Object value) { - try { - if (oldShape == newShape) { - location.set(receiver, value, oldShape); - } else { - location.set(receiver, value, oldShape, newShape); - } - } catch (IncompatibleLocationException | FinalLocationException e) { - replace(next).executeObject(receiver, value); - } - } - - @Override - protected void executeLongUnchecked(DynamicObject receiver, long value) { - try { - if (oldShape == newShape) { - location.setLong(receiver, value, oldShape); - } else { - location.setLong(receiver, value, oldShape, newShape); - } - } catch (FinalLocationException e) { - replace(next).executeLong(receiver, value); - } - } - - @Override - protected boolean checkValue(DynamicObject receiver, Object value) { - return value instanceof Long; - } } - protected static class SLUninitializedWritePropertyNode extends SLWritePropertyCacheNode { - protected final String propertyName; - - protected SLUninitializedWritePropertyNode(String propertyName) { - this.propertyName = propertyName; - } - - @Override - public void executeObject(DynamicObject receiver, Object value) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - - if (receiver.updateShape()) { - // shape changed, retry cache again - getTopNode().executeObject(receiver, value); - return; - } - - Shape oldShape = receiver.getShape(); - Shape newShape; - Property property = oldShape.getProperty(propertyName); - - final SLWritePropertyCacheNode resolvedNode; - if (property != null && property.getLocation().canSet(receiver, value)) { - newShape = oldShape; - } else { - receiver.define(propertyName, value, 0); - newShape = receiver.getShape(); - property = newShape.getProperty(propertyName); - } - - if (property.getLocation() instanceof LongLocation) { - resolvedNode = new SLWriteLongPropertyNode(oldShape, newShape, (LongLocation) property.getLocation(), this); - } else if (property.getLocation() instanceof BooleanLocation) { - resolvedNode = new SLWriteBooleanPropertyNode(oldShape, newShape, (BooleanLocation) property.getLocation(), this); - } else { - resolvedNode = new SLWriteObjectPropertyNode(oldShape, newShape, property.getLocation(), this); - } - - this.replace(resolvedNode, "resolved '" + propertyName + "'").executeObject(receiver, value); - } - - private SLWritePropertyCacheNode getTopNode() { - SLWritePropertyCacheNode top = this; - while (top.getParent() instanceof SLWritePropertyCacheNode) { - top = (SLWritePropertyCacheNode) top.getParent(); - } - return top; - } - - @Override - public void executeLong(DynamicObject receiver, long value) { - executeObject(receiver, value); - } - - @Override - public void executeBoolean(DynamicObject receiver, boolean value) { - executeObject(receiver, value); - } - } } diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/access/SLWritePropertyNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/access/SLWritePropertyNode.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/access/SLWritePropertyNode.java Wed Apr 15 11:03:04 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,7 +54,7 @@ this.receiverNode = receiverNode; this.propertyName = propertyName; this.valueNode = valueNode; - this.cacheNode = SLWritePropertyCacheNode.create(propertyName); + this.cacheNode = SLWritePropertyCacheNodeGen.create(propertyName); } @Override diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLAbstractDispatchNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLAbstractDispatchNode.java Wed Apr 15 10:09:13 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.sl.nodes.call; - -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.sl.runtime.*; - -/** - * Before a call is executed the first time, the dispatch node is a - * {@link SLUninitializedDispatchNode}. During execution, the call is optimized using a polymorphic - * inline cache, i.e., a chain of {@link SLDirectDispatchNode}s. The chain is terminated by a - * {@link SLUninitializedDispatchNode}. If the chain gets too long (longer than - * {@link #INLINE_CACHE_SIZE}), i.e., if the call is too polymorphic, the whole chain is replaced by - * a single {@link SLGenericDispatchNode}. All this rewriting happens on runtime, based on profiling - * feedback of the actual execution. - *

    - * Example of the chain of nodes ({@code I}: {@link SLInvokeNode}; {@code U}: - * {@link SLUninitializedDispatchNode}; {@code D}: {@link SLDirectDispatchNode}; {@code G}: - * {@link SLGenericDispatchNode}): - *

      - *
    1. After parsing: {@code I->U} - *
    2. After execution of function {@code f1}: {@code I->D(f1)->U} - *
    3. After execution of function {@code f2}: {@code I->D(f1)->D(f2)->U} - *
    4. After execution of function {@code f3}: {@code I->G} - *
    - */ -public abstract class SLAbstractDispatchNode extends Node { - - protected static final int INLINE_CACHE_SIZE = 2; - - protected abstract Object executeDispatch(VirtualFrame frame, SLFunction function, Object[] arguments); -} diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDirectDispatchNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDirectDispatchNode.java Wed Apr 15 10:09:13 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,112 +0,0 @@ -/* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.sl.nodes.call; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.sl.runtime.*; - -/** - * An entry in the polymorphic inline cache. - */ -final class SLDirectDispatchNode extends SLAbstractDispatchNode { - - /** The cached function. */ - private final SLFunction cachedFunction; - - /** - * {@link DirectCallNode} is part of the Truffle API and handles all the steps necessary for - * method inlining: if the call is executed frequently and the callee is small, then the call is - * inlined, i.e., the call node is replaced with a copy of the callee's AST. - */ - @Child private DirectCallNode callCachedTargetNode; - - /** Assumption that the {@link #callCachedTargetNode} is still valid. */ - private final Assumption cachedTargetStable; - - /** - * The next entry of the polymorphic inline cache, either another {@link SLDirectDispatchNode} - * or a {@link SLUninitializedDispatchNode}. - */ - @Child private SLAbstractDispatchNode nextNode; - - protected SLDirectDispatchNode(SLAbstractDispatchNode next, SLFunction cachedFunction) { - this.cachedFunction = cachedFunction; - this.callCachedTargetNode = Truffle.getRuntime().createDirectCallNode(cachedFunction.getCallTarget()); - this.cachedTargetStable = cachedFunction.getCallTargetStable(); - this.nextNode = next; - } - - /** - * Perform the inline cache check. If it succeeds, execute the cached - * {@link #cachedTargetStable call target}; if it fails, defer to the next element in the chain. - *

    - * Since SL is a quite simple language, the benefit of the inline cache is quite small: after - * checking that the actual function to be executed is the same as the - * {@link SLDirectDispatchNode#cachedFunction}, we can safely execute the cached call target. - * You can reasonably argue that caching the call target is overkill, since we could just - * retrieve it via {@code function.getCallTarget()}. However, in a more complex language the - * lookup of the call target is usually much more complicated than in SL. In addition, caching - * the call target allows method inlining. - */ - @Override - protected Object executeDispatch(VirtualFrame frame, SLFunction function, Object[] arguments) { - /* - * The inline cache check. Note that cachedFunction must be a final field so that the - * compiler can optimize the check. - */ - if (this.cachedFunction == function) { - /* Inline cache hit, we are safe to execute the cached call target. */ - try { - /* - * Support for function redefinition: When a function is redefined, the call target - * maintained by the SLFunction object is change. To avoid a check for that, we use - * an Assumption that is invalidated by the SLFunction when the change is performed. - * Since checking an assumption is a no-op in compiled code, the line below does not - * add any overhead during optimized execution. - */ - cachedTargetStable.check(); - - /* - * Now we are really ready to perform the call. We use a Truffle CallNode for that, - * because it does all the work for method inlining. - */ - return callCachedTargetNode.call(frame, arguments); - - } catch (InvalidAssumptionException ex) { - /* - * The function has been redefined. Remove ourself from the polymorphic inline - * cache, so that we fail the check only once. Note that this replacement has subtle - * semantics: we are changing a node in the tree that is currently executed. This is - * only safe because we know that after the call to replace(), there is no more code - * that requires that this node is part of the tree. - */ - replace(nextNode); - /* Execute the next node in the chain by falling out of the if block. */ - } - } - /* Inline cache miss, defer to the next element in the chain. */ - return nextNode.executeDispatch(frame, function, arguments); - } -} diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDispatchNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDispatchNode.java Wed Apr 15 11:03:04 2015 -0700 @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.sl.nodes.call; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.sl.runtime.*; + +public abstract class SLDispatchNode extends Node { + + protected static final int INLINE_CACHE_SIZE = 2; + + public abstract Object executeDispatch(VirtualFrame frame, SLFunction function, Object[] arguments); + + /** + * Inline cached specialization of the dispatch. + * + *

    + * Since SL is a quite simple language, the benefit of the inline cache is quite small: after + * checking that the actual function to be executed is the same as the cachedFuntion, we can + * safely execute the cached call target. You can reasonably argue that caching the call target + * is overkill, since we could just retrieve it via {@code function.getCallTarget()}. However, + * in a more complex language the lookup of the call target is usually much more complicated + * than in SL. In addition, caching the call target allows method inlining. + *

    + * + *

    + * {@code limit = "INLINE_CACHE_SIZE"} Specifies the limit number of inline cache specialization + * instantiations. + *

    + *

    + * {@code guards = "function == cachedFunction"} The inline cache check. Note that + * cachedFunction is a final field so that the compiler can optimize the check. + *

    + *

    + * {@code assumptions = "cachedFunction.getCallTargetStable()"} Support for function + * redefinition: When a function is redefined, the call target maintained by the SLFunction + * object is change. To avoid a check for that, we use an Assumption that is invalidated by the + * SLFunction when the change is performed. Since checking an assumption is a no-op in compiled + * code, the assumption check performed by the DSL does not add any overhead during optimized + * execution. + *

    + * + * @see Cached + * @see Specialization + * + * @param function the dynamically provided function + * @param cachedFunction the cached function of the specialization instance + * @param callNode the {@link DirectCallNode} specifically created for the {@link CallTarget} in + * cachedFunction. + */ + @Specialization(limit = "INLINE_CACHE_SIZE", guards = "function == cachedFunction", assumptions = "cachedFunction.getCallTargetStable()") + protected static Object doDirect(VirtualFrame frame, SLFunction function, Object[] arguments, // + @Cached("function") SLFunction cachedFunction, // + @Cached("create(cachedFunction.getCallTarget())") DirectCallNode callNode) { + /* Inline cache hit, we are safe to execute the cached call target. */ + return callNode.call(frame, arguments); + } + + /** + * Slow-path code for a call, used when the polymorphic inline cache exceeded its maximum size + * specified in INLINE_CACHE_SIZE. Such calls are not optimized any further, e.g., + * no method inlining is performed. + */ + @Specialization(contains = "doDirect") + protected static Object doIndirect(VirtualFrame frame, SLFunction function, Object[] arguments, // + @Cached("create()") IndirectCallNode callNode) { + /* + * SL has a quite simple call lookup: just ask the function for the current call target, and + * call it. + */ + return callNode.call(frame, function.getCallTarget(), arguments); + } + +} diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLGenericDispatchNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLGenericDispatchNode.java Wed Apr 15 10:09:13 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.sl.nodes.call; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.sl.runtime.*; - -/** - * Slow-path code for a call, used when the polymorphic inline cache exceeded its maximum size. Such - * calls are not optimized any further, e.g., no method inlining is performed. - */ -final class SLGenericDispatchNode extends SLAbstractDispatchNode { - - /** - * {@link IndirectCallNode} is part of the Truffle API and handles all the steps necessary for - * calling a megamorphic call-site. The Graal specific version of this node performs additional - * optimizations for the fast access of the SimpleLanguage stack trace. - */ - @Child private IndirectCallNode callNode = Truffle.getRuntime().createIndirectCallNode(); - - @Override - protected Object executeDispatch(VirtualFrame frame, SLFunction function, Object[] arguments) { - /* - * SL has a quite simple call lookup: just ask the function for the current call target, and - * call it. - */ - return callNode.call(frame, function.getCallTarget(), arguments); - } - -} diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLInvokeNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLInvokeNode.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLInvokeNode.java Wed Apr 15 11:03:04 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,24 +35,24 @@ * {@link SLFunction target function} can be computed by an {@link #functionNode arbitrary * expression}. This node is responsible for evaluating this expression, as well as evaluating the * {@link #argumentNodes arguments}. The actual dispatch is then delegated to a chain of - * {@link SLAbstractDispatchNode}s that form a polymorphic inline cache. + * {@link SLDispatchNode} that form a polymorphic inline cache. */ @NodeInfo(shortName = "invoke") public final class SLInvokeNode extends SLExpressionNode { public static SLInvokeNode create(SourceSection src, SLExpressionNode function, SLExpressionNode[] arguments) { - return new SLInvokeNode(src, function, arguments, new SLUninitializedDispatchNode()); + return new SLInvokeNode(src, function, arguments); } - @Child protected SLExpressionNode functionNode; - @Children protected final SLExpressionNode[] argumentNodes; - @Child protected SLAbstractDispatchNode dispatchNode; + @Child private SLExpressionNode functionNode; + @Children private final SLExpressionNode[] argumentNodes; + @Child private SLDispatchNode dispatchNode; - private SLInvokeNode(SourceSection src, SLExpressionNode functionNode, SLExpressionNode[] argumentNodes, SLAbstractDispatchNode dispatchNode) { + private SLInvokeNode(SourceSection src, SLExpressionNode functionNode, SLExpressionNode[] argumentNodes) { super(src); this.functionNode = functionNode; this.argumentNodes = argumentNodes; - this.dispatchNode = dispatchNode; + this.dispatchNode = SLDispatchNodeGen.create(); } @Override diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLUninitializedDispatchNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLUninitializedDispatchNode.java Wed Apr 15 10:09:13 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.sl.nodes.call; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.sl.*; -import com.oracle.truffle.sl.runtime.*; - -/** - * The last entry of a polymorphic inline cache. - */ -final class SLUninitializedDispatchNode extends SLAbstractDispatchNode { - - /** - * When we reach this method, all the previous cache entries did not match the function. If the - * cache is still small enough, we extend it by adding another {@link SLDirectDispatchNode}. If - * the cache reached its maximum size, we replace the whole dispatch chain with a - * {@link SLGenericDispatchNode}. - */ - @Override - protected Object executeDispatch(VirtualFrame frame, SLFunction function, Object[] arguments) { - /* The following code modifies the AST, so compiled code must be invalidated. */ - CompilerDirectives.transferToInterpreterAndInvalidate(); - - /* - * Count the number of SLDirectDispatchNodes we already have in the cache. We walk the chain - * of parent nodes until we hit the SLCallNode. We know that a SLCallNode is always present. - */ - Node cur = this; - int depth = 0; - while (cur.getParent() instanceof SLAbstractDispatchNode) { - cur = cur.getParent(); - depth++; - } - SLInvokeNode invokeNode = (SLInvokeNode) cur.getParent(); - - SLAbstractDispatchNode replacement; - if (function.getCallTarget() == null) { - /* Corner case: the function is not defined, so report an error to the user. */ - throw new SLException("Call of undefined function: " + function.getName()); - - } else if (depth < INLINE_CACHE_SIZE) { - /* Extend the inline cache. Allocate the new cache entry, and the new end of the cache. */ - SLAbstractDispatchNode next = new SLUninitializedDispatchNode(); - replacement = new SLDirectDispatchNode(next, function); - /* Replace ourself with the new cache entry. */ - replace(replacement); - - } else { - /* Cache size exceeded, fall back to a single generic dispatch node. */ - replacement = new SLGenericDispatchNode(); - /* Replace the whole chain, not just ourself, with the new generic node. */ - invokeNode.dispatchNode.replace(replacement); - } - - /* - * Execute the newly created node perform the actual dispatch. That saves us from - * duplicating the actual call logic here. - */ - return replacement.executeDispatch(frame, function, arguments); - } -} diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBlockNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBlockNode.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBlockNode.java Wed Apr 15 11:03:04 2015 -0700 @@ -55,8 +55,7 @@ @ExplodeLoop public void executeVoid(VirtualFrame frame) { /* - * This assertion illustrates that the arryay length is really a constant during - * compilation. + * This assertion illustrates that the array length is really a constant during compilation. */ CompilerAsserts.compilationConstant(bodyNodes.length); diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLBigIntegerLiteralNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLBigIntegerLiteralNode.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLBigIntegerLiteralNode.java Wed Apr 15 11:03:04 2015 -0700 @@ -44,12 +44,7 @@ } @Override - public BigInteger executeBigInteger(VirtualFrame frame) { - return value; - } - - @Override - public Object executeGeneric(VirtualFrame frame) { + public BigInteger executeGeneric(VirtualFrame frame) { return value; } } diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLEqualNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLEqualNode.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLEqualNode.java Wed Apr 15 11:03:04 2015 -0700 @@ -25,6 +25,7 @@ import java.math.*; import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.api.source.*; import com.oracle.truffle.sl.nodes.*; @@ -47,6 +48,9 @@ super(src); } + @Override + public abstract boolean executeBoolean(VirtualFrame frame); + @Specialization protected boolean equal(long left, long right) { return left == right; diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLFunctionLiteralNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLFunctionLiteralNode.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLFunctionLiteralNode.java Wed Apr 15 11:03:04 2015 -0700 @@ -46,12 +46,7 @@ } @Override - public SLFunction executeFunction(VirtualFrame frame) { - return value; - } - - @Override - public Object executeGeneric(VirtualFrame frame) { + public SLFunction executeGeneric(VirtualFrame frame) { return value; } } diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLessOrEqualNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLessOrEqualNode.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLessOrEqualNode.java Wed Apr 15 11:03:04 2015 -0700 @@ -25,6 +25,7 @@ import java.math.*; import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.api.source.*; import com.oracle.truffle.sl.nodes.*; @@ -39,6 +40,9 @@ super(src); } + @Override + public abstract boolean executeBoolean(VirtualFrame frame); + @Specialization protected boolean lessOrEqual(long left, long right) { return left <= right; diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLessThanNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLessThanNode.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLessThanNode.java Wed Apr 15 11:03:04 2015 -0700 @@ -25,6 +25,7 @@ import java.math.*; import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.api.source.*; import com.oracle.truffle.sl.nodes.*; @@ -40,6 +41,9 @@ super(src); } + @Override + public abstract boolean executeBoolean(VirtualFrame frame); + @Specialization protected boolean lessThan(long left, long right) { return left < right; diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalAndNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalAndNode.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalAndNode.java Wed Apr 15 11:03:04 2015 -0700 @@ -23,6 +23,7 @@ package com.oracle.truffle.sl.nodes.expression; import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.api.source.*; import com.oracle.truffle.sl.nodes.*; @@ -44,6 +45,9 @@ super(src); } + @Override + public abstract boolean executeBoolean(VirtualFrame frame); + /** * This method is called after the left child was evaluated, but before the right child is * evaluated. The right child is only evaluated when the return value is {code true}. diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalNotNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalNotNode.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalNotNode.java Wed Apr 15 11:03:04 2015 -0700 @@ -23,6 +23,7 @@ package com.oracle.truffle.sl.nodes.expression; import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.api.source.*; import com.oracle.truffle.sl.nodes.*; @@ -39,6 +40,9 @@ super(src); } + @Override + public abstract boolean executeBoolean(VirtualFrame frame); + @Specialization protected boolean doBoolean(boolean value) { return !value; diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalOrNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalOrNode.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalOrNode.java Wed Apr 15 11:03:04 2015 -0700 @@ -39,6 +39,9 @@ super(src); } + @Override + public abstract boolean executeBoolean(VirtualFrame frame); + @ShortCircuit("rightNode") protected boolean needsRightNode(boolean left) { return !left; diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLParenExpressionNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLParenExpressionNode.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLParenExpressionNode.java Wed Apr 15 11:03:04 2015 -0700 @@ -22,13 +22,10 @@ */ package com.oracle.truffle.sl.nodes.expression; -import java.math.*; - import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.api.source.*; import com.oracle.truffle.sl.nodes.*; -import com.oracle.truffle.sl.runtime.*; /** * A {@link SLExpressionNode} that represents a parenthesized expression; it simply returns the @@ -57,27 +54,8 @@ } @Override - public BigInteger executeBigInteger(VirtualFrame frame) throws UnexpectedResultException { - return expression.executeBigInteger(frame); - } - - @Override public boolean executeBoolean(VirtualFrame frame) throws UnexpectedResultException { return expression.executeBoolean(frame); } - @Override - public String executeString(VirtualFrame frame) throws UnexpectedResultException { - return expression.executeString(frame); - } - - @Override - public SLFunction executeFunction(VirtualFrame frame) throws UnexpectedResultException { - return expression.executeFunction(frame); - } - - @Override - public SLNull executeNull(VirtualFrame frame) throws UnexpectedResultException { - return expression.executeNull(frame); - } } diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLStringLiteralNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLStringLiteralNode.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLStringLiteralNode.java Wed Apr 15 11:03:04 2015 -0700 @@ -41,12 +41,7 @@ } @Override - public String executeString(VirtualFrame frame) { - return value; - } - - @Override - public Object executeGeneric(VirtualFrame frame) { + public String executeGeneric(VirtualFrame frame) { return value; } } diff -r 92fc95e8667d -r 23d6b95bd687 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLExpressionWrapperNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLExpressionWrapperNode.java Wed Apr 15 10:09:13 2015 -0700 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLExpressionWrapperNode.java Wed Apr 15 11:03:04 2015 -0700 @@ -22,8 +22,6 @@ */ package com.oracle.truffle.sl.nodes.instrument; -import java.math.*; - import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.instrument.*; import com.oracle.truffle.api.instrument.ProbeNode.WrapperNode; @@ -101,21 +99,11 @@ } @Override - public BigInteger executeBigInteger(VirtualFrame vFrame) throws UnexpectedResultException { - return SLTypesGen.expectBigInteger(executeGeneric(vFrame)); - } - - @Override public boolean executeBoolean(VirtualFrame vFrame) throws UnexpectedResultException { return SLTypesGen.expectBoolean(executeGeneric(vFrame)); } @Override - public String executeString(VirtualFrame vFrame) throws UnexpectedResultException { - return SLTypesGen.expectString(executeGeneric(vFrame)); - } - - @Override public SLFunction executeFunction(VirtualFrame vFrame) throws UnexpectedResultException { probeNode.enter(child, vFrame); SLFunction result; @@ -130,8 +118,4 @@ return result; } - @Override - public SLNull executeNull(VirtualFrame vFrame) throws UnexpectedResultException { - return SLTypesGen.expectSLNull(executeGeneric(vFrame)); - } } diff -r 92fc95e8667d -r 23d6b95bd687 mx/mx_graal.py --- a/mx/mx_graal.py Wed Apr 15 10:09:13 2015 -0700 +++ b/mx/mx_graal.py Wed Apr 15 11:03:04 2015 -0700 @@ -1482,6 +1482,7 @@ jar = os.path.abspath(args.jar) else: jar = join(_jdk(installJars=False), 'jre', 'lib', 'rt.jar') + vmargs.append('-G:CompileTheWorldExcludeMethodFilter=sun.awt.X11.*.*') vmargs += ['-XX:+CompileTheWorld'] vm_ = _get_vm() @@ -1492,7 +1493,7 @@ else: vmargs += ['-Xbootclasspath/p:' + jar] - # suppress menubar and dock when running on Mac + # suppress menubar and dock when running on Mac; exclude x11 classes as they may cause vm crashes (on Solaris) vmargs = ['-Djava.awt.headless=true'] + vmargs vm(vmargs) diff -r 92fc95e8667d -r 23d6b95bd687 mx/suite.py --- a/mx/suite.py Wed Apr 15 10:09:13 2015 -0700 +++ b/mx/suite.py Wed Apr 15 11:03:04 2015 -0700 @@ -465,7 +465,6 @@ "checkstyle" : "com.oracle.graal.graph", "dependencies" : [ "com.oracle.graal.nodeinfo", - "com.oracle.truffle.dsl.processor", ], "javaCompliance" : "1.8", "workingSets" : "Graal,Graph", @@ -1037,6 +1036,7 @@ "dependencies" : [ "com.oracle.truffle.api.dsl", "com.oracle.truffle.api.object", + "FINDBUGS" ], "checkstyle" : "com.oracle.graal.graph", "javaCompliance" : "1.8", diff -r 92fc95e8667d -r 23d6b95bd687 mxtool/mx.py --- a/mxtool/mx.py Wed Apr 15 10:09:13 2015 -0700 +++ b/mxtool/mx.py Wed Apr 15 11:03:04 2015 -0700 @@ -2097,7 +2097,9 @@ return cmp(self.parts, other.parts) def _filter_non_existant_paths(paths): - return os.pathsep.join([path for path in _separatedCygpathW2U(paths).split(os.pathsep) if exists(path)]) + if paths: + return os.pathsep.join([path for path in _separatedCygpathW2U(paths).split(os.pathsep) if exists(path)]) + return None """ A JavaConfig object encapsulates info on how Java commands are run. @@ -2161,11 +2163,14 @@ if not exists(outDir): os.makedirs(outDir) javaSource = join(myDir, 'ClasspathDump.java') - if not exists(join(outDir, 'ClasspathDump.class')): + javaClass = join(outDir, 'ClasspathDump.class') + if not exists(javaClass) or getmtime(javaClass) < getmtime(javaSource): subprocess.check_call([self.javac, '-d', _cygpathU2W(outDir), _cygpathU2W(javaSource)], stderr=subprocess.PIPE, stdout=subprocess.PIPE) self._bootclasspath, self._extdirs, self._endorseddirs = [x if x != 'null' else None for x in subprocess.check_output([self.java, '-cp', _cygpathU2W(outDir), 'ClasspathDump'], stderr=subprocess.PIPE).split('|')] - if not self._bootclasspath or not self._extdirs or not self._endorseddirs: - warn("Could not find all classpaths: boot='" + str(self._bootclasspath) + "' extdirs='" + str(self._extdirs) + "' endorseddirs='" + str(self._endorseddirs) + "'") + if self.javaCompliance <= JavaCompliance('1.8'): + # All 3 system properties accessed by ClasspathDump are expected to exist + if not self._bootclasspath or not self._extdirs or not self._endorseddirs: + warn("Could not find all classpaths: boot='" + str(self._bootclasspath) + "' extdirs='" + str(self._extdirs) + "' endorseddirs='" + str(self._endorseddirs) + "'") self._bootclasspath = _filter_non_existant_paths(self._bootclasspath) self._extdirs = _filter_non_existant_paths(self._extdirs) self._endorseddirs = _filter_non_existant_paths(self._endorseddirs) @@ -2214,6 +2219,33 @@ self._init_classpaths() return _separatedCygpathU2W(self._endorseddirs) + """ + Add javadoc style options for the library paths of this JDK. + """ + def javadocLibOptions(self, args): + if args is None: + args = [] + if self.bootclasspath(): + args.append('-bootclasspath') + args.append(self.bootclasspath()) + if self.endorseddirs(): + args.append('-endorseddirs') + args.append(self.endorseddirs()) + if self.extdirs(): + args.append('-extdirs') + args.append(self.extdirs()) + return args + + """ + Add javac style options for the library paths of this JDK. + """ + def javacLibOptions(self, args): + args = self.javadocLibOptions(args) + if self.endorseddirs(): + args.append('-endorseddirs') + args.append(self.endorseddirs()) + return args + def containsJar(self, jar): if self._bootclasspath is None: self._init_classpaths() @@ -2447,7 +2479,8 @@ if not args.error_prone: javac = args.alt_javac if args.alt_javac else mainJava.javac self.logCompilation('javac' if not args.alt_javac else args.alt_javac) - javacCmd = [javac, '-g', '-J-Xmx1g', '-source', compliance, '-target', compliance, '-classpath', cp, '-d', outputDir, '-bootclasspath', jdk.bootclasspath(), '-endorseddirs', jdk.endorseddirs(), '-extdirs', jdk.extdirs()] + javacCmd = [javac, '-g', '-J-Xmx1g', '-source', compliance, '-target', compliance, '-classpath', cp, '-d', outputDir] + jdk.javacLibOptions(javacCmd) if jdk.debug_port is not None: javacCmd += ['-J-Xdebug', '-J-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(jdk.debug_port)] javacCmd += processorArgs @@ -2459,7 +2492,8 @@ else: self.logCompilation('javac (with error-prone)') javaArgs = ['-Xmx1g'] - javacArgs = ['-g', '-source', compliance, '-target', compliance, '-classpath', cp, '-d', outputDir, '-bootclasspath', jdk.bootclasspath(), '-endorseddirs', jdk.endorseddirs(), '-extdirs', jdk.extdirs()] + javacArgs = ['-g', '-source', compliance, '-target', compliance, '-classpath', cp, '-d', outputDir] + jdk.javacLibOptions(javacCmd) javacArgs += processorArgs javacArgs += ['@' + argfile.name] if not args.warnAPI: @@ -2472,10 +2506,8 @@ jdtArgs = ['-' + compliance, '-cp', cp, '-g', '-enableJavadoc', - '-d', outputDir, - '-bootclasspath', jdk.bootclasspath(), - '-endorseddirs', jdk.endorseddirs(), - '-extdirs', jdk.extdirs()] + '-d', outputDir] + jdk.javacLibOptions(jdtArgs) jdtArgs += processorArgs jdtProperties = join(self.proj.dir, '.settings', 'org.eclipse.jdt.core.prefs') @@ -4840,9 +4872,8 @@ '-d', out, '-overview', overviewFile, '-sourcepath', sp, - '-source', str(projectJava.javaCompliance), - '-bootclasspath', projectJava.bootclasspath(), - '-extdirs', projectJava.extdirs()] + + '-source', str(projectJava.javaCompliance)] + + projectJava.javadocLibOptions() + ([] if projectJava.javaCompliance < JavaCompliance('1.8') else ['-Xdoclint:none']) + links + extraArgs + diff -r 92fc95e8667d -r 23d6b95bd687 src/cpu/x86/vm/registerMap_x86.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/cpu/x86/vm/registerMap_x86.cpp Wed Apr 15 11:03:04 2015 -0700 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include +#include "vmreg_x86.inline.hpp" + +address RegisterMap::pd_location(VMReg reg) const { + if (reg->is_XMMRegister()) { + int regBase = reg->value() - ConcreteRegisterImpl::max_fpr; + if (regBase % 4 == 0) { + // Reads of the low and high 16 byte parts should be handled by location itself + return NULL; + } + VMReg baseReg = as_XMMRegister(regBase >> 3)->as_VMReg(); + intptr_t offset = (reg->value() - baseReg->value()) * 4; + if (offset >= 16) { + // The high part of YMM registers are saved in a their own area in the frame + baseReg = baseReg->next()->next()->next()->next(); + offset -= 16; + } + address baseLocation = location(baseReg); + if (baseLocation != NULL) { + return baseLocation + offset; + } + } + return NULL; +} diff -r 92fc95e8667d -r 23d6b95bd687 src/cpu/x86/vm/registerMap_x86.hpp --- a/src/cpu/x86/vm/registerMap_x86.hpp Wed Apr 15 10:09:13 2015 -0700 +++ b/src/cpu/x86/vm/registerMap_x86.hpp Wed Apr 15 11:03:04 2015 -0700 @@ -31,11 +31,7 @@ private: // This is the hook for finding a register in an "well-known" location, // such as a register block of a predetermined format. - // Since there is none, we just return NULL. - // See registerMap_sparc.hpp for an example of grabbing registers - // from register save areas of a standard layout. - address pd_location(VMReg reg) const {return NULL;} - + address pd_location(VMReg reg) const; // no PD state to clear or copy: void pd_clear() {} void pd_initialize() {} diff -r 92fc95e8667d -r 23d6b95bd687 src/cpu/x86/vm/register_x86.cpp --- a/src/cpu/x86/vm/register_x86.cpp Wed Apr 15 10:09:13 2015 -0700 +++ b/src/cpu/x86/vm/register_x86.cpp Wed Apr 15 11:03:04 2015 -0700 @@ -64,3 +64,28 @@ }; return is_valid() ? names[encoding()] : "xnoreg"; } + +const char* XMMRegisterImpl::sub_word_name(int i) const { + const char* names[number_of_registers * 8] = { + "xmm0:0", "xmm0:1", "xmm0:2", "xmm0:3", "xmm0:4", "xmm0:5", "xmm0:6", "xmm0:7", + "xmm1:0", "xmm1:1", "xmm1:2", "xmm1:3", "xmm1:4", "xmm1:5", "xmm1:6", "xmm1:7", + "xmm2:0", "xmm2:1", "xmm2:2", "xmm2:3", "xmm2:4", "xmm2:5", "xmm2:6", "xmm2:7", + "xmm3:0", "xmm3:1", "xmm3:2", "xmm3:3", "xmm3:4", "xmm3:5", "xmm3:6", "xmm3:7", + "xmm4:0", "xmm4:1", "xmm4:2", "xmm4:3", "xmm4:4", "xmm4:5", "xmm4:6", "xmm4:7", + "xmm5:0", "xmm5:1", "xmm5:2", "xmm5:3", "xmm5:4", "xmm5:5", "xmm5:6", "xmm5:7", + "xmm6:0", "xmm6:1", "xmm6:2", "xmm6:3", "xmm6:4", "xmm6:5", "xmm6:6", "xmm6:7", + "xmm7:0", "xmm7:1", "xmm7:2", "xmm7:3", "xmm7:4", "xmm7:5", "xmm7:6", "xmm7:7", +#ifdef AMD64 + "xmm8:0", "xmm8:1", "xmm8:2", "xmm8:3", "xmm8:4", "xmm8:5", "xmm8:6", "xmm8:7", + "xmm9:0", "xmm9:1", "xmm9:2", "xmm9:3", "xmm9:4", "xmm9:5", "xmm9:6", "xmm9:7", + "xmm10:0", "xmm10:1", "xmm10:2", "xmm10:3", "xmm10:4", "xmm10:5", "xmm10:6", "xmm10:7", + "xmm11:0", "xmm11:1", "xmm11:2", "xmm11:3", "xmm11:4", "xmm11:5", "xmm11:6", "xmm11:7", + "xmm12:0", "xmm12:1", "xmm12:2", "xmm12:3", "xmm12:4", "xmm12:5", "xmm12:6", "xmm12:7", + "xmm13:0", "xmm13:1", "xmm13:2", "xmm13:3", "xmm13:4", "xmm13:5", "xmm13:6", "xmm13:7", + "xmm14:0", "xmm14:1", "xmm14:2", "xmm14:3", "xmm14:4", "xmm14:5", "xmm14:6", "xmm14:7", + "xmm15:0", "xmm15:1", "xmm15:2", "xmm15:3", "xmm15:4", "xmm15:5", "xmm15:6", "xmm15:7", +#endif // AMD64 + }; + assert(i >= 0 && i < 8, "offset too large"); + return is_valid() ? names[encoding() * 8 + i] : "xnoreg"; +} diff -r 92fc95e8667d -r 23d6b95bd687 src/cpu/x86/vm/register_x86.hpp --- a/src/cpu/x86/vm/register_x86.hpp Wed Apr 15 10:09:13 2015 -0700 +++ b/src/cpu/x86/vm/register_x86.hpp Wed Apr 15 11:03:04 2015 -0700 @@ -161,6 +161,7 @@ int encoding() const { assert(is_valid(), err_msg("invalid register (%d)", (int)(intptr_t)this )); return (intptr_t)this; } bool is_valid() const { return 0 <= (intptr_t)this && (intptr_t)this < number_of_registers; } const char* name() const; + const char* sub_word_name(int offset) const; }; diff -r 92fc95e8667d -r 23d6b95bd687 src/cpu/x86/vm/sharedRuntime_x86_64.cpp --- a/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Wed Apr 15 10:09:13 2015 -0700 +++ b/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Wed Apr 15 11:03:04 2015 -0700 @@ -70,9 +70,32 @@ // Capture info about frame layout. Layout offsets are in jint // units because compiler frame slots are jints. #define DEF_XMM_OFFS(regnum) xmm ## regnum ## _off = xmm_off + (regnum)*16/BytesPerInt, xmm ## regnum ## H_off +#define DEF_YMM_HI_OFFS(regnum) ymm_hi ## regnum ## _off = ymm_off + (regnum)*16/BytesPerInt enum layout { fpu_state_off = frame::arg_reg_save_area_bytes/BytesPerInt, // fxsave save area - xmm_off = fpu_state_off + 160/BytesPerInt, // offset in fxsave save area +#if defined(COMPILER2) || defined(GRAAL) + ymm_off = fpu_state_off, // offset in fxsave save area + DEF_YMM_HI_OFFS(0), + DEF_YMM_HI_OFFS(1), + DEF_YMM_HI_OFFS(2), + DEF_YMM_HI_OFFS(3), + DEF_YMM_HI_OFFS(4), + DEF_YMM_HI_OFFS(5), + DEF_YMM_HI_OFFS(6), + DEF_YMM_HI_OFFS(7), + DEF_YMM_HI_OFFS(8), + DEF_YMM_HI_OFFS(9), + DEF_YMM_HI_OFFS(10), + DEF_YMM_HI_OFFS(11), + DEF_YMM_HI_OFFS(12), + DEF_YMM_HI_OFFS(13), + DEF_YMM_HI_OFFS(14), + DEF_YMM_HI_OFFS(15), + ymm_hi_save_size = 16 * 16 / BytesPerInt, +#else + ymm_hi_save_size = 0, +#endif + xmm_off = fpu_state_off + 160/BytesPerInt + ymm_hi_save_size, // offset in fxsave save area DEF_XMM_OFFS(0), DEF_XMM_OFFS(1), DEF_XMM_OFFS(2), @@ -89,7 +112,7 @@ DEF_XMM_OFFS(13), DEF_XMM_OFFS(14), DEF_XMM_OFFS(15), - fpu_state_end = fpu_state_off + ((FPUStateSizeInWords-1)*wordSize / BytesPerInt), + fpu_state_end = fpu_state_off + ((FPUStateSizeInWords-1)*wordSize / BytesPerInt) + ymm_hi_save_size, fpu_stateH_end, r15_off, r15H_off, r14_off, r14H_off, @@ -139,19 +162,6 @@ }; OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm, int additional_frame_words, int* total_frame_words, bool save_vectors) { - int vect_words = 0; -#ifdef COMPILER2 - if (save_vectors) { - assert(UseAVX > 0, "256bit vectors are supported only with AVX"); - assert(MaxVectorSize == 32, "only 256bit vectors are supported now"); - // Save upper half of YMM registes - vect_words = 16 * 16 / wordSize; - additional_frame_words += vect_words; - } -#else - assert(!save_vectors, "vectors are generated only by C2"); -#endif - // Always make the frame size 16-byte aligned int frame_size_in_bytes = round_to(additional_frame_words*wordSize + reg_save_size*BytesPerInt, 16); @@ -172,26 +182,34 @@ __ enter(); // rsp becomes 16-byte aligned here __ push_CPU_state(); // Push a multiple of 16 bytes - if (vect_words > 0) { - assert(vect_words*wordSize == 256, ""); - __ subptr(rsp, 256); // Save upper half of YMM registes - __ vextractf128h(Address(rsp, 0),xmm0); - __ vextractf128h(Address(rsp, 16),xmm1); - __ vextractf128h(Address(rsp, 32),xmm2); - __ vextractf128h(Address(rsp, 48),xmm3); - __ vextractf128h(Address(rsp, 64),xmm4); - __ vextractf128h(Address(rsp, 80),xmm5); - __ vextractf128h(Address(rsp, 96),xmm6); - __ vextractf128h(Address(rsp,112),xmm7); - __ vextractf128h(Address(rsp,128),xmm8); - __ vextractf128h(Address(rsp,144),xmm9); - __ vextractf128h(Address(rsp,160),xmm10); - __ vextractf128h(Address(rsp,176),xmm11); - __ vextractf128h(Address(rsp,192),xmm12); - __ vextractf128h(Address(rsp,208),xmm13); - __ vextractf128h(Address(rsp,224),xmm14); - __ vextractf128h(Address(rsp,240),xmm15); +#if defined(COMPILER2) || defined(GRAAL) + __ subptr(rsp, 256); // Save upper half of YMM registers + if (save_vectors) { + assert(UseAVX > 0, "256bit vectors are supported only with AVX"); +#ifdef COMPILER2 + assert(MaxVectorSize == 32, "only 256bit vectors are supported now"); +#endif + // Save upper half of YMM registers + __ vextractf128h(Address(rsp, ymm_hi0_off * BytesPerInt), xmm0); + __ vextractf128h(Address(rsp, ymm_hi1_off * BytesPerInt), xmm1); + __ vextractf128h(Address(rsp, ymm_hi2_off * BytesPerInt), xmm2); + __ vextractf128h(Address(rsp, ymm_hi3_off * BytesPerInt), xmm3); + __ vextractf128h(Address(rsp, ymm_hi4_off * BytesPerInt), xmm4); + __ vextractf128h(Address(rsp, ymm_hi5_off * BytesPerInt), xmm5); + __ vextractf128h(Address(rsp, ymm_hi6_off * BytesPerInt), xmm6); + __ vextractf128h(Address(rsp, ymm_hi7_off * BytesPerInt), xmm7); + __ vextractf128h(Address(rsp, ymm_hi8_off * BytesPerInt), xmm8); + __ vextractf128h(Address(rsp, ymm_hi9_off * BytesPerInt), xmm9); + __ vextractf128h(Address(rsp, ymm_hi10_off * BytesPerInt), xmm10); + __ vextractf128h(Address(rsp, ymm_hi11_off * BytesPerInt), xmm11); + __ vextractf128h(Address(rsp, ymm_hi12_off * BytesPerInt), xmm12); + __ vextractf128h(Address(rsp, ymm_hi13_off * BytesPerInt), xmm13); + __ vextractf128h(Address(rsp, ymm_hi14_off * BytesPerInt), xmm14); + __ vextractf128h(Address(rsp, ymm_hi15_off * BytesPerInt), xmm15); } +#else + assert(!save_vectors, "vectors are generated only by C2 and Graal"); +#endif if (frame::arg_reg_save_area_bytes != 0) { // Allocate argument register save area __ subptr(rsp, frame::arg_reg_save_area_bytes); @@ -240,6 +258,28 @@ map->set_callee_saved(STACK_OFFSET(xmm14_off), xmm14->as_VMReg()); map->set_callee_saved(STACK_OFFSET(xmm15_off), xmm15->as_VMReg()); + +#if defined(COMPILER2) || defined(GRAAL) + if (save_vectors) { + map->set_callee_saved(STACK_OFFSET(ymm_hi0_off ), xmm0->as_VMReg()->next()->next()->next()->next()); + map->set_callee_saved(STACK_OFFSET(ymm_hi1_off ), xmm1->as_VMReg()->next()->next()->next()->next()); + map->set_callee_saved(STACK_OFFSET(ymm_hi2_off ), xmm2->as_VMReg()->next()->next()->next()->next()); + map->set_callee_saved(STACK_OFFSET(ymm_hi3_off ), xmm3->as_VMReg()->next()->next()->next()->next()); + map->set_callee_saved(STACK_OFFSET(ymm_hi4_off ), xmm4->as_VMReg()->next()->next()->next()->next()); + map->set_callee_saved(STACK_OFFSET(ymm_hi5_off ), xmm5->as_VMReg()->next()->next()->next()->next()); + map->set_callee_saved(STACK_OFFSET(ymm_hi6_off ), xmm6->as_VMReg()->next()->next()->next()->next()); + map->set_callee_saved(STACK_OFFSET(ymm_hi7_off ), xmm7->as_VMReg()->next()->next()->next()->next()); + map->set_callee_saved(STACK_OFFSET(ymm_hi8_off ), xmm8->as_VMReg()->next()->next()->next()->next()); + map->set_callee_saved(STACK_OFFSET(ymm_hi9_off ), xmm9->as_VMReg()->next()->next()->next()->next()); + map->set_callee_saved(STACK_OFFSET(ymm_hi10_off), xmm10->as_VMReg()->next()->next()->next()->next()); + map->set_callee_saved(STACK_OFFSET(ymm_hi11_off), xmm11->as_VMReg()->next()->next()->next()->next()); + map->set_callee_saved(STACK_OFFSET(ymm_hi12_off), xmm12->as_VMReg()->next()->next()->next()->next()); + map->set_callee_saved(STACK_OFFSET(ymm_hi13_off), xmm13->as_VMReg()->next()->next()->next()->next()); + map->set_callee_saved(STACK_OFFSET(ymm_hi14_off), xmm14->as_VMReg()->next()->next()->next()->next()); + map->set_callee_saved(STACK_OFFSET(ymm_hi15_off), xmm15->as_VMReg()->next()->next()->next()->next()); + } +#endif + // %%% These should all be a waste but we'll keep things as they were for now if (true) { map->set_callee_saved(STACK_OFFSET( raxH_off ), rax->as_VMReg()->next()); @@ -283,31 +323,33 @@ // Pop arg register save area __ addptr(rsp, frame::arg_reg_save_area_bytes); } -#ifdef COMPILER2 +#if defined(COMPILER2) || defined(GRAAL) if (restore_vectors) { // Restore upper half of YMM registes. assert(UseAVX > 0, "256bit vectors are supported only with AVX"); +#if defined(COMPILER2) assert(MaxVectorSize == 32, "only 256bit vectors are supported now"); - __ vinsertf128h(xmm0, Address(rsp, 0)); - __ vinsertf128h(xmm1, Address(rsp, 16)); - __ vinsertf128h(xmm2, Address(rsp, 32)); - __ vinsertf128h(xmm3, Address(rsp, 48)); - __ vinsertf128h(xmm4, Address(rsp, 64)); - __ vinsertf128h(xmm5, Address(rsp, 80)); - __ vinsertf128h(xmm6, Address(rsp, 96)); - __ vinsertf128h(xmm7, Address(rsp,112)); - __ vinsertf128h(xmm8, Address(rsp,128)); - __ vinsertf128h(xmm9, Address(rsp,144)); - __ vinsertf128h(xmm10, Address(rsp,160)); - __ vinsertf128h(xmm11, Address(rsp,176)); - __ vinsertf128h(xmm12, Address(rsp,192)); - __ vinsertf128h(xmm13, Address(rsp,208)); - __ vinsertf128h(xmm14, Address(rsp,224)); - __ vinsertf128h(xmm15, Address(rsp,240)); - __ addptr(rsp, 256); +#endif + __ vinsertf128h(xmm0, Address(rsp, ymm_hi0_off * BytesPerInt)); + __ vinsertf128h(xmm1, Address(rsp, ymm_hi1_off * BytesPerInt)); + __ vinsertf128h(xmm2, Address(rsp, ymm_hi2_off * BytesPerInt)); + __ vinsertf128h(xmm3, Address(rsp, ymm_hi3_off * BytesPerInt)); + __ vinsertf128h(xmm4, Address(rsp, ymm_hi4_off * BytesPerInt)); + __ vinsertf128h(xmm5, Address(rsp, ymm_hi5_off * BytesPerInt)); + __ vinsertf128h(xmm6, Address(rsp, ymm_hi6_off * BytesPerInt)); + __ vinsertf128h(xmm7, Address(rsp, ymm_hi7_off * BytesPerInt)); + __ vinsertf128h(xmm8, Address(rsp, ymm_hi8_off * BytesPerInt)); + __ vinsertf128h(xmm9, Address(rsp, ymm_hi9_off * BytesPerInt)); + __ vinsertf128h(xmm10, Address(rsp, ymm_hi10_off * BytesPerInt)); + __ vinsertf128h(xmm11, Address(rsp, ymm_hi11_off * BytesPerInt)); + __ vinsertf128h(xmm12, Address(rsp, ymm_hi12_off * BytesPerInt)); + __ vinsertf128h(xmm13, Address(rsp, ymm_hi13_off * BytesPerInt)); + __ vinsertf128h(xmm14, Address(rsp, ymm_hi14_off * BytesPerInt)); + __ vinsertf128h(xmm15, Address(rsp, ymm_hi15_off * BytesPerInt)); } + __ addptr(rsp, 256); #else - assert(!restore_vectors, "vectors are generated only by C2"); + assert(!restore_vectors, "vectors are generated only by C2 and Graal"); #endif // Recover CPU state __ pop_CPU_state(); diff -r 92fc95e8667d -r 23d6b95bd687 src/cpu/x86/vm/vmreg_x86.cpp --- a/src/cpu/x86/vm/vmreg_x86.cpp Wed Apr 15 10:09:13 2015 -0700 +++ b/src/cpu/x86/vm/vmreg_x86.cpp Wed Apr 15 11:03:04 2015 -0700 @@ -48,8 +48,9 @@ XMMRegister xreg = ::as_XMMRegister(0); for ( ; i < ConcreteRegisterImpl::max_xmm ; ) { - for (int j = 0 ; j < 8 ; j++) { - regName[i++] = xreg->name(); + regName[i++] = xreg->name(); + for (int j = 1 ; j < 8 ; j++) { + regName[i++] = xreg->sub_word_name(j); } xreg = xreg->successor(); } diff -r 92fc95e8667d -r 23d6b95bd687 src/share/vm/compiler/oopMap.cpp --- a/src/share/vm/compiler/oopMap.cpp Wed Apr 15 10:09:13 2015 -0700 +++ b/src/share/vm/compiler/oopMap.cpp Wed Apr 15 11:03:04 2015 -0700 @@ -388,68 +388,71 @@ do { omv = oms.current(); oop* loc = fr->oopmapreg_to_location(omv.reg(),reg_map); - if ( loc != NULL ) { - oop *base_loc = fr->oopmapreg_to_location(omv.content_reg(), reg_map); - oop *derived_loc = loc; - oop val = *base_loc; - if (val == (oop)NULL || Universe::is_narrow_oop_base(val)) { - // Ignore NULL oops and decoded NULL narrow oops which - // equal to Universe::narrow_oop_base when a narrow oop - // implicit null check is used in compiled code. - // The narrow_oop_base could be NULL or be the address - // of the page below heap depending on compressed oops mode. - } else - derived_oop_fn(base_loc, derived_loc); + guarantee(loc != NULL, "missing saved register"); + oop *base_loc = fr->oopmapreg_to_location(omv.content_reg(), reg_map); + oop *derived_loc = loc; + oop val = *base_loc; + if (val == (oop)NULL || Universe::is_narrow_oop_base(val)) { + // Ignore NULL oops and decoded NULL narrow oops which + // equal to Universe::narrow_oop_base when a narrow oop + // implicit null check is used in compiled code. + // The narrow_oop_base could be NULL or be the address + // of the page below heap depending on compressed oops mode. + } else { + derived_oop_fn(base_loc, derived_loc); } oms.next(); } while (!oms.is_done()); } } - // We want coop, value and oop oop_types + // We want narrowoop and oop oop_types int mask = OopMapValue::oop_value | OopMapValue::narrowoop_value; { for (OopMapStream oms(map,mask); !oms.is_done(); oms.next()) { omv = oms.current(); oop* loc = fr->oopmapreg_to_location(omv.reg(),reg_map); - if ( loc != NULL ) { - if ( omv.type() == OopMapValue::oop_value ) { - oop val = *loc; - if (val == (oop)NULL || Universe::is_narrow_oop_base(val)) { - // Ignore NULL oops and decoded NULL narrow oops which - // equal to Universe::narrow_oop_base when a narrow oop - // implicit null check is used in compiled code. - // The narrow_oop_base could be NULL or be the address - // of the page below heap depending on compressed oops mode. - continue; - } + // It should be an error if no location can be found for a + // register mentioned as contained an oop of some kind. Maybe + // this was allowed previously because value_value items might + // be missing? + guarantee(loc != NULL, "missing saved register"); + if ( omv.type() == OopMapValue::oop_value ) { + oop val = *loc; + if (val == (oop)NULL || Universe::is_narrow_oop_base(val)) { + // Ignore NULL oops and decoded NULL narrow oops which + // equal to Universe::narrow_oop_base when a narrow oop + // implicit null check is used in compiled code. + // The narrow_oop_base could be NULL or be the address + // of the page below heap depending on compressed oops mode. + continue; + } #ifdef ASSERT - if ((((uintptr_t)loc & (sizeof(*loc)-1)) != 0) || - !Universe::heap()->is_in_or_null(*loc)) { - tty->print_cr("# Found non oop pointer. Dumping state at failure"); - // try to dump out some helpful debugging information - trace_codeblob_maps(fr, reg_map); - omv.print(); - tty->print_cr("register r"); - omv.reg()->print(); - tty->print_cr("loc = %p *loc = %p\n", loc, (address)*loc); - // do the real assert. - assert(Universe::heap()->is_in_or_null(*loc), "found non oop pointer"); - } + if ((((uintptr_t)loc & (sizeof(*loc)-1)) != 0) || + !Universe::heap()->is_in_or_null(*loc)) { + tty->print_cr("# Found non oop pointer. Dumping state at failure"); + // try to dump out some helpful debugging information + trace_codeblob_maps(fr, reg_map); + omv.print(); + tty->print_cr("register r"); + omv.reg()->print(); + tty->print_cr("loc = %p *loc = %p\n", loc, (address)*loc); + // do the real assert. + assert(Universe::heap()->is_in_or_null(*loc), "found non oop pointer"); + } #endif // ASSERT - oop_fn->do_oop(loc); - } else if ( omv.type() == OopMapValue::narrowoop_value ) { - narrowOop *nl = (narrowOop*)loc; + oop_fn->do_oop(loc); + } else if ( omv.type() == OopMapValue::narrowoop_value ) { + narrowOop *nl = (narrowOop*)loc; #ifndef VM_LITTLE_ENDIAN - if (!omv.reg()->is_stack()) { - // compressed oops in registers only take up 4 bytes of an - // 8 byte register but they are in the wrong part of the - // word so adjust loc to point at the right place. - nl = (narrowOop*)((address)nl + 4); - } + if (!omv.reg()->is_stack()) { + // compressed oops in registers only take up 4 bytes of an + // 8 byte register but they are in the wrong part of the + // word so adjust loc to point at the right place. + nl = (narrowOop*)((address)nl + 4); + } #endif - oop_fn->do_oop(nl); - } + oop_fn->do_oop(nl); } } } diff -r 92fc95e8667d -r 23d6b95bd687 src/share/vm/graal/graalEnv.cpp --- a/src/share/vm/graal/graalEnv.cpp Wed Apr 15 10:09:13 2015 -0700 +++ b/src/share/vm/graal/graalEnv.cpp Wed Apr 15 11:03:04 2015 -0700 @@ -546,6 +546,12 @@ } } else { nm->set_has_unsafe_access(has_unsafe_access); +#ifdef TARGET_ARCH_x86 + // It might be preferable to set this only for methods which + // use vector instructions but we currently don't track this + // and it probably wouldn't make much difference. + nm->set_has_wide_vectors(UseAVX >= 2); +#endif // Record successful registration. // (Put nm into the task handle *before* publishing to the Java heap.) diff -r 92fc95e8667d -r 23d6b95bd687 src/share/vm/runtime/sharedRuntime.cpp --- a/src/share/vm/runtime/sharedRuntime.cpp Wed Apr 15 10:09:13 2015 -0700 +++ b/src/share/vm/runtime/sharedRuntime.cpp Wed Apr 15 11:03:04 2015 -0700 @@ -111,9 +111,14 @@ _resolve_virtual_call_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::resolve_virtual_call_C), "resolve_virtual_call"); _resolve_static_call_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::resolve_static_call_C), "resolve_static_call"); +#if defined(COMPILER2) || defined(GRAAL) + // Vectors are generated only by C2 and Graal. #ifdef COMPILER2 - // Vectors are generated only by C2. - if (is_wide_vector(MaxVectorSize)) { + bool support_wide = is_wide_vector(MaxVectorSize) || IS_GRAAL_DEFINED; +#else + bool support_wide = true; +#endif + if (support_wide) { _polling_page_vectors_safepoint_handler_blob = generate_handler_blob(CAST_FROM_FN_PTR(address, SafepointSynchronize::handle_polling_page_exception), POLL_AT_VECTOR_LOOP); } #endif // COMPILER2