changeset 22517:60c68f691534

Fix assumptions should always be checked before guards to ensure they are removed if they are not needed anymore.
author Christian Humer <christian.humer@oracle.com>
date Fri, 18 Dec 2015 15:14:10 +0100
parents 687bc1dda125
children 72809fce725f
files truffle/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/AssumptionsTest.java truffle/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java
diffstat 2 files changed, 42 insertions(+), 31 deletions(-) [+]
line wrap: on
line diff
--- a/truffle/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/AssumptionsTest.java	Fri Dec 18 14:41:06 2015 +0100
+++ b/truffle/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/AssumptionsTest.java	Fri Dec 18 15:14:10 2015 +0100
@@ -30,7 +30,6 @@
 import java.util.HashMap;
 import java.util.Map;
 
-import org.junit.Ignore;
 import org.junit.Test;
 
 import com.oracle.truffle.api.Assumption;
@@ -323,7 +322,6 @@
 
     }
 
-    @Ignore
     @Test
     public void testAssumptionRemovesSpecializationBefore() {
         // This only test if a specialization on the chain before the matching one is removed.
--- a/truffle/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java	Fri Dec 18 14:41:06 2015 +0100
+++ b/truffle/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java	Fri Dec 18 15:14:10 2015 +0100
@@ -802,7 +802,7 @@
             }
         };
 
-        builder.tree(createGuardAndCast(group, genericType, currentLocals, executionFactory));
+        builder.tree(createGuardAndCast(builder, group, null, currentLocals, executionFactory));
         builder.returnFalse();
         return method;
     }
@@ -928,7 +928,7 @@
 
         CodeTreeBuilder builder = method.createBuilder();
         SpecializationGroup group = createSpecializationGroups();
-        CodeTree execution = createGuardAndCast(group, genericType, locals, new SpecializationBody(false, false) {
+        CodeTree execution = createGuardAndCast(builder, group, null, locals, new SpecializationBody(false, false) {
             @Override
             public CodeTree createBody(SpecializationData specialization, LocalContext values) {
                 CodeTypeElement generatedType = specializationClasses.get(specialization);
@@ -1631,8 +1631,8 @@
         return builder.build();
     }
 
-    private CodeTree createCallDelegate(String methodName, String reason, ExecutableTypeData forType, LocalContext currentValues) {
-        CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
+    private CodeTree createCallDelegate(CodeTreeBuilder parent, String methodName, String reason, ExecutableTypeData forType, LocalContext currentValues) {
+        CodeTreeBuilder builder = parent.create();
         builder.startCall(methodName);
         if (reason != null) {
             builder.doubleQuote(reason);
@@ -1860,7 +1860,7 @@
         } else if (specialization.isPolymorphic()) {
             builder.tree(createCallNext(builder, executableType, node.getGenericExecutableType(executableType), currentLocals));
         } else if (specialization.isUninitialized()) {
-            builder.startReturn().tree(createCallDelegate("uninitialized", null, executableType, currentLocals)).end();
+            builder.startReturn().tree(createCallDelegate(builder, "uninitialized", null, executableType, currentLocals)).end();
         } else {
             SpecializationGroup group = SpecializationGroup.create(specialization);
             SpecializationBody executionFactory = new SpecializationBody(true, true) {
@@ -1869,7 +1869,7 @@
                     return createFastPathExecute(builder, executableType, s, values);
                 }
             };
-            builder.tree(createGuardAndCast(group, returnType, currentLocals, executionFactory));
+            builder.tree(createGuardAndCast(builder, group, executableType, currentLocals, executionFactory));
             if (hasFallthrough(group, returnType, originalValues, true, null) || group.getSpecialization().isFallback()) {
                 builder.tree(createCallNext(builder, executableType, node.getGenericExecutableType(executableType), originalValues));
             }
@@ -2005,26 +2005,6 @@
         }
         CodeTreeBuilder execute = builder.create();
 
-        if (!specialization.getAssumptionExpressions().isEmpty()) {
-            builder.startTryBlock();
-            for (AssumptionExpression assumption : specialization.getAssumptionExpressions()) {
-                LocalVariable assumptionVar = currentValues.get(assumptionName(assumption));
-                if (assumptionVar == null) {
-                    throw new AssertionError("Could not resolve assumption var " + currentValues);
-                }
-                builder.startStatement().startCall("check").tree(assumptionVar.createReference()).end().end();
-            }
-            builder.end().startCatchBlock(getType(InvalidAssumptionException.class), "ae");
-            builder.startReturn();
-            List<String> assumptionIds = new ArrayList<>();
-            for (AssumptionExpression assumption : specialization.getAssumptionExpressions()) {
-                assumptionIds.add(assumption.getId());
-            }
-            builder.tree(createCallDelegate("removeThis", String.format("Assumption %s invalidated", assumptionIds), forType, currentValues));
-            builder.end();
-            builder.end();
-        }
-
         if (specialization.getMethod() == null) {
             execute.startReturn();
             execute.startCall("unsupported");
@@ -2055,8 +2035,8 @@
         return builder.build();
     }
 
-    private CodeTree createGuardAndCast(SpecializationGroup group, TypeMirror forType, LocalContext currentValues, SpecializationBody execution) {
-        CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
+    private CodeTree createGuardAndCast(CodeTreeBuilder parent, SpecializationGroup group, ExecutableTypeData forType, LocalContext currentValues, SpecializationBody execution) {
+        CodeTreeBuilder builder = parent.create();
 
         Set<TypeGuard> castGuards;
         if (execution.needsCastedValues()) {
@@ -2071,6 +2051,14 @@
         }
 
         SpecializationData specialization = group.getSpecialization();
+
+        CodeTree assumptionChecks = null;
+        if (specialization != null && execution.isFastPath() && forType != null) {
+            if (!specialization.getAssumptionExpressions().isEmpty()) {
+                assumptionChecks = createFastPathAssumptionCheck(builder, specialization, forType, currentValues);
+            }
+        }
+
         CodeTree[] checkAndCast = createTypeCheckAndLocals(specialization, group.getTypeGuards(), castGuards, currentValues, execution);
 
         CodeTree check = checkAndCast[0];
@@ -2083,6 +2071,9 @@
         CodeTree methodGuards = methodGuardAndAssertions[0];
         CodeTree guardAssertions = methodGuardAndAssertions[1];
 
+        if (assumptionChecks != null) {
+            builder.tree(assumptionChecks);
+        }
         int ifCount = 0;
         if (!check.isEmpty()) {
             builder.startIf();
@@ -2110,7 +2101,7 @@
         boolean reachable = isReachableGroup(group, ifCount);
         if (reachable) {
             for (SpecializationGroup child : group.getChildren()) {
-                builder.tree(createGuardAndCast(child, forType, currentValues.copy(), execution));
+                builder.tree(createGuardAndCast(builder, child, forType, currentValues.copy(), execution));
             }
             if (specialization != null) {
                 builder.tree(execution.createBody(specialization, currentValues));
@@ -2121,6 +2112,28 @@
         return builder.build();
     }
 
+    private CodeTree createFastPathAssumptionCheck(CodeTreeBuilder parent, SpecializationData specialization, ExecutableTypeData forType, LocalContext currentValues) throws AssertionError {
+        CodeTreeBuilder builder = parent.create();
+        builder.startTryBlock();
+        for (AssumptionExpression assumption : specialization.getAssumptionExpressions()) {
+            LocalVariable assumptionVar = currentValues.get(assumptionName(assumption));
+            if (assumptionVar == null) {
+                throw new AssertionError("Could not resolve assumption var " + currentValues);
+            }
+            builder.startStatement().startCall("check").tree(assumptionVar.createReference()).end().end();
+        }
+        builder.end().startCatchBlock(getType(InvalidAssumptionException.class), "ae");
+        builder.startReturn();
+        List<String> assumptionIds = new ArrayList<>();
+        for (AssumptionExpression assumption : specialization.getAssumptionExpressions()) {
+            assumptionIds.add(assumption.getId());
+        }
+        builder.tree(createCallDelegate(builder, "removeThis", String.format("Assumption %s invalidated", assumptionIds), forType, currentValues));
+        builder.end();
+        builder.end();
+        return builder.build();
+    }
+
     private static boolean isReachableGroup(SpecializationGroup group, int ifCount) {
         if (ifCount != 0) {
             return true;