diff graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java @ 19757:e8d2f3f95dcd

Truffle-DSL: implemented duplication check for specializations with @Cached to avoid duplicates for multithreaded AST execution.
author Christian Humer <christian.humer@gmail.com>
date Tue, 10 Mar 2015 19:28:26 +0100
parents d03352ba2efb
children e773cc48d3e8
line wrap: on
line diff
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java	Tue Mar 10 13:47:46 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java	Tue Mar 10 19:28:26 2015 +0100
@@ -447,6 +447,7 @@
         clazz.addOptional(createSpecializationCreateMethod(specialization, constructor));
         clazz.addOptional(createMergeMethod(specialization));
         clazz.addOptional(createIsSameMethod(specialization));
+        clazz.addOptional(createIsIdenticalMethod(specialization));
 
         TypeData returnType = specialization.getReturnType().getTypeSystemType();
         int signatureSize = specialization.getSignatureSize();
@@ -493,6 +494,36 @@
         return executable;
     }
 
+    private Element createIsIdenticalMethod(SpecializationData specialization) {
+        boolean cacheBoundGuard = specialization.hasMultipleInstances();
+        if (!cacheBoundGuard) {
+            return null;
+        }
+
+        LocalContext currentLocals = LocalContext.load(this, node.getSignatureSize(), varArgsThreshold);
+        currentLocals.loadFastPathState(specialization);
+
+        CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), getType(boolean.class), "isIdentical");
+        method.addParameter(new CodeVariableElement(getType(SpecializationNode.class), "other"));
+        currentLocals.addParametersTo(method, FRAME_VALUE);
+        method.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class)));
+        final CodeTreeBuilder builder = method.createBuilder();
+
+        SpecializationGroup group = SpecializationGroup.create(specialization);
+        SpecializationBody executionFactory = new SpecializationBody(true, false) {
+            @Override
+            public CodeTree createBody(SpecializationData s, LocalContext values) {
+                return builder.create().returnTrue().build();
+            }
+        };
+
+        builder.startIf().string("isSame(other)").end().startBlock();
+        builder.tree(createGuardAndCast(group, typeSystem.getGenericTypeData(), currentLocals, executionFactory));
+        builder.end();
+        builder.returnFalse();
+        return method;
+    }
+
     private CodeExecutableElement createIsSameMethod(SpecializationData specialization) {
         if (!specialization.isSpecialized() || !options.implicitCastOptimization().isDuplicateTail()) {
             return null;
@@ -532,18 +563,29 @@
     }
 
     private Element createMergeMethod(SpecializationData specialization) {
-        boolean cacheBoundGuard = specialization.hasMultipleInstances();
-        if (specialization.getExcludedBy().isEmpty() && !specialization.isPolymorphic() && !cacheBoundGuard) {
+        if (specialization.getExcludedBy().isEmpty() && !specialization.isPolymorphic()) {
             return null;
         }
         TypeMirror specializationNodeType = getType(SpecializationNode.class);
+        LocalContext currentLocals = LocalContext.load(this, node.getSignatureSize(), varArgsThreshold);
+
         CodeExecutableElement executable = new CodeExecutableElement(modifiers(PUBLIC), specializationNodeType, "merge");
         executable.addParameter(new CodeVariableElement(specializationNodeType, "newNode"));
+        currentLocals.addParametersTo(executable, FRAME_VALUE);
         executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class)));
         CodeTreeBuilder builder = executable.createBuilder();
 
         if (specialization.isPolymorphic()) {
-            builder.statement("return polymorphicMerge(newNode)");
+            builder.startReturn();
+            builder.startCall("polymorphicMerge");
+            builder.string("newNode");
+            builder.startCall("super", "merge");
+            builder.string("newNode");
+            currentLocals.addReferencesTo(builder, FRAME_VALUE);
+            builder.end();
+            builder.end();
+            builder.end();
+
         } else {
             boolean elseIf = false;
             for (SpecializationData containedSpecialization : specialization.getExcludedBy()) {
@@ -554,11 +596,12 @@
                 builder.statement("removeSame(\"Contained by " + containedSpecialization.createReferenceName() + "\")");
                 builder.end();
             }
-            if (cacheBoundGuard) {
-                builder.statement("return super.mergeNoSame(newNode)");
-            } else {
-                builder.statement("return super.merge(newNode)");
-            }
+            builder.startReturn();
+            builder.startCall("super", "merge");
+            builder.string("newNode");
+            currentLocals.addReferencesTo(builder, FRAME_VALUE);
+            builder.end();
+            builder.end();
         }
 
         return executable;
@@ -638,18 +681,15 @@
 
         CodeTreeBuilder builder = method.createBuilder();
         SpecializationGroup group = createSpecializationGroups();
-        CodeTree execution = createGuardAndCast(group, genericType, locals, new SpecializationExecution() {
-            public CodeTree createExecute(SpecializationData specialization, LocalContext values) {
+        CodeTree execution = createGuardAndCast(group, genericType, locals, new SpecializationBody(false, false) {
+            @Override
+            public CodeTree createBody(SpecializationData specialization, LocalContext values) {
                 CodeTypeElement generatedType = specializationClasses.get(specialization);
                 if (generatedType == null) {
                     throw new AssertionError("No generated type for " + specialization);
                 }
                 return createSlowPathExecute(specialization, values);
             }
-
-            public boolean isFastPath() {
-                return false;
-            }
         });
 
         builder.tree(execution);
@@ -1525,14 +1565,11 @@
         } else {
             final TypeData finalType = type;
             SpecializationGroup group = SpecializationGroup.create(specialization);
-            SpecializationExecution executionFactory = new SpecializationExecution() {
-                public CodeTree createExecute(SpecializationData s, LocalContext values) {
+            SpecializationBody executionFactory = new SpecializationBody(true, true) {
+                @Override
+                public CodeTree createBody(SpecializationData s, LocalContext values) {
                     return createFastPathExecute(builder, finalType, s, values);
                 }
-
-                public boolean isFastPath() {
-                    return true;
-                }
             };
             builder.tree(createGuardAndCast(group, type, currentLocals, executionFactory));
             if (hasFallthrough(group, type, originalValues, true, null) || group.getSpecialization().isFallback()) {
@@ -1621,11 +1658,11 @@
         return builder.build();
     }
 
-    private CodeTree createGuardAndCast(SpecializationGroup group, TypeData forType, LocalContext currentValues, SpecializationExecution execution) {
+    private CodeTree createGuardAndCast(SpecializationGroup group, TypeData forType, LocalContext currentValues, SpecializationBody execution) {
         CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
 
         Set<TypeGuard> castGuards;
-        if (execution.isFastPath()) {
+        if (execution.needsCastedValues()) {
             castGuards = null; // cast all
         } else {
             castGuards = new HashSet<>();
@@ -1679,7 +1716,7 @@
                 builder.tree(createGuardAndCast(child, forType, currentValues.copy(), execution));
             }
             if (specialization != null) {
-                builder.tree(execution.createExecute(specialization, currentValues));
+                builder.tree(execution.createBody(specialization, currentValues));
             }
         }
         builder.end(ifCount);
@@ -2207,7 +2244,7 @@
     }
 
     private CodeTree[] createTypeCheckAndLocals(SpecializationData specialization, List<TypeGuard> typeGuards, Set<TypeGuard> castGuards, LocalContext currentValues,
-                    SpecializationExecution specializationExecution) {
+                    SpecializationBody specializationExecution) {
         CodeTreeBuilder checksBuilder = CodeTreeBuilder.createBuilder();
         CodeTreeBuilder localsBuilder = CodeTreeBuilder.createBuilder();
         for (TypeGuard typeGuard : typeGuards) {
@@ -2635,11 +2672,25 @@
 
     }
 
-    private interface SpecializationExecution {
-
-        boolean isFastPath();
-
-        CodeTree createExecute(SpecializationData specialization, LocalContext currentValues);
+    private abstract class SpecializationBody {
+
+        private final boolean fastPath;
+        private final boolean needsCastedValues;
+
+        public SpecializationBody(boolean fastPath, boolean needsCastedValues) {
+            this.fastPath = fastPath;
+            this.needsCastedValues = needsCastedValues;
+        }
+
+        public final boolean isFastPath() {
+            return fastPath;
+        }
+
+        public final boolean needsCastedValues() {
+            return needsCastedValues;
+        }
+
+        public abstract CodeTree createBody(SpecializationData specialization, LocalContext currentValues);
 
     }