# HG changeset patch # User Christian Humer # Date 1366818255 -7200 # Node ID 2a4b57f02fb41aa5cd44c0ec604090b19de62501 # Parent a9cfbe03d9c4d880c6c532194378af45833472a1 Implemented basic support for assumptions for sourcecode generation. diff -r a9cfbe03d9c4 -r 2a4b57f02fb4 graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/AssumptionsTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/AssumptionsTest.java Wed Apr 24 17:44:15 2013 +0200 @@ -0,0 +1,139 @@ +/* + * 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.api.codegen.test; + +import org.junit.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.codegen.*; +import com.oracle.truffle.api.codegen.test.AssumptionsTestFactory.DerivedAssumptionNodeFactory; +import com.oracle.truffle.api.codegen.test.AssumptionsTestFactory.DerivedAssumptionRedeclaredNodeFactory; +import com.oracle.truffle.api.codegen.test.AssumptionsTestFactory.MultipleAssumptionsNodeFactory; +import com.oracle.truffle.api.codegen.test.AssumptionsTestFactory.SingleAssumptionNodeFactory; +import com.oracle.truffle.api.codegen.test.TypeSystemTest.TestRootNode; +import com.oracle.truffle.api.codegen.test.TypeSystemTest.ValueNode; + +public class AssumptionsTest { + + @Test + public void testSingleAssumption() { + Assumption assumption = Truffle.getRuntime().createAssumption(); + TestRootNode root = TestHelper.create(SingleAssumptionNodeFactory.getInstance(), assumption); + + Assert.assertEquals(42, TestHelper.executeWith(root)); + assumption.invalidate(); + Assert.assertEquals("42", TestHelper.executeWith(root)); + } + + @NodeAssumptions("assumption") + abstract static class SingleAssumptionNode extends ValueNode { + + @Specialization(order = 0, assumptions = "assumption") + int doInt() { + return 42; + } + + @Specialization + Object doObject() { + return "42"; + } + } + + @Test + public void testMultipleAssumption() { + Assumption assumption1 = Truffle.getRuntime().createAssumption(); + Assumption assumption2 = Truffle.getRuntime().createAssumption(); + TestRootNode root = TestHelper.create(MultipleAssumptionsNodeFactory.getInstance(), assumption1, assumption2); + + Assert.assertEquals(42, TestHelper.executeWith(root)); + assumption2.invalidate(); + Assert.assertEquals("42", TestHelper.executeWith(root)); + assumption1.invalidate(); + Assert.assertEquals("43", TestHelper.executeWith(root)); + } + + @NodeAssumptions({"assumption1", "assumption2"}) + abstract static class MultipleAssumptionsNode extends ValueNode { + + @Specialization(assumptions = {"assumption1", "assumption2"}) + int doInt() { + return 42; + } + + @Specialization(assumptions = "assumption1") + Object doObject() { + return "42"; + } + + @Generic + Object doGeneric() { + return "43"; + } + } + + @Test + public void testDerivedAssumption() { + Assumption additionalAssumption = Truffle.getRuntime().createAssumption(); + Assumption assumption = Truffle.getRuntime().createAssumption(); + TestRootNode root = TestHelper.create(DerivedAssumptionNodeFactory.getInstance(), assumption, additionalAssumption); + + Assert.assertEquals(42, TestHelper.executeWith(root)); + assumption.invalidate(); + Assert.assertEquals(43, TestHelper.executeWith(root)); + additionalAssumption.invalidate(); + Assert.assertEquals("42", TestHelper.executeWith(root)); + } + + @NodeAssumptions({"additionalAssumption"}) + abstract static class DerivedAssumptionNode extends SingleAssumptionNode { + + @Specialization(order = 1, assumptions = "additionalAssumption") + int doIntDerived() { + return 43; + } + } + + @Test + public void testDerivedAssumptionRedeclared() { + Assumption additionalAssumption = Truffle.getRuntime().createAssumption(); + Assumption assumption = Truffle.getRuntime().createAssumption(); + TestRootNode root = TestHelper.create(DerivedAssumptionRedeclaredNodeFactory.getInstance(), additionalAssumption, assumption); + + Assert.assertEquals(42, TestHelper.executeWith(root)); + assumption.invalidate(); + Assert.assertEquals(43, TestHelper.executeWith(root)); + additionalAssumption.invalidate(); + Assert.assertEquals("42", TestHelper.executeWith(root)); + } + + @NodeAssumptions({"additionalAssumption", "assumption"}) + abstract static class DerivedAssumptionRedeclaredNode extends SingleAssumptionNode { + + @Specialization(order = 1, assumptions = "additionalAssumption") + int doIntDerived() { + return 43; + } + + } + +} diff -r a9cfbe03d9c4 -r 2a4b57f02fb4 graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeAssumptions.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeAssumptions.java Wed Apr 24 17:44:15 2013 +0200 @@ -0,0 +1,38 @@ +/* + * 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.api.codegen; + +import java.lang.annotation.*; + +/** + * Declares one or multiple assumptions for use inside a source code generation enabled node. + * Declared assumptions must be passed to the {@link NodeFactory#createNode(Object...)} method as + * parameters. + */ +@Retention(RetentionPolicy.CLASS) +@Target({ElementType.TYPE}) +public @interface NodeAssumptions { + + String[] value(); + +} diff -r a9cfbe03d9c4 -r 2a4b57f02fb4 graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/Specialization.java --- a/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/Specialization.java Tue Apr 23 21:03:47 2013 +0200 +++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/Specialization.java Wed Apr 24 17:44:15 2013 +0200 @@ -36,4 +36,11 @@ String[] guards() default {}; + /** + * Defines the assumptions to check for this specialization. When the specialization method is + * invoked it is guaranteed that the assigned assumptions still hold. To declare assumptions use + * the {@link NodeAssumptions} annotation at class level. + */ + String[] assumptions() default {}; + } diff -r a9cfbe03d9c4 -r 2a4b57f02fb4 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleTypes.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleTypes.java Tue Apr 23 21:03:47 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleTypes.java Wed Apr 24 17:44:15 2013 +0200 @@ -43,6 +43,8 @@ private final TypeMirror nodeArray; private final TypeMirror unexpectedValueException; private final TypeMirror frame; + private final TypeMirror assumption; + private final TypeMirror invalidAssumption; private final DeclaredType childAnnotation; private final DeclaredType childrenAnnotation; private final TypeMirror compilerDirectives; @@ -57,6 +59,8 @@ childAnnotation = getRequired(context, Child.class); childrenAnnotation = getRequired(context, Children.class); compilerDirectives = getRequired(context, CompilerDirectives.class); + assumption = getRequired(context, Assumption.class); + invalidAssumption = getRequired(context, InvalidAssumptionException.class); } public boolean verify(ProcessorContext context, Element element, AnnotationMirror mirror) { @@ -79,6 +83,14 @@ return (DeclaredType) type; } + public TypeMirror getInvalidAssumption() { + return invalidAssumption; + } + + public TypeMirror getAssumption() { + return assumption; + } + public TypeMirror getCompilerDirectives() { return compilerDirectives; } diff -r a9cfbe03d9c4 -r 2a4b57f02fb4 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java Tue Apr 23 21:03:47 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java Wed Apr 24 17:44:15 2013 +0200 @@ -289,11 +289,11 @@ } private CodeTree createGuardAndCast(CodeTreeBuilder parent, String conditionPrefix, SpecializationData sourceSpecialization, SpecializationData targetSpecialization, boolean castValues, - CodeTree guardedStatements, CodeTree elseStatements) { + CodeTree guardedStatements, CodeTree elseStatements, boolean emitAssumptions) { NodeData node = targetSpecialization.getNode(); CodeTreeBuilder builder = new CodeTreeBuilder(parent); - CodeTree implicitGuards = createImplicitGuards(parent, conditionPrefix, sourceSpecialization, targetSpecialization); + CodeTree implicitGuards = createImplicitGuards(parent, conditionPrefix, sourceSpecialization, targetSpecialization, emitAssumptions); CodeTree explicitGuards = createExplicitGuards(parent, implicitGuards == null ? conditionPrefix : null, sourceSpecialization, targetSpecialization); Set valuesNeedsCast; @@ -392,10 +392,26 @@ return builder.getRoot(); } - private CodeTree createImplicitGuards(CodeTreeBuilder parent, String conditionPrefix, SpecializationData valueSpecialization, SpecializationData guardedSpecialization) { + private CodeTree createImplicitGuards(CodeTreeBuilder parent, String conditionPrefix, SpecializationData valueSpecialization, SpecializationData guardedSpecialization, boolean emitAssumptions) { CodeTreeBuilder builder = new CodeTreeBuilder(parent); // Implict guards based on method signature String andOperator = conditionPrefix != null ? conditionPrefix + " && " : ""; + + if (emitAssumptions) { + boolean isStatic = parent.findMethod().getModifiers().contains(STATIC); + + for (String assumption : guardedSpecialization.getAssumptions()) { + builder.string(andOperator); + if (isStatic) { + builder.string(THIS_NODE_LOCAL_VAR_NAME); + } else { + builder.string("this"); + } + builder.string(".").string(assumption).string(".isValid()"); + andOperator = " && "; + } + } + for (ActualParameter guardedParam : guardedSpecialization.getParameters()) { NodeChildData field = guardedSpecialization.getNode().findChild(guardedParam.getSpecification().getName()); if (field == null) { @@ -528,6 +544,19 @@ return constructors; } + private static ExecutableElement findCopyConstructor(TypeMirror type) { + for (ExecutableElement constructor : ElementFilter.constructorsIn(Utils.fromTypeMirror(type).getEnclosedElements())) { + if (constructor.getModifiers().contains(PRIVATE)) { + continue; + } + if (isCopyConstructor(constructor)) { + return constructor; + } + } + + return null; + } + private static boolean isCopyConstructor(ExecutableElement element) { if (element.getParameters().size() != 1) { return false; @@ -578,6 +607,10 @@ } } + for (String assumption : node.getAssumptions()) { + clazz.add(createAssumptionField(assumption)); + } + createConstructors(node, clazz); if (node.getExtensionElements() != null) { @@ -588,93 +621,88 @@ } private void createConstructors(NodeData node, CodeTypeElement clazz) { - List signatureConstructors = new ArrayList<>(); - ExecutableElement copyConstructor = null; - List constructors = ElementFilter.constructorsIn(Utils.fromTypeMirror(node.getNodeType()).getEnclosedElements()); - for (ExecutableElement constructor : constructors) { - if (constructor.getModifiers().contains(Modifier.PRIVATE) || constructor.getParameters().isEmpty()) { - continue; + List constructors = findUserConstructors(node.getNodeType()); + if (constructors.isEmpty()) { + clazz.add(createUserConstructor(clazz, null)); + } else { + for (ExecutableElement constructor : constructors) { + clazz.add(createUserConstructor(clazz, constructor)); } + } + clazz.add(createCopyConstructor(clazz, findCopyConstructor(node.getNodeType()))); + } - if (isCopyConstructor(constructor)) { - assert copyConstructor == null; - copyConstructor = createConstructor(clazz, constructor, true); - } else { - signatureConstructors.add(createConstructor(clazz, constructor, false)); + private CodeExecutableElement createUserConstructor(CodeTypeElement type, ExecutableElement superConstructor) { + CodeExecutableElement method = new CodeExecutableElement(null, type.getSimpleName().toString()); + CodeTreeBuilder builder = method.createBuilder(); + + if (superConstructor != null) { + for (VariableElement param : superConstructor.getParameters()) { + method.getParameters().add(CodeVariableElement.clone(param)); } } - if (copyConstructor == null && node.needsRewrites(getContext())) { - clazz.add(createConstructor(clazz, null, true)); - } else if (copyConstructor != null) { - clazz.add(copyConstructor); - } - - if (signatureConstructors.isEmpty() && !node.getChildren().isEmpty()) { - clazz.add(createConstructor(clazz, null, false)); - } else { - clazz.getEnclosedElements().addAll(signatureConstructors); - } - } - - private CodeExecutableElement createConstructor(CodeTypeElement type, ExecutableElement superConstructor, boolean copyConstructor) { - CodeExecutableElement method = new CodeExecutableElement(null, type.getSimpleName().toString()); - CodeTreeBuilder builder = method.createBuilder(); - if (!copyConstructor) { - if (superConstructor != null) { - for (VariableElement param : superConstructor.getParameters()) { - method.getParameters().add(CodeVariableElement.clone(param)); - } - } - for (NodeChildData child : getModel().getChildren()) { - method.getParameters().add(new CodeVariableElement(child.getNodeType(), child.getName())); - } - } else { - if (!(superConstructor == null && getModel().getChildren().isEmpty())) { - method.getParameters().add(new CodeVariableElement(type.asType(), "copy")); - } + for (VariableElement var : type.getFields()) { + method.getParameters().add(new CodeVariableElement(var.asType(), var.getSimpleName().toString())); } if (superConstructor != null) { - builder.startStatement(); - builder.startSuperCall(); - if (copyConstructor) { - builder.string("copy"); - } else { - for (VariableElement param : superConstructor.getParameters()) { - builder.string(param.getSimpleName().toString()); - } + builder.startStatement().startSuperCall(); + for (VariableElement param : superConstructor.getParameters()) { + builder.string(param.getSimpleName().toString()); } - builder.end(); - builder.end(); + builder.end().end(); } - for (NodeChildData child : getModel().getChildren()) { - + for (VariableElement var : type.getFields()) { builder.startStatement(); - builder.string("this.").string(child.getName()).string(" = "); - - if (child.getCardinality() == Cardinality.MANY) { - builder.startCall("adoptChildren"); + String varName = var.getSimpleName().toString(); + builder.string("this.").string(varName); + if (Utils.isAssignable(getContext(), var.asType(), getContext().getTruffleTypes().getNode())) { + builder.string(" = adoptChild(").string(varName).string(")"); + } else if (Utils.isAssignable(getContext(), var.asType(), getContext().getTruffleTypes().getNodeArray())) { + builder.string(" = adoptChildren(").string(varName).string(")"); } else { - builder.startCall("adoptChild"); + builder.string(" = ").string(varName); } + builder.end(); + } + return method; + } - builder.startGroup(); - if (copyConstructor) { - builder.string("copy."); - } - builder.string(child.getName()); - builder.end(); - - builder.end(); - builder.end(); - + private CodeExecutableElement createCopyConstructor(CodeTypeElement type, ExecutableElement superConstructor) { + CodeExecutableElement method = new CodeExecutableElement(null, type.getSimpleName().toString()); + CodeTreeBuilder builder = method.createBuilder(); + if (!(superConstructor == null && type.getFields().isEmpty())) { + method.getParameters().add(new CodeVariableElement(type.asType(), "copy")); } + if (superConstructor != null) { + builder.startStatement().startSuperCall().string("copy").end().end(); + } + + for (VariableElement var : type.getFields()) { + builder.startStatement(); + String varName = var.getSimpleName().toString(); + builder.string("this.").string(varName); + if (Utils.isAssignable(getContext(), var.asType(), getContext().getTruffleTypes().getNode())) { + builder.string(" = adoptChild(copy.").string(varName).string(")"); + } else if (Utils.isAssignable(getContext(), var.asType(), getContext().getTruffleTypes().getNodeArray())) { + builder.string(" = adoptChildren(copy.").string(varName).string(")"); + } else { + builder.string(" = copy.").string(varName); + } + builder.end(); + } return method; } + private CodeVariableElement createAssumptionField(String assumption) { + CodeVariableElement var = new CodeVariableElement(getContext().getTruffleTypes().getAssumption(), assumption); + var.getModifiers().add(Modifier.FINAL); + return var; + } + private CodeVariableElement createChildField(NodeChildData child) { CodeVariableElement var = new CodeVariableElement(child.getNodeType(), child.getName()); var.getModifiers().add(Modifier.PROTECTED); @@ -728,11 +756,8 @@ createFactoryMethods(node, clazz, createVisibility); - if (node.getSpecializations().size() > 1) { + if (node.needsRewrites(context)) { clazz.add(createCreateSpecializedMethod(node, createVisibility)); - } - - if (node.needsRewrites(context)) { clazz.add(createSpecializeMethod(node)); } @@ -912,7 +937,7 @@ private CodeExecutableElement createCreateNodeSpecializedMethod(NodeData node) { CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), node.getNodeType(), "createNodeSpecialized"); - CodeVariableElement nodeParam = new CodeVariableElement(node.getNodeType(), "thisNode"); + CodeVariableElement nodeParam = new CodeVariableElement(node.getNodeType(), THIS_NODE_LOCAL_VAR_NAME); CodeVariableElement arguments = new CodeVariableElement(getContext().getType(Class.class), "types"); method.addParameter(nodeParam); method.addParameter(arguments); @@ -928,7 +953,9 @@ builder.startBlock(); builder.startReturn().startCall("createSpecialized"); - builder.string("thisNode"); + builder.startGroup(); + builder.string(THIS_NODE_LOCAL_VAR_NAME); + builder.end(); builder.string("types[0]"); builder.end().end(); @@ -1085,10 +1112,16 @@ CodeTreeBuilder body = method.createBuilder(); - body.startStatement(); - body.type(generatedNode.asType()).string(" ").string(THIS_NODE_LOCAL_VAR_NAME + "Cast"); - body.string(" = ").string("(").type(generatedNode.asType()).string(") ").string(THIS_NODE_LOCAL_VAR_NAME); - body.end(); + boolean hasCopyConstructor = findCopyConstructor(generatedNode.asType()) != null; + + final String thisLocalVariableName = THIS_NODE_LOCAL_VAR_NAME + "Cast"; + + if (hasCopyConstructor) { + body.startStatement(); + body.type(generatedNode.asType()).string(" ").string(thisLocalVariableName); + body.string(" = ").string("(").type(generatedNode.asType()).string(") ").string(THIS_NODE_LOCAL_VAR_NAME); + body.end(); + } boolean first = true; for (TypeData type : node.getTypeSystem().getTypes()) { @@ -1101,16 +1134,12 @@ body.startElseIf(); } body.string("specializationClass == ").type(type.getBoxedType()).string(".class").end().startBlock(); - body.startReturn().startNew(nodeSpecializationClassName(specialization)); - body.string(THIS_NODE_LOCAL_VAR_NAME + "Cast"); - body.end().end(); // new, return + body.tree(createReturnNewSpecialization(body, specialization, thisLocalVariableName, hasCopyConstructor)); body.end(); // if } } - body.startReturn().startNew(nodeSpecializationClassName(node.getGenericSpecialization())); - body.string(THIS_NODE_LOCAL_VAR_NAME + "Cast"); - body.end().end(); + body.tree(createReturnNewSpecialization(body, node.getGenericSpecialization(), thisLocalVariableName, hasCopyConstructor)); return method; } @@ -1123,22 +1152,31 @@ CodeTreeBuilder body = method.createBuilder(); body.startStatement().string("boolean allowed = (minimumState == ").string(nodeSpecializationClassName(node.getSpecializations().get(0))).string(".class)").end(); + boolean hasCopyConstructor = findCopyConstructor(generatedNode.asType()) != null; + for (int i = 1; i < node.getSpecializations().size(); i++) { SpecializationData specialization = node.getSpecializations().get(i); body.startStatement().string("allowed = allowed || (minimumState == ").string(nodeSpecializationClassName(specialization)).string(".class)").end(); - CodeTreeBuilder guarded = new CodeTreeBuilder(body); - guarded.startReturn().startNew(nodeSpecializationClassName(specialization)); - guarded.string(THIS_NODE_LOCAL_VAR_NAME); - guarded.end().end(); + CodeTree guarded = createReturnNewSpecialization(body, specialization, THIS_NODE_LOCAL_VAR_NAME, hasCopyConstructor); - body.tree(createGuardAndCast(body, "allowed", node.getGenericSpecialization(), specialization, false, guarded.getRoot(), null)); + body.tree(createGuardAndCast(body, "allowed", node.getGenericSpecialization(), specialization, false, guarded, null, true)); } body.startThrow().startNew(getContext().getType(IllegalArgumentException.class)).end().end(); return method; } + private CodeTree createReturnNewSpecialization(CodeTreeBuilder parent, SpecializationData specialization, String thisLocalVariableName, boolean hasCopyConstructor) { + CodeTreeBuilder builder = new CodeTreeBuilder(parent); + builder.startReturn().startNew(nodeSpecializationClassName(specialization)); + if (hasCopyConstructor) { + builder.string(thisLocalVariableName); + } + builder.end().end(); + return builder.getRoot(); + } + private List createGeneratedGenericMethod(NodeData node) { TypeMirror genericReturnType = node.getGenericSpecialization().getReturnType().getType(); if (node.needsRewrites(context)) { @@ -1155,7 +1193,7 @@ } else { String methodName = generatedGenericMethodName(current); CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE, STATIC), genericReturnType, methodName); - method.addParameter(new CodeVariableElement(node.getNodeType(), THIS_NODE_LOCAL_VAR_NAME)); + method.addParameter(new CodeVariableElement(generatedNode.asType(), THIS_NODE_LOCAL_VAR_NAME)); addInternalValueParameters(method, node.getGenericSpecialization(), true); emitGeneratedGenericSpecialization(method.createBuilder(), current, next); @@ -1168,7 +1206,7 @@ return methods; } else { CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE, STATIC), genericReturnType, generatedGenericMethodName(null)); - method.addParameter(new CodeVariableElement(node.getNodeType(), THIS_NODE_LOCAL_VAR_NAME)); + method.addParameter(new CodeVariableElement(generatedNode.asType(), THIS_NODE_LOCAL_VAR_NAME)); addInternalValueParameters(method, node.getGenericSpecialization(), true); emitInvokeDoMethod(method.createBuilder(), node.getGenericSpecialization(), 0); return Arrays.asList(method); @@ -1188,7 +1226,7 @@ addInternalValueParameterNames(nextBuilder, next, next, null, true, true); nextBuilder.end().end(); - invokeMethod = createGuardAndCast(builder, null, current.getNode().getGenericSpecialization(), current, true, invokeMethod, nextBuilder.getRoot()); + invokeMethod = createGuardAndCast(builder, null, current.getNode().getGenericSpecialization(), current, true, invokeMethod, nextBuilder.getRoot(), true); } builder.tree(invokeMethod); @@ -1274,7 +1312,7 @@ } } - if (node.needsRewrites(getContext()) && !specialization.isGeneric() && !specialization.isUninitialized()) { + if (specialization.hasRewrite(getContext())) { buildSpecializeAndExecute(clazz, specialization); } } @@ -1469,7 +1507,7 @@ if (next != null) { returnSpecialized = createReturnSpecializeAndExecute(builder, executable, next, null); } - builder.tree(createGuardAndCast(builder, null, specialization, specialization, true, executeNode, returnSpecialized)); + builder.tree(createGuardAndCast(builder, null, specialization, specialization, true, executeNode, returnSpecialized, false)); return builder.getRoot(); } @@ -1507,10 +1545,16 @@ private CodeTree createExecute(CodeTreeBuilder parent, ExecutableTypeData executable, SpecializationData specialization) { NodeData node = specialization.getNode(); CodeTreeBuilder builder = new CodeTreeBuilder(parent); - if (!specialization.getExceptions().isEmpty()) { + if (!specialization.getExceptions().isEmpty() || !specialization.getAssumptions().isEmpty()) { builder.startTryBlock(); } + for (String assumption : specialization.getAssumptions()) { + builder.startStatement(); + builder.string("this.").string(assumption).string(".check()"); + builder.end(); + } + CodeTreeBuilder returnBuilder = new CodeTreeBuilder(parent); if (specialization.isUninitialized()) { String genericMethodName = generatedGenericMethodName(null); @@ -1559,6 +1603,12 @@ } builder.end(); } + if (!specialization.getAssumptions().isEmpty()) { + builder.end().startCatchBlock(getContext().getTruffleTypes().getInvalidAssumption(), "ex"); + builder.tree(createReturnSpecializeAndExecute(parent, executable, specialization.findNextSpecialization(), null)); + builder.end(); + } + return builder.getRoot(); } diff -r a9cfbe03d9c4 -r 2a4b57f02fb4 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java Tue Apr 23 21:03:47 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java Wed Apr 24 17:44:15 2013 +0200 @@ -49,6 +49,7 @@ private List specializationListeners; private Map> executableTypes; private List shortCircuits; + private List assumptions; public NodeData(TypeElement type, String id) { super(type, null, null); @@ -68,6 +69,7 @@ this.shortCircuits = splitSource.shortCircuits; this.fields = splitSource.fields; this.children = splitSource.children; + this.assumptions = splitSource.assumptions; } public boolean isSplitByMethodName() { @@ -143,6 +145,14 @@ return getTemplateType().asType(); } + void setAssumptions(List assumptions) { + this.assumptions = assumptions; + } + + public List getAssumptions() { + return assumptions; + } + public boolean needsFactory() { if (specializations == null) { return false; @@ -241,6 +251,9 @@ } public List getExecutableTypes(int evaluatedCount) { + if (executableTypes == null) { + return Collections.emptyList(); + } if (evaluatedCount == -1) { List typeData = new ArrayList<>(); for (int currentEvaluationCount : executableTypes.keySet()) { @@ -304,7 +317,7 @@ break; } } - return needsRewrites; + return needsRewrites || getSpecializations().size() > 1; } public SpecializationData getGenericSpecialization() { @@ -339,6 +352,7 @@ dumpProperty(builder, indent, "fields", getChildren()); dumpProperty(builder, indent, "executableTypes", getExecutableTypes()); dumpProperty(builder, indent, "specializations", getSpecializations()); + dumpProperty(builder, indent, "assumptions", getAssumptions()); dumpProperty(builder, indent, "messages", collectMessages()); if (getDeclaredNodes().size() > 0) { builder.append(String.format("\n%s children = [", indent)); diff -r a9cfbe03d9c4 -r 2a4b57f02fb4 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java Tue Apr 23 21:03:47 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java Wed Apr 24 17:44:15 2013 +0200 @@ -562,6 +562,22 @@ splitByMethodName = Utils.getAnnotationValue(Boolean.class, nodeClass, "splitByMethodName"); } + List assumptionsList = new ArrayList<>(); + + for (int i = lookupTypes.size() - 1; i >= 0; i--) { + TypeElement type = lookupTypes.get(i); + AnnotationMirror assumptions = Utils.findAnnotationMirror(context.getEnvironment(), type, NodeAssumptions.class); + if (assumptions != null) { + List assumptionStrings = Utils.getAnnotationValueList(String.class, assumptions, "value"); + for (String string : assumptionStrings) { + if (assumptionsList.contains(string)) { + assumptionsList.remove(string); + } + assumptionsList.add(string); + } + } + } + nodeData.setAssumptions(new ArrayList<>(assumptionsList)); nodeData.setNodeType(nodeType); nodeData.setSplitByMethodName(splitByMethodName); nodeData.setTypeSystem(typeSystem); diff -r a9cfbe03d9c4 -r 2a4b57f02fb4 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java Tue Apr 23 21:03:47 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java Wed Apr 24 17:44:15 2013 +0200 @@ -36,8 +36,9 @@ private final boolean uninitialized; private final List exceptions; private List guardDefinitions = Collections.emptyList(); - private List guards; + private List guards = Collections.emptyList(); private List shortCircuits; + private List assumptions = Collections.emptyList(); private boolean useSpecializationsForGeneric = true; private NodeData node; @@ -59,7 +60,6 @@ this.generic = generic; this.uninitialized = uninitialized; this.exceptions = Collections.emptyList(); - this.guards = new ArrayList<>(); } @Override @@ -81,6 +81,9 @@ if (!getGuards().isEmpty()) { return true; } + if (!getAssumptions().isEmpty()) { + return true; + } for (ActualParameter parameter : getParameters()) { NodeChildData field = getNode().findChild(parameter.getSpecification().getName()); if (field == null) { @@ -175,6 +178,14 @@ return useSpecializationsForGeneric; } + public List getAssumptions() { + return assumptions; + } + + void setAssumptions(List assumptions) { + this.assumptions = assumptions; + } + public SpecializationData findNextSpecialization() { List specializations = node.getSpecializations(); for (int i = 0; i < specializations.size() - 1; i++) { diff -r a9cfbe03d9c4 -r 2a4b57f02fb4 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationMethodParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationMethodParser.java Tue Apr 23 21:03:47 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationMethodParser.java Wed Apr 24 17:44:15 2013 +0200 @@ -53,7 +53,7 @@ return Specialization.class; } - private static SpecializationData parseSpecialization(TemplateMethod method) { + private SpecializationData parseSpecialization(TemplateMethod method) { int order = Utils.getAnnotationValue(Integer.class, method.getMarkerAnnotation(), "order"); if (order < 0 && order != Specialization.DEFAULT_ORDER) { method.addError("Invalid order attribute %d. The value must be >= 0 or the default value."); @@ -82,7 +82,15 @@ List guardDefs = Utils.getAnnotationValueList(String.class, specialization.getMarkerAnnotation(), "guards"); specialization.setGuardDefinitions(guardDefs); + List assumptionDefs = Utils.getAnnotationValueList(String.class, specialization.getMarkerAnnotation(), "assumptions"); + specialization.setAssumptions(assumptionDefs); + + for (String assumption : assumptionDefs) { + if (!getNode().getAssumptions().contains(assumption)) { + specialization.addError("Undeclared assumption '%s' used. Use @NodeAssumptions to declare them.", assumption); + } + } + return specialization; } - }