# HG changeset patch # User Christian Humer # Date 1361290845 -3600 # Node ID 06a7cd6aaf0009079e2ab204b53d72732999f050 # Parent 91cc98eae8eee3d0b3f77d2650b01bdd6c204a1a Casting is now done on demand using local variables for explicit guards. diff -r 91cc98eae8ee -r 06a7cd6aaf00 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java --- 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); + } + + /** + *
+     * variant1 $condition != null
+     * 
+     * $type $name = defaultValue($type);
+     * if ($condition) {
+     *     $name = $value;
+     * }
+     * 
+     * variant2 $condition != null
+     * $type $name = $value;
+     * 
+ * + * . + */ + 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> 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); diff -r 91cc98eae8ee -r 06a7cd6aaf00 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java --- 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; - } - } diff -r 91cc98eae8ee -r 06a7cd6aaf00 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ActualParameter.java --- 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); + } } diff -r 91cc98eae8ee -r 06a7cd6aaf00 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java --- 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; + } }