changeset 18785:93016f2f3f16

Truffle-DSL: optimize generated code for nodes with a single specialization. (GRAAL-602 #resolve)
author Christian Humer <christian.humer@gmail.com>
date Mon, 05 Jan 2015 20:23:22 +0100
parents 3c7d543d758d
children eecda5abf627
files graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ImplicitCastTest.java graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TypeSystemTest.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalOrNode.java
diffstat 4 files changed, 112 insertions(+), 49 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ImplicitCastTest.java	Mon Jan 05 20:23:22 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ImplicitCastTest.java	Mon Jan 05 20:23:22 2015 +0100
@@ -166,4 +166,15 @@
 
     }
 
+    @TypeSystem({String.class, boolean.class})
+    static class ImplicitCastError2 {
+
+        @ImplicitCast
+        @ExpectError("Target type and source type of an @ImplicitCast must not be the same type.")
+        static String castInvalid(@SuppressWarnings("unused") String value) {
+            throw new AssertionError();
+        }
+
+    }
+
 }
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TypeSystemTest.java	Mon Jan 05 20:23:22 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TypeSystemTest.java	Mon Jan 05 20:23:22 2015 +0100
@@ -183,6 +183,7 @@
 
         @Override
         public int executeInt(VirtualFrame frame) throws UnexpectedResultException {
+            invocationCount++;
             // avoid casts for some tests
             Object o = frame.getArguments()[index];
             if (o instanceof Integer) {
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java	Mon Jan 05 20:23:22 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java	Mon Jan 05 20:23:22 2015 +0100
@@ -59,6 +59,7 @@
     private final TypeSystemData typeSystem;
     private final TypeData genericType;
     private final DSLOptions options;
+    private final boolean singleSpecializable;
 
     public NodeGenFactory(ProcessorContext context, NodeData node) {
         this.context = context;
@@ -66,6 +67,7 @@
         this.typeSystem = node.getTypeSystem();
         this.genericType = typeSystem.getGenericTypeData();
         this.options = typeSystem.getOptions();
+        this.singleSpecializable = isSingleSpecializableImpl();
     }
 
     public static String nodeTypeName(NodeData node) {
@@ -85,11 +87,17 @@
     }
 
     private static String specializationTypeName(SpecializationData specialization) {
-        return specialization.getId() + "Node_";
+        String id;
+        if (specialization == null) {
+            id = "Base";
+        } else {
+            id = specialization.getId();
+        }
+        return id + "Node_";
     }
 
-    private static TypeMirror specializationType(SpecializationData specialization) {
-        return new GeneratedTypeMirror(ElementUtils.getPackageName(specialization.getNode().getTemplateType()) + "." + nodeTypeName(specialization.getNode()), specializationTypeName(specialization));
+    private TypeMirror specializationType(SpecializationData specialization) {
+        return new GeneratedTypeMirror(ElementUtils.getPackageName(node.getTemplateType()) + "." + nodeTypeName(node), specializationTypeName(specialization));
     }
 
     private static String polymorphicTypeProfileFieldName(NodeExecutionData execution) {
@@ -160,10 +168,9 @@
         }
 
         for (NodeExecutionData execution : node.getChildExecutions()) {
-            if (resolveSpecializedExecutables(execution, node.findSpecializedTypes(execution), options.polymorphicTypeBoxingElimination()).isEmpty()) {
-                continue;
+            if (!resolvePolymorphicExecutables(execution).isEmpty()) {
+                clazz.add(createNodeField(PRIVATE, getType(Class.class), polymorphicTypeProfileFieldName(execution), CompilationFinal.class));
             }
-            clazz.add(createNodeField(PRIVATE, getType(Class.class), polymorphicTypeProfileFieldName(execution), CompilationFinal.class));
         }
 
         for (SpecializationData specialization : node.getSpecializations()) {
@@ -172,7 +179,6 @@
             }
         }
 
-        clazz.add(createNodeField(PRIVATE, TypeSystemNodeFactory.nodeType(node.getTypeSystem()), specializationStartFieldName(), Child.class));
         clazz.add(createMethodGetSpecializationNode());
         clazz.add(createDeepCopyMethod());
         clazz.add(createGetCostMethod());
@@ -184,13 +190,16 @@
             }
         }
 
-        SpecializationData initialSpecialization = createSpecializations(clazz);
+        SpecializationData specializationStart = createSpecializations(clazz);
+        SpecializationData finalSpecialization = singleSpecializable ? specializationStart : null;
+
+        clazz.add(createNodeField(PRIVATE, specializationType(finalSpecialization), specializationStartFieldName(), Child.class));
 
         for (ExecutableElement constructor : ElementFilter.constructorsIn(clazz.getEnclosedElements())) {
             CodeTreeBuilder builder = ((CodeExecutableElement) constructor).appendBuilder();
             builder.startStatement();
             builder.string("this.").string(specializationStartFieldName());
-            builder.string(" = ").tree(createCallCreateMethod(initialSpecialization, "this", null));
+            builder.string(" = ").tree(createCallCreateMethod(specializationStart, "this", null));
             builder.end();
         }
 
@@ -269,7 +278,7 @@
     private SpecializationData createSpecializations(CodeTypeElement clazz) {
         List<SpecializationData> reachableSpecializations = getReachableSpecializations();
 
-        if (isSingleSpecializable(reachableSpecializations)) {
+        if (singleSpecializable) {
             SpecializationData single = reachableSpecializations.get(0);
             clazz.add(createSingleSpecialization(single));
             return single;
@@ -301,7 +310,7 @@
     // create specialization
 
     private CodeTypeElement createBaseSpecialization() {
-        CodeTypeElement clazz = createClass(node, null, modifiers(PRIVATE, ABSTRACT, STATIC), "BaseNode_", TypeSystemNodeFactory.nodeType(typeSystem));
+        CodeTypeElement clazz = createClass(node, null, modifiers(PRIVATE, ABSTRACT, STATIC), specializationTypeName(null), TypeSystemNodeFactory.nodeType(typeSystem));
 
         clazz.addOptional(createSpecializationConstructor(clazz, null, null));
         clazz.add(new CodeVariableElement(modifiers(PROTECTED, FINAL), nodeType(node), "root"));
@@ -336,13 +345,27 @@
         clazz.add(new CodeVariableElement(modifiers(PROTECTED, FINAL), nodeType(node), "root"));
         TypeData returnType = specialization.getReturnType().getTypeSystemType();
         Set<Integer> evaluatedCount = getEvaluatedCounts();
+
+        TypeData specializedType = returnType;
+        if (!isTypeBoxingEliminated(specialization)) {
+            specializedType = genericType;
+        }
+
         for (int evaluated : evaluatedCount) {
-            clazz.add(createFastPathExecuteMethod(specialization, null, evaluated));
+            if (evaluated != 0) {
+                clazz.add(createFastPathExecuteMethod(specialization, null, evaluated));
+            }
         }
-        if (isTypeBoxingEliminated(specialization)) {
-            clazz.add(createFastPathExecuteMethod(specialization, returnType, 0));
+
+        clazz.add(createFastPathExecuteMethod(specialization, specializedType, 0));
+        if (!specializedType.isGeneric()) {
+            clazz.add(createFastPathWrapExecuteMethod(genericType, returnType));
         }
-        clazz.add(createFastPathWrapExecuteMethod(genericType, null));
+
+        ExecutableTypeData voidExecutableType = node.findExecutableType(typeSystem.getVoidType(), 0);
+        if (voidExecutableType != null && isTypeBoxingOptimized(options.voidBoxingOptimization(), returnType)) {
+            clazz.add(createFastPathWrapVoidMethod(returnType));
+        }
 
         clazz.addOptional(createUnsupported());
         clazz.addOptional(createSpecializationCreateMethod(specialization, constructor));
@@ -695,11 +718,18 @@
         return method;
     }
 
-    private boolean isSingleSpecializable(List<SpecializationData> reachableSpecializations) {
+    private boolean isSingleSpecializableImpl() {
+        List<SpecializationData> reachableSpecializations = getReachableSpecializations();
         if (reachableSpecializations.size() != 1) {
             return false;
         }
-        return !reachableSpecializations.get(0).hasRewrite(context);
+        for (Parameter parameter : reachableSpecializations.get(0).getSignatureParameters()) {
+            TypeData type = parameter.getTypeSystemType();
+            if (type != null && type.hasImplicitSourceTypes()) {
+                return false;
+            }
+        }
+        return true;
     }
 
     private List<SpecializationData> getReachableSpecializations() {
@@ -1016,7 +1046,7 @@
         CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
 
         TypeMirror specializationType = specializationType(specialization);
-        if (options.useLazyClassLoading()) {
+        if (useLazyClassLoading()) {
             builder.startStaticCall(specializationType(specialization), "create");
         } else {
             builder.startNew(specializationType);
@@ -1041,20 +1071,17 @@
     }
 
     private Element createSpecializationCreateMethod(SpecializationData specialization, CodeExecutableElement constructor) {
-        if (!options.useLazyClassLoading()) {
+        if (!useLazyClassLoading()) {
             return null;
         }
 
         CodeExecutableElement executable = CodeExecutableElement.clone(context.getEnvironment(), constructor);
-
-        TypeMirror specializationType = specializationType(specialization);
-
-        executable.setReturnType(TypeSystemNodeFactory.nodeType(typeSystem));
+        executable.setReturnType(specializationType(null));
         executable.setSimpleName(CodeNames.of("create"));
         executable.getModifiers().add(STATIC);
 
         CodeTreeBuilder builder = executable.createBuilder();
-        builder.startReturn().startNew(specializationType);
+        builder.startReturn().startNew(specializationType(specialization));
         for (VariableElement parameter : executable.getParameters()) {
             builder.string(parameter.getSimpleName().toString());
         }
@@ -1062,6 +1089,10 @@
         return executable;
     }
 
+    private boolean useLazyClassLoading() {
+        return options.useLazyClassLoading() && !singleSpecializable;
+    }
+
     private static String implicitClassFieldName(NodeExecutionData execution) {
         return execution.getName() + "ImplicitType";
     }
@@ -1133,18 +1164,32 @@
 
     private CodeTree createCallNext(TypeData forType, LocalContext currentValues) {
         CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
-        builder.startCall("next", TypeSystemNodeFactory.executeName(null));
+        if (singleSpecializable) {
+            builder.startCall("unsupported");
+        } else {
+            builder.startCall("next", TypeSystemNodeFactory.executeName(null));
+        }
         currentValues.addReferencesTo(builder, FRAME_VALUE);
         builder.end();
         return TypeSystemCodeGenerator.expect(genericType, forType, builder.build());
     }
 
-    private static CodeTree createCallDelegate(String methodName, String reason, TypeData forType, LocalContext currentValues) {
+    private CodeTree createCallRemove(String reason, TypeData forType, LocalContext currentValues) {
+        CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
+        if (singleSpecializable) {
+            builder.startCall("unsupported");
+        } else {
+            builder.startCall("remove");
+            builder.doubleQuote(reason);
+        }
+        currentValues.addReferencesTo(builder, FRAME_VALUE);
+        builder.end();
+        return TypeSystemCodeGenerator.expect(genericType, forType, builder.build());
+    }
+
+    private static CodeTree createCallDelegate(String methodName, TypeData forType, LocalContext currentValues) {
         CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
         builder.startCall(methodName);
-        if (reason != null) {
-            builder.doubleQuote(reason);
-        }
         currentValues.addReferencesTo(builder, FRAME_VALUE);
         builder.end();
 
@@ -1211,11 +1256,11 @@
 
         LocalContext originalValues = currentLocals.copy();
         if (specialization == null) {
-            builder.startReturn().tree(createCallDelegate("acceptAndExecute", null, type, currentLocals)).end();
+            builder.startReturn().tree(createCallDelegate("acceptAndExecute", type, currentLocals)).end();
         } else if (specialization.isPolymorphic()) {
             builder.startReturn().tree(createCallNext(type, currentLocals)).end();
         } else if (specialization.isUninitialized()) {
-            builder.startReturn().tree(createCallDelegate("uninitialized", null, type, currentLocals)).end();
+            builder.startReturn().tree(createCallDelegate("uninitialized", type, currentLocals)).end();
         } else {
             final TypeData finalType = type;
             SpecializationGroup group = SpecializationGroup.create(specialization);
@@ -1482,10 +1527,7 @@
         if (targetType.isVoid()) {
             return false;
         } else if (targetType.isGeneric()) {
-            if (isSingleSpecializable(getReachableSpecializations())) {
-                return false;
-            }
-            return resolveSpecializedExecutables(execution, node.findSpecializedTypes(execution), options.polymorphicTypeBoxingElimination()).size() >= 1;
+            return resolvePolymorphicExecutables(execution).size() >= 1;
         } else {
             if (!isTypeBoxingOptimized(options.monomorphicTypeBoxingOptimization(), targetType)) {
                 return false;
@@ -1523,11 +1565,16 @@
         }
 
         builder.tree(createTryExecuteChild(targetValue, executeChild, shortCircuit == null, hasUnexpected));
+
+        if (shortCircuit != null) {
+            currentValues.setShortCircuitValue(execution, shortCircuit.accessWith(null));
+        }
+
         builder.end();
         if (hasUnexpected) {
             builder.startCatchBlock(getType(UnexpectedResultException.class), "ex");
+            LocalContext slowPathValues = currentValues.copy();
 
-            LocalContext slowPathValues = currentValues.copy();
             slowPathValues.setValue(execution, targetValue.makeGeneric().accessWith(CodeTreeBuilder.singleString("ex.getResult()")));
             boolean found = false;
             for (NodeExecutionData otherExecution : node.getChildExecutions()) {
@@ -1545,9 +1592,6 @@
             builder.end();
         }
 
-        if (shortCircuit != null) {
-            currentValues.setShortCircuitValue(execution, shortCircuit.accessWith(null));
-        }
         return createShortCircuit(targetValue, shortCircuit, builder.build());
     }
 
@@ -1663,12 +1707,7 @@
             throw new AssertionError("At least one generic executable method must be available.");
         }
 
-        Set<TypeData> specializedTypes = new HashSet<>();
-        for (TypeData type : node.findSpecializedTypes(execution)) {
-            specializedTypes.addAll(type.getImplicitSourceTypes());
-        }
-
-        List<ExecutableTypeData> specializedExecutables = resolveSpecializedExecutables(execution, specializedTypes, options.polymorphicTypeBoxingElimination());
+        List<ExecutableTypeData> specializedExecutables = resolvePolymorphicExecutables(execution);
         Collections.sort(specializedExecutables, new Comparator<ExecutableTypeData>() {
             public int compare(ExecutableTypeData o1, ExecutableTypeData o2) {
                 return o1.getType().compareTo(o2.getType());
@@ -1679,7 +1718,7 @@
         CodeTree executeGeneric = createSingleExecute(execution, target, currentValues, genericExecutableType);
 
         CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
-        if (specializedExecutables.isEmpty() || isSingleSpecializable(getReachableSpecializations())) {
+        if (specializedExecutables.isEmpty()) {
             builder.tree(assignment);
             builder.tree(executeGeneric);
         } else {
@@ -1747,6 +1786,17 @@
         return builder.build();
     }
 
+    private List<ExecutableTypeData> resolvePolymorphicExecutables(NodeExecutionData execution) {
+        if (singleSpecializable) {
+            return Collections.emptyList();
+        }
+        Set<TypeData> specializedTypes = new HashSet<>();
+        for (TypeData type : node.findSpecializedTypes(execution)) {
+            specializedTypes.addAll(type.getImplicitSourceTypes());
+        }
+        return resolveSpecializedExecutables(execution, specializedTypes, options.polymorphicTypeBoxingElimination());
+    }
+
     private static CodeTree createAssignmentStart(LocalVariable target, boolean shared) {
         CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
         if (shared) {
@@ -1804,7 +1854,7 @@
         return builder.build();
     }
 
-    private static CodeTree createFastPathTryCatchRewriteException(SpecializationData specialization, TypeData forType, LocalContext currentValues, CodeTree execution) {
+    private CodeTree createFastPathTryCatchRewriteException(SpecializationData specialization, TypeData forType, LocalContext currentValues, CodeTree execution) {
         if (specialization.getExceptions().isEmpty()) {
             return execution;
         }
@@ -1818,7 +1868,7 @@
         builder.end().startCatchBlock(exceptionTypes, "ex");
         builder.startStatement().tree(accessParent(excludedFieldName(specialization))).string(" = true").end();
         builder.startReturn();
-        builder.tree(createCallDelegate("remove", "threw rewrite exception", forType, currentValues));
+        builder.tree(createCallRemove("threw rewrite exception", forType, currentValues));
         builder.end();
         builder.end();
         return builder.build();
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalOrNode.java	Mon Jan 05 20:23:22 2015 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalOrNode.java	Mon Jan 05 20:23:22 2015 +0100
@@ -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.*;
@@ -48,7 +49,7 @@
         return left instanceof Boolean && needsRightNode(((Boolean) left).booleanValue());
     }
 
-    @Specialization
+    @Specialization(rewriteOn = RuntimeException.class)
     protected boolean doBoolean(boolean left, boolean hasRight, boolean right) {
         return left || right;
     }