changeset 7847:06a7cd6aaf00

Casting is now done on demand using local variables for explicit guards.
author Christian Humer <christian.humer@gmail.com>
date Tue, 19 Feb 2013 17:20:45 +0100
parents 91cc98eae8ee
children 698cd036a1ca
files graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ActualParameter.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java
diffstat 4 files changed, 199 insertions(+), 76 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java	Tue Feb 19 14:29:12 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java	Tue Feb 19 17:20:45 2013 +0100
@@ -83,8 +83,8 @@
         return field.getName() + "Value";
     }
 
-    private static String valueName(TemplateMethod method, ActualParameter param) {
-        NodeData node = (NodeData) method.getTemplate();
+    private static String valueName(ActualParameter param) {
+        NodeData node = (NodeData) param.getMethod().getTemplate();
         NodeFieldData field = node.findField(param.getSpecification().getName());
         if (field != null) {
             return valueName(field);
@@ -93,6 +93,14 @@
         }
     }
 
+    private static String castValueName(ActualParameter parameter) {
+        return valueName(parameter) + "Cast";
+    }
+
+    private static String castValueName(NodeFieldData field) {
+        return valueName(field) + "Cast";
+    }
+
     private void addValueParameters(CodeExecutableElement method, TemplateMethod specialization, boolean forceFrame) {
         if (forceFrame) {
             method.addParameter(new CodeVariableElement(getContext().getTruffleTypes().getFrame(), "frame"));
@@ -102,7 +110,7 @@
             if (forceFrame && spec.getName().equals("frame")) {
                 continue;
             }
-            method.addParameter(new CodeVariableElement(parameter.getActualType(), valueName(specialization, parameter)));
+            method.addParameter(new CodeVariableElement(parameter.getActualType(), valueName(parameter)));
         }
     }
 
@@ -119,12 +127,12 @@
             if (unexpectedValueName != null && spec.getName().equals(unexpectedValueName)) {
                 builder.string("ex.getResult()");
             } else {
-                builder.string(valueName(specialization, parameter));
+                builder.string(valueName(parameter));
             }
         }
     }
 
-    private static void addValueParameterNamesWithCasts(ProcessorContext context, CodeTreeBuilder body, SpecializationData valueSpecialization, SpecializationData targetSpecialization) {
+    private static void addValueParameterNamesWithCasts(CodeTreeBuilder body, SpecializationData valueSpecialization, SpecializationData targetSpecialization) {
         NodeData node = targetSpecialization.getNode();
         TypeSystemData typeSystem = node.getTypeSystem();
 
@@ -138,12 +146,9 @@
             }
 
             if (targetType == null || targetType.isGeneric() || (valueType != null && valueType.equalsType(targetType))) {
-                body.string(valueName(targetSpecialization, targetParameter));
+                body.string(valueName(targetParameter));
             } else {
-                String methodName = TypeSystemCodeGenerator.asTypeMethodName(targetType);
-                startCallTypeSystemMethod(context, body, node, methodName);
-                body.string(valueName(targetSpecialization, targetParameter));
-                body.end().end();
+                body.string(castValueName(targetParameter));
             }
         }
     }
@@ -184,6 +189,14 @@
         return prefix;
     }
 
+    private static CodeTree createCallTypeSystemMethod(ProcessorContext context, CodeTreeBuilder parent, NodeData node, String methodName, String value) {
+        CodeTreeBuilder builder = new CodeTreeBuilder(parent);
+        startCallTypeSystemMethod(context, builder, node, methodName);
+        builder.string(value);
+        builder.end().end();
+        return builder.getRoot();
+    }
+
     private static void startCallTypeSystemMethod(ProcessorContext context, CodeTreeBuilder body, NodeData node, String methodName) {
         VariableElement singleton = TypeSystemCodeGenerator.findSingleton(context, node.getTypeSystem());
         assert singleton != null;
@@ -193,12 +206,12 @@
         body.string(".").startCall(methodName);
     }
 
-    private static CodeTree createGuardAndCast(ProcessorContext context, CodeTreeBuilder parent, String prefix, SpecializationData valueSpecialization, SpecializationData guardedSpecialization,
-                    boolean onSpecialization, CodeTree guardedStatements, CodeTree elseStatements) {
+    private CodeTree createGuardAndCast(CodeTreeBuilder parent, String conditionPrefix, SpecializationData valueSpecialization, SpecializationData guardedSpecialization, boolean onSpecialization,
+                    CodeTree guardedStatements, CodeTree elseStatements) {
 
         CodeTreeBuilder builder = new CodeTreeBuilder(parent);
-        CodeTree implicitGuards = createImplicitGuards(context, parent, prefix, valueSpecialization, guardedSpecialization);
-        CodeTree explicitGuards = createExplicitGuards(context, parent, implicitGuards == null ? prefix : null, valueSpecialization, guardedSpecialization, onSpecialization);
+        CodeTree implicitGuards = createImplicitGuards(parent, conditionPrefix, valueSpecialization, guardedSpecialization);
+        CodeTree explicitGuards = createExplicitGuards(parent, implicitGuards == null ? conditionPrefix : null, valueSpecialization, guardedSpecialization, onSpecialization);
 
         int ifCount = 0;
 
@@ -210,6 +223,10 @@
             ifCount++;
         }
 
+        if (explicitGuards != null || !onSpecialization) {
+            builder.tree(createCasts(parent, valueSpecialization, guardedSpecialization));
+        }
+
         if (explicitGuards != null) {
             builder.startIf();
             builder.tree(explicitGuards);
@@ -218,8 +235,8 @@
             ifCount++;
         }
 
-        if (implicitGuards == null && explicitGuards == null && prefix != null && !prefix.isEmpty()) {
-            builder.startIf().string(prefix).end().startBlock();
+        if (implicitGuards == null && explicitGuards == null && conditionPrefix != null && !conditionPrefix.isEmpty()) {
+            builder.startIf().string(conditionPrefix).end().startBlock();
             ifCount++;
         }
 
@@ -235,10 +252,10 @@
         return builder.getRoot();
     }
 
-    private static CodeTree createExplicitGuards(ProcessorContext context, CodeTreeBuilder parent, String prefix, SpecializationData valueSpecialization, SpecializationData guardedSpecialization,
+    private static CodeTree createExplicitGuards(CodeTreeBuilder parent, String conditionPrefix, SpecializationData valueSpecialization, SpecializationData guardedSpecialization,
                     boolean onSpecialization) {
         CodeTreeBuilder builder = new CodeTreeBuilder(parent);
-        String andOperator = (prefix != null && !prefix.isEmpty()) ? (prefix + " && ") : "";
+        String andOperator = conditionPrefix != null ? conditionPrefix + " && " : "";
         if (guardedSpecialization.getGuards().length > 0) {
             // Explicitly specified guards
             for (SpecializationGuardData guard : guardedSpecialization.getGuards()) {
@@ -246,7 +263,7 @@
                     builder.string(andOperator);
 
                     startCallOperationMethod(builder, guard.getGuardDeclaration());
-                    addValueParameterNamesWithCasts(context, builder, valueSpecialization, guardedSpecialization);
+                    addValueParameterNamesWithCasts(builder, valueSpecialization, guardedSpecialization);
 
                     builder.end().end(); // call
                     andOperator = " && ";
@@ -257,50 +274,139 @@
         return builder.isEmpty() ? null : builder.getRoot();
     }
 
-    private static CodeTree createImplicitGuards(ProcessorContext context, CodeTreeBuilder parent, String prefix, SpecializationData valueSpecialization, SpecializationData guardedSpecialization) {
+    private CodeTree createCasts(CodeTreeBuilder parent, SpecializationData valueSpecialization, SpecializationData guardedSpecialization) {
         NodeData node = guardedSpecialization.getNode();
-        TypeSystemData typeSystem = node.getTypeSystem();
 
         CodeTreeBuilder builder = new CodeTreeBuilder(parent);
         // Implict guards based on method signature
-        String andOperator = (prefix != null && !prefix.isEmpty()) ? (prefix + " && ") : "";
         for (NodeFieldData field : node.getFields()) {
             ActualParameter guardedParam = guardedSpecialization.findParameter(field.getName());
             ActualParameter valueParam = valueSpecialization.findParameter(field.getName());
 
-            TypeData guardedType = guardedParam.getActualTypeData(typeSystem);
-            TypeData valueType = valueParam.getActualTypeData(typeSystem);
+            CodeTree cast = createCast(parent, field, valueParam, guardedParam);
+            if (cast == null) {
+                continue;
+            }
+            builder.tree(cast);
+        }
+
+        return builder.getRoot();
+    }
 
-            if (guardedType.equalsType(valueType) || guardedType.isGeneric()) {
+    private CodeTree createImplicitGuards(CodeTreeBuilder parent, String conditionPrefix, SpecializationData valueSpecialization, SpecializationData guardedSpecialization) {
+        NodeData node = guardedSpecialization.getNode();
+
+        CodeTreeBuilder builder = new CodeTreeBuilder(parent);
+        // Implict guards based on method signature
+        String andOperator = conditionPrefix != null ? conditionPrefix + " && " : "";
+        for (NodeFieldData field : node.getFields()) {
+            ActualParameter guardedParam = guardedSpecialization.findParameter(field.getName());
+            ActualParameter valueParam = valueSpecialization.findParameter(field.getName());
+
+            CodeTree implicitGuard = createImplicitGuard(builder, field, valueParam, guardedParam);
+            if (implicitGuard == null) {
                 continue;
             }
 
             builder.string(andOperator);
-
-            builder.startGroup();
-
-            if (field.isShortCircuit()) {
-                ActualParameter shortCircuit = guardedSpecialization.getPreviousParam(guardedParam);
-                builder.string("(");
-                builder.string("!").string(valueName(guardedSpecialization, shortCircuit));
-                builder.string(" || ");
-            }
-
-            startCallTypeSystemMethod(context, builder, guardedSpecialization.getNode(), TypeSystemCodeGenerator.isTypeMethodName(guardedType));
-            builder.string(valueName(guardedSpecialization, guardedParam));
-            builder.end().end(); // call
-
-            if (field.isShortCircuit()) {
-                builder.string(")");
-            }
-
-            builder.end(); // group
+            builder.tree(implicitGuard);
             andOperator = " && ";
         }
 
         return builder.isEmpty() ? null : builder.getRoot();
     }
 
+    private CodeTree createImplicitGuard(CodeTreeBuilder parent, NodeFieldData field, ActualParameter source, ActualParameter target) {
+        NodeData node = field.getNodeData();
+        CodeTreeBuilder builder = new CodeTreeBuilder(parent);
+
+        TypeData targetType = target.getActualTypeData(node.getTypeSystem());
+        TypeData sourceType = source.getActualTypeData(node.getTypeSystem());
+
+        if (targetType.equalsType(sourceType) || targetType.isGeneric()) {
+            return null;
+        }
+
+        builder.startGroup();
+
+        if (field.isShortCircuit()) {
+            ActualParameter shortCircuit = target.getPreviousParameter();
+            assert shortCircuit != null;
+            builder.string("(");
+            builder.string("!").string(valueName(shortCircuit));
+            builder.string(" || ");
+        }
+
+        startCallTypeSystemMethod(getContext(), builder, node, TypeSystemCodeGenerator.isTypeMethodName(target.getActualTypeData(node.getTypeSystem())));
+        builder.string(valueName(field));
+        builder.end().end(); // call
+
+        if (field.isShortCircuit()) {
+            builder.string(")");
+        }
+
+        builder.end(); // group
+
+        return builder.getRoot();
+    }
+
+    private CodeTree createCast(CodeTreeBuilder parent, NodeFieldData field, ActualParameter source, ActualParameter target) {
+        NodeData node = field.getNodeData();
+        TypeSystemData typeSystem = node.getTypeSystem();
+
+        TypeData sourceType = source.getActualTypeData(typeSystem);
+        TypeData targetType = target.getActualTypeData(typeSystem);
+
+        if (targetType.equalsType(sourceType) || targetType.isGeneric()) {
+            return null;
+        }
+
+        CodeTree condition = null;
+        if (field.isShortCircuit()) {
+            ActualParameter shortCircuit = target.getPreviousParameter();
+            assert shortCircuit != null;
+            condition = CodeTreeBuilder.singleString(valueName(shortCircuit));
+        }
+
+        CodeTree value = createCallTypeSystemMethod(context, parent, node, TypeSystemCodeGenerator.asTypeMethodName(targetType), valueName(target));
+
+        return createLazyAssignment(parent, castValueName(field), target.getActualType(), condition, value);
+    }
+
+    /**
+     * <pre>
+     * variant1 $condition != null
+     * 
+     * $type $name = defaultValue($type);
+     * if ($condition) {
+     *     $name = $value;
+     * }
+     * 
+     * variant2 $condition != null
+     * $type $name = $value;
+     * </pre>
+     * 
+     * .
+     */
+    private static CodeTree createLazyAssignment(CodeTreeBuilder parent, String name, TypeMirror type, CodeTree condition, CodeTree value) {
+        CodeTreeBuilder builder = new CodeTreeBuilder(parent);
+        if (condition == null) {
+            builder.declaration(type, name, value);
+        } else {
+            builder.declaration(type, name, new CodeTreeBuilder(parent).defaultValue(type).getRoot());
+
+            builder.startIf().tree(condition).end();
+            builder.startBlock();
+            builder.startStatement();
+            builder.string(name);
+            builder.string(" = ");
+            builder.tree(value);
+            builder.end(); // statement
+            builder.end(); // block
+        }
+        return builder.getRoot();
+    }
+
     @Override
     protected void createChildren(NodeData node) {
         Map<NodeData, List<TypeElement>> childTypes = new LinkedHashMap<>();
@@ -520,7 +626,7 @@
                 guarded.string(THIS_NODE_LOCAL_VAR_NAME);
                 guarded.end().end();
 
-                body.tree(createGuardAndCast(getContext(), body, "allowed", node.getGenericSpecialization(), specialization, true, guarded.getRoot(), null));
+                body.tree(createGuardAndCast(body, "allowed", node.getGenericSpecialization(), specialization, true, guarded.getRoot(), null));
             }
             body.startThrow().startNew(getContext().getType(IllegalArgumentException.class)).end().end();
 
@@ -569,7 +675,7 @@
             CodeTree invokeMethod = invokeMethodBuilder.getRoot();
 
             if (next != null) {
-                invokeMethod = createGuardAndCast(getContext(), builder, "", current.getNode().getGenericSpecialization(), current, false, invokeMethod, null);
+                invokeMethod = createGuardAndCast(builder, null, current.getNode().getGenericSpecialization(), current, false, invokeMethod, null);
             }
 
             builder.tree(invokeMethod);
@@ -591,7 +697,7 @@
 
             builder.startReturn();
             startCallOperationMethod(builder, specialization);
-            addValueParameterNamesWithCasts(context, builder, specialization.getNode().getGenericSpecialization(), specialization);
+            addValueParameterNamesWithCasts(builder, specialization.getNode().getGenericSpecialization(), specialization);
             builder.end().end(); // start call operation
             builder.end(); // return
 
@@ -698,14 +804,14 @@
                     builder.string("// ignore").newLine();
                 } else {
                     builder.startReturn();
-                    builder.tree(castPrimaryExecute(node, castedType, CodeTreeBuilder.singleString("ex.getResult()")));
+                    builder.tree(createExpectType(node, castedType, CodeTreeBuilder.singleString("ex.getResult()")));
                     builder.end();
                 }
                 builder.end();
 
                 if (!returnVoid) {
                     builder.startReturn();
-                    builder.tree(castPrimaryExecute(node, castedType, CodeTreeBuilder.singleString("value")));
+                    builder.tree(createExpectType(node, castedType, CodeTreeBuilder.singleString("value")));
                     builder.end();
                 }
             } else {
@@ -713,13 +819,13 @@
                     builder.statement(primaryExecuteCall);
                 } else {
                     builder.startReturn();
-                    builder.tree(castPrimaryExecute(node, castedType, primaryExecuteCall));
+                    builder.tree(createExpectType(node, castedType, primaryExecuteCall));
                     builder.end();
                 }
             }
         }
 
-        private CodeTree castPrimaryExecute(NodeData node, ExecutableTypeData castedType, CodeTree value) {
+        private CodeTree createExpectType(NodeData node, ExecutableTypeData castedType, CodeTree value) {
             if (castedType == null) {
                 return value;
             } else if (castedType.getType().isVoid()) {
@@ -729,11 +835,14 @@
             }
 
             CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
+            String targetMethodName;
             if (castedType.hasUnexpectedValue(getContext())) {
-                startCallTypeSystemMethod(getContext(), builder, node, TypeSystemCodeGenerator.expectTypeMethodName(castedType.getType()));
+                targetMethodName = TypeSystemCodeGenerator.expectTypeMethodName(castedType.getType());
             } else {
-                startCallTypeSystemMethod(getContext(), builder, node, TypeSystemCodeGenerator.asTypeMethodName(castedType.getType()));
+                targetMethodName = TypeSystemCodeGenerator.asTypeMethodName(castedType.getType());
             }
+            startCallTypeSystemMethod(getContext(), builder, node, targetMethodName);
+
             builder.tree(value);
             builder.end().end();
             return builder.getRoot();
@@ -757,7 +866,7 @@
             if (next != null) {
                 returnSpecialized = createReturnSpecializeAndExecute(builder, next, null);
             }
-            builder.tree(createGuardAndCast(context, builder, "", specialization, specialization, false, executeNode, returnSpecialized));
+            builder.tree(createGuardAndCast(builder, null, specialization, specialization, false, executeNode, returnSpecialized));
         }
 
         private CodeTree createDeoptimize(CodeTreeBuilder parent) {
@@ -863,7 +972,7 @@
                 builder.string(" ");
             }
 
-            builder.string(valueName(specialization, specParameter));
+            builder.string(valueName(specParameter));
             builder.string(" = ");
             ExecutableTypeData genericExecutableType = field.getNodeData().findGenericExecutableType(getContext(), specParameter.getActualTypeData(node.getTypeSystem()));
             if (genericExecutableType == null) {
@@ -899,7 +1008,7 @@
             boolean shortCircuit = startShortCircuit(builder, specialization, field, null);
 
             if (!shortCircuit) {
-                builder.startStatement().type(param.getActualType()).string(" ").string(valueName(specialization, param)).end();
+                builder.startStatement().type(param.getActualType()).string(" ").string(valueName(param)).end();
             }
 
             ExecutableTypeData execType = field.getNodeData().findExecutableType(param.getActualTypeData(field.getNodeData().getTypeSystem()));
@@ -951,7 +1060,7 @@
                 }
             }
 
-            builder.startStatement().type(shortCircuitParam.getActualType()).string(" ").string(valueName(specialization, shortCircuitParam)).string(" = ");
+            builder.startStatement().type(shortCircuitParam.getActualType()).string(" ").string(valueName(shortCircuitParam)).string(" = ");
             ShortCircuitData shortCircuitData = specialization.getShortCircuits()[shortCircuitIndex];
 
             startCallOperationMethod(builder, shortCircuitData);
@@ -960,7 +1069,7 @@
 
             builder.end(); // statement
 
-            builder.declaration(parameter.getActualType(), valueName(specialization, parameter), CodeTreeBuilder.createBuilder().defaultValue(parameter.getActualType()));
+            builder.declaration(parameter.getActualType(), valueName(parameter), CodeTreeBuilder.createBuilder().defaultValue(parameter.getActualType()));
             builder.startIf().string(shortCircuitParam.getSpecification().getName()).end();
             builder.startBlock();
 
@@ -1023,7 +1132,7 @@
             addValueParameterNames(genericExecute, specialization.getNode().getGenericSpecialization(), null, true);
             genericExecute.end(); // call generated generic
 
-            CodeTree genericInvocation = castPrimaryExecute(node, returnExecutableType, genericExecute.getRoot());
+            CodeTree genericInvocation = createExpectType(node, returnExecutableType, genericExecute.getRoot());
 
             if (generatedGeneric != null && Utils.isVoid(generatedGeneric.getReturnType())) {
                 builder.statement(genericInvocation);
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java	Tue Feb 19 14:29:12 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java	Tue Feb 19 17:20:45 2013 +0100
@@ -124,15 +124,4 @@
         return false;
     }
 
-    public ActualParameter getPreviousParam(ActualParameter searchParam) {
-        ActualParameter prev = null;
-        for (ActualParameter param : getParameters()) {
-            if (param == searchParam) {
-                return prev;
-            }
-            prev = param;
-        }
-        return prev;
-    }
-
 }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ActualParameter.java	Tue Feb 19 14:29:12 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ActualParameter.java	Tue Feb 19 17:20:45 2013 +0100
@@ -30,16 +30,25 @@
 
     private final ParameterSpec specification;
     private final TypeMirror actualType;
+    private TemplateMethod method;
 
     public ActualParameter(ParameterSpec specification, TypeMirror actualType) {
         this.specification = specification;
         this.actualType = actualType;
     }
 
+    void setMethod(TemplateMethod method) {
+        this.method = method;
+    }
+
     public ParameterSpec getSpecification() {
         return specification;
     }
 
+    public TemplateMethod getMethod() {
+        return method;
+    }
+
     public TypeMirror getActualType() {
         return actualType;
     }
@@ -47,4 +56,8 @@
     public TypeData getActualTypeData(TypeSystemData typeSystem) {
         return typeSystem.findTypeData(actualType);
     }
+
+    public ActualParameter getPreviousParameter() {
+        return method.getPreviousParam(this);
+    }
 }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java	Tue Feb 19 14:29:12 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java	Tue Feb 19 17:20:45 2013 +0100
@@ -40,15 +40,16 @@
         this.markerAnnotation = markerAnnotation;
         this.returnType = returnType;
         this.parameters = parameters;
+
+        if (parameters != null) {
+            for (ActualParameter param : parameters) {
+                param.setMethod(this);
+            }
+        }
     }
 
     public TemplateMethod(TemplateMethod method) {
-        this.template = method.template;
-        this.specification = method.specification;
-        this.method = method.method;
-        this.markerAnnotation = method.markerAnnotation;
-        this.returnType = method.returnType;
-        this.parameters = method.parameters;
+        this(method.template, method.specification, method.method, method.markerAnnotation, method.returnType, method.parameters);
     }
 
     public Template getTemplate() {
@@ -101,4 +102,15 @@
     public String toString() {
         return getClass().getSimpleName() + " [method = " + method + "]";
     }
+
+    public ActualParameter getPreviousParam(ActualParameter searchParam) {
+        ActualParameter prev = null;
+        for (ActualParameter param : getParameters()) {
+            if (param == searchParam) {
+                return prev;
+            }
+            prev = param;
+        }
+        return prev;
+    }
 }