diff graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java @ 9279:2a4b57f02fb4

Implemented basic support for assumptions for sourcecode generation.
author Christian Humer <christian.humer@gmail.com>
date Wed, 24 Apr 2013 17:44:15 +0200
parents fe5bc02fcd19
children e16363e50252
line wrap: on
line diff
--- 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<String> 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<ExecutableElement> signatureConstructors = new ArrayList<>();
-            ExecutableElement copyConstructor = null;
-            List<? extends ExecutableElement> constructors = ElementFilter.constructorsIn(Utils.fromTypeMirror(node.getNodeType()).getEnclosedElements());
-            for (ExecutableElement constructor : constructors) {
-                if (constructor.getModifiers().contains(Modifier.PRIVATE) || constructor.getParameters().isEmpty()) {
-                    continue;
+            List<ExecutableElement> 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<CodeExecutableElement> 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();
         }