Mercurial > hg > truffle
diff graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java @ 11195:4f52b08bd2f9
Truffle-DSL: Implemented specialization grouping for generic cases.
author | Christian Humer <christian.humer@gmail.com> |
---|---|
date | Thu, 01 Aug 2013 20:53:54 +0200 |
parents | 4eb23800c907 |
children | 3479ab380552 |
line wrap: on
line diff
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java Thu Aug 01 20:53:05 2013 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java Thu Aug 01 20:53:54 2013 +0200 @@ -440,7 +440,7 @@ continue; } - CodeTree cast = createCast(parent, field, valueParam, guardedParam); + CodeTree cast = createCast(parent, field, valueParam, guardedParam.getTypeSystemType()); if (cast == null) { continue; } @@ -479,7 +479,7 @@ valueParam = guardedParam; } - CodeTree implicitGuard = createImplicitGuard(builder, field, valueParam, guardedParam); + CodeTree implicitGuard = createTypeGuard(builder, field, valueParam, guardedParam.getTypeSystemType()); if (implicitGuard == null) { continue; } @@ -492,11 +492,11 @@ return builder.isEmpty() ? null : builder.getRoot(); } - private CodeTree createImplicitGuard(CodeTreeBuilder parent, NodeChildData field, ActualParameter source, ActualParameter target) { + private CodeTree createTypeGuard(CodeTreeBuilder parent, NodeChildData field, ActualParameter source, TypeData targetType) { NodeData node = field.getNodeData(); + CodeTreeBuilder builder = new CodeTreeBuilder(parent); - TypeData targetType = target.getTypeSystemType(); TypeData sourceType = source.getTypeSystemType(); if (!sourceType.needsCastTo(getContext(), targetType)) { @@ -506,14 +506,14 @@ builder.startGroup(); if (field.isShortCircuit()) { - ActualParameter shortCircuit = target.getPreviousParameter(); + ActualParameter shortCircuit = source.getPreviousParameter(); assert shortCircuit != null; builder.string("("); builder.string("!").string(valueName(shortCircuit)); builder.string(" || "); } - startCallTypeSystemMethod(getContext(), builder, node, TypeSystemCodeGenerator.isTypeMethodName(target.getTypeSystemType())); + startCallTypeSystemMethod(getContext(), builder, node, TypeSystemCodeGenerator.isTypeMethodName(targetType)); builder.string(valueName(source)); builder.end().end(); // call @@ -526,10 +526,9 @@ return builder.getRoot(); } - private CodeTree createCast(CodeTreeBuilder parent, NodeChildData field, ActualParameter source, ActualParameter target) { + private CodeTree createCast(CodeTreeBuilder parent, NodeChildData field, ActualParameter source, TypeData targetType) { NodeData node = field.getNodeData(); TypeData sourceType = source.getTypeSystemType(); - TypeData targetType = target.getTypeSystemType(); if (!sourceType.needsCastTo(getContext(), targetType)) { return null; @@ -537,14 +536,14 @@ CodeTree condition = null; if (field.isShortCircuit()) { - ActualParameter shortCircuit = target.getPreviousParameter(); + ActualParameter shortCircuit = source.getPreviousParameter(); assert shortCircuit != null; condition = CodeTreeBuilder.singleString(valueName(shortCircuit)); } - CodeTree value = createCallTypeSystemMethod(context, parent, node, TypeSystemCodeGenerator.asTypeMethodName(targetType), CodeTreeBuilder.singleString(valueName(target))); - - return createLazyAssignment(parent, castValueName(target), target.getType(), condition, value); + CodeTree value = createCallTypeSystemMethod(context, parent, node, TypeSystemCodeGenerator.asTypeMethodName(targetType), CodeTreeBuilder.singleString(valueName(source))); + + return createLazyAssignment(parent, castValueName(source), targetType.getPrimitiveType(), condition, value); } /** @@ -1416,8 +1415,7 @@ return var; } - private CodeExecutableElement createGenericExecuteAndSpecialize(NodeData node) { - + private CodeExecutableElement createGenericExecuteAndSpecialize(final NodeData node) { TypeMirror genericReturnType = node.getGenericSpecialization().getReturnType().getType(); CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED), genericReturnType, EXECUTE_SPECIALIZE_NAME); method.addParameter(new CodeVariableElement(getContext().getType(int.class), "minimumState")); @@ -1436,33 +1434,36 @@ builder.end().end(); List<SpecializationData> specializations = node.getSpecializations(); - - boolean firstUnreachable = true; - SpecializationData previous = null; + List<SpecializationData> filteredSpecializations = new ArrayList<>(); for (SpecializationData current : specializations) { - if (current.isUninitialized()) { + if (current.isUninitialized() || !current.isReachable()) { continue; } - String prefix = null; - - if (current.hasRewrite(getContext())) { - prefix = "minimumState < " + node.getSpecializations().indexOf(current); + filteredSpecializations.add(current); + } + + List<SpecializationGroup> groups = SpecializationGroup.create(filteredSpecializations); + + for (SpecializationGroup group : groups) { + builder.tree(createExecuteTree(builder, node.getGenericSpecialization(), group, true, new CodeBlock<SpecializationData>() { + + public CodeTree create(CodeTreeBuilder b, SpecializationData current) { + return createGenericInvokeAndSpecialize(b, node.getGenericSpecialization(), current); + } + })); + } + + boolean firstUnreachable = true; + for (SpecializationData current : specializations) { + if (current.isUninitialized() || current.isReachable()) { + continue; } - - if (current.isReachable()) { - CodeTree execute = createGenericInvokeAndSpecialize(builder, node.getGenericSpecialization(), current); - - builder.tree(createGuardAndCast(builder, prefix, current.getNode().getGenericSpecialization(), current, true, execute, null, true, false)); - } else { - if (firstUnreachable) { - if (previous != null && !previous.isGenericSpecialization(getContext()) && !previous.hasRewrite(getContext())) { - emitEncounteredSynthetic(builder, current); - } - firstUnreachable = false; - } - builder.string("// unreachable ").string(current.getId()).newLine(); + if (firstUnreachable) { + emitEncounteredSynthetic(builder, current); + firstUnreachable = false; } - previous = current; + + builder.string("// unreachable ").string(current.getId()).newLine(); } return method; @@ -1475,18 +1476,26 @@ method.getAnnotationMirrors().add(new CodeAnnotationMirror(getContext().getTruffleTypes().getSlowPath())); addInternalValueParameters(method, node.getGenericSpecialization(), node.needsFrame(), false); - CodeTreeBuilder builder = method.createBuilder(); - - String prefix = null; + final CodeTreeBuilder builder = method.createBuilder(); + List<SpecializationData> specializations = node.getSpecializations(); - + List<SpecializationData> filteredSpecializations = new ArrayList<>(); for (SpecializationData current : specializations) { if (current.isUninitialized() || !current.isReachable()) { continue; } - CodeTreeBuilder execute = new CodeTreeBuilder(builder); - execute.tree(createGenericInvoke(builder, node.getGenericSpecialization(), current)); - builder.tree(createGuardAndCast(builder, prefix, current.getNode().getGenericSpecialization(), current, true, execute.getRoot(), null, true, false)); + filteredSpecializations.add(current); + } + + List<SpecializationGroup> groups = SpecializationGroup.create(filteredSpecializations); + + for (SpecializationGroup group : groups) { + builder.tree(createExecuteTree(builder, node.getGenericSpecialization(), group, false, new CodeBlock<SpecializationData>() { + + public CodeTree create(CodeTreeBuilder b, SpecializationData current) { + return createGenericInvoke(builder, current.getNode().getGenericSpecialization(), current); + } + })); } for (SpecializationData current : specializations) { @@ -1499,6 +1508,209 @@ return method; } + private CodeTree createExecuteTree(CodeTreeBuilder outerParent, final SpecializationData source, final SpecializationGroup group, final boolean checkMinimumState, + final CodeBlock<SpecializationData> guardedblock) { + return guard(outerParent, source, group, checkMinimumState, new CodeBlock<Void>() { + + public CodeTree create(CodeTreeBuilder parent, Void value) { + CodeTreeBuilder builder = parent.create(); + + if (group.getSpecialization() != null) { + builder.tree(guardedblock.create(builder, group.getSpecialization())); + + assert group.getChildren().isEmpty() : "missed a specialization"; + } else { + for (SpecializationGroup childGroup : group.getChildren()) { + builder.tree(createExecuteTree(builder, source, childGroup, checkMinimumState, guardedblock)); + } + } + + return builder.getRoot(); + } + }); + } + + private CodeTree guard(CodeTreeBuilder parent, SpecializationData source, SpecializationGroup group, boolean checkMinimumState, CodeBlock<Void> bodyBlock) { + NodeData node = source.getNode(); + + CodeTreeBuilder guardsBuilder = parent.create(); + CodeTreeBuilder castBuilder = parent.create(); + CodeTreeBuilder guardsCastBuilder = parent.create(); + + String guardsAnd = ""; + String guardsCastAnd = ""; + + boolean minimumState = checkMinimumState; + if (minimumState) { + int groupMaxIndex = group.getMaxSpecializationIndex(); + + int genericIndex = node.getSpecializations().indexOf(node.getGenericSpecialization()); + if (groupMaxIndex >= genericIndex) { + // no minimum state check for an generic index + minimumState = false; + } + + if (minimumState) { + // no minimum state check if alread checked by parent group + int parentMaxIndex = -1; + if (group.getParent() != null) { + parentMaxIndex = group.getParent().getMaxSpecializationIndex(); + } + if (groupMaxIndex == parentMaxIndex) { + minimumState = false; + } + } + + if (minimumState) { + guardsBuilder.string(guardsAnd); + guardsBuilder.string("minimumState < " + groupMaxIndex); + guardsAnd = " && "; + } + } + + for (String assumption : group.getAssumptions()) { + guardsBuilder.string(guardsAnd); + guardsBuilder.string("this"); + guardsBuilder.string(".").string(assumption).string(".isValid()"); + guardsAnd = " && "; + } + + int argOffset = group.getTypeGuardOffset(); + int argIndex = argOffset; + for (TypeData typeData : group.getTypeGuards()) { + + ActualParameter valueParam = source.getSignatureParameter(argIndex); + + if (valueParam == null) { + /* + * If used inside a execute evaluated method then the value param may not exist. + * In that case we assume that the value is executed generic or of the current + * specialization. + */ + if (group.getSpecialization() != null) { + valueParam = group.getSpecialization().getSignatureParameter(argIndex); + } else { + valueParam = node.getGenericSpecialization().getSignatureParameter(argIndex); + } + } + + NodeChildData child = node.findChild(valueParam.getSpecification().getName()); + if (child == null) { + throw new IllegalStateException(); + } + + CodeTree implicitGuard = createTypeGuard(guardsBuilder, child, valueParam, typeData); + if (implicitGuard != null) { + guardsBuilder.string(guardsAnd); + guardsBuilder.tree(implicitGuard); + guardsAnd = " && "; + } + + CodeTree cast = createCast(castBuilder, child, valueParam, typeData); + if (cast != null) { + castBuilder.tree(cast); + } + + argIndex++; + } + CodeTreeBuilder builder = parent.create(); + + int ifCount = 0; + if (isElseConnectableGroup(group)) { + if (minimumState) { + builder.startElseIf().tree(guardsBuilder.getRoot()).end().startBlock(); + } else { + builder.startElseBlock(); + } + ifCount++; + + } else { + for (GuardData guard : group.getGuards()) { + if (needsTypeGuard(source, group, guard)) { + guardsCastBuilder.tree(createMethodGuard(parent, guardsCastAnd, source, guard)); + guardsCastAnd = " && "; + } else { + guardsBuilder.tree(createMethodGuard(parent, guardsAnd, source, guard)); + guardsAnd = " && "; + } + } + + if (!guardsBuilder.isEmpty()) { + builder.startIf().tree(guardsBuilder.getRoot()).end().startBlock(); + ifCount++; + } + builder.tree(castBuilder.getRoot()); + + if (!guardsCastBuilder.isEmpty()) { + builder.startIf().tree(guardsCastBuilder.getRoot()).end().startBlock(); + ifCount++; + } + } + + builder.tree(bodyBlock.create(builder, null)); + + builder.end(ifCount); + return builder.getRoot(); + } + + private boolean isElseConnectableGroup(SpecializationGroup group) { + if (!group.getTypeGuards().isEmpty() || !group.getAssumptions().isEmpty()) { + return false; + } + + SpecializationGroup previousGroup = group.getPreviousGroup(); + if (previousGroup != null && group.getGuards().size() == 1 && previousGroup.getGuards().size() == 1) { + GuardData guard = group.getGuards().get(0); + GuardData previousGuard = previousGroup.getGuards().get(0); + + if (guard.getMethod().equals(previousGuard.getMethod())) { + assert guard.isNegated() != previousGuard.isNegated(); + return true; + } + } + return false; + } + + private boolean needsTypeGuard(SpecializationData source, SpecializationGroup group, GuardData guard) { + int offset = group.getTypeGuardOffset(); + int argIndex = 0; + for (ActualParameter parameter : guard.getParameters()) { + if (!parameter.getSpecification().isSignature()) { + continue; + } + if (argIndex < offset) { + // type casted in parent group + continue; + } + + int guardIndex = argIndex - offset; + if (guardIndex < group.getTypeGuards().size()) { + TypeData requiredType = group.getTypeGuards().get(guardIndex); + + ActualParameter sourceParameter = source.findParameter(parameter.getLocalName()); + if (sourceParameter == null) { + sourceParameter = source.getNode().getGenericSpecialization().findParameter(parameter.getLocalName()); + } + + if (sourceParameter.getTypeSystemType().needsCastTo(getContext(), requiredType)) { + return true; + } + } + argIndex++; + } + return false; + } + + private CodeTree createMethodGuard(CodeTreeBuilder parent, String prefix, SpecializationData source, GuardData guard) { + CodeTreeBuilder builder = parent.create(); + builder.string(prefix); + if (guard.isNegated()) { + builder.string("!"); + } + builder.tree(createTemplateMethodCall(builder, null, source, guard, null)); + return builder.getRoot(); + } + protected CodeTree createGenericInvoke(CodeTreeBuilder parent, SpecializationData source, SpecializationData current) { CodeTreeBuilder builder = new CodeTreeBuilder(parent); @@ -1508,14 +1720,16 @@ builder.startReturn().tree(createTemplateMethodCall(builder, null, source, current, null)).end(); } - return encloseThrowsWithFallThrough(current, builder.getRoot()); + return encloseThrowsWithFallThrough(current, builder.getRoot(), null); } protected CodeTree createGenericInvokeAndSpecialize(CodeTreeBuilder parent, SpecializationData source, SpecializationData current) { - CodeTreeBuilder builder = new CodeTreeBuilder(parent); + CodeTreeBuilder builder = parent.create(); + CodeTreeBuilder prefix = parent.create(); NodeData node = current.getNode(); + String restoreNode = null; if (current.isGeneric() && node.isPolymorphic()) { builder.startIf().string("next0 == null && minimumState > 0").end().startBlock(); builder.tree(createRewritePolymorphic(builder, node)); @@ -1525,10 +1739,18 @@ builder.end(); } else { // simple rewrite - builder.tree(createReturnRewriteAndInvoke(builder, null, null, source, current)); + if (current.getExceptions().isEmpty()) { + builder.tree(createGenericInvoke(builder, source, current, createReplaceCall(builder, current, null, null))); + } else { + prefix.declaration(baseClassName(node), "restoreNode", createReplaceCall(builder, current, null, null)); + builder.tree(createGenericInvoke(builder, source, current, CodeTreeBuilder.singleString("restoreNode"))); + restoreNode = "restoreNode"; + } } - - return encloseThrowsWithFallThrough(current, builder.getRoot()); + CodeTreeBuilder root = parent.create(); + root.tree(prefix.getRoot()); + root.tree(encloseThrowsWithFallThrough(current, builder.getRoot(), restoreNode)); + return root.getRoot(); } private CodeTree createRewriteGeneric(CodeTreeBuilder parent, SpecializationData source, SpecializationData current) { @@ -1540,7 +1762,7 @@ builder.tree(createFindRoot(builder, node, false)); builder.end(); builder.end(); - builder.tree(createReturnRewriteAndInvoke(builder, "root", null, source, current)); + builder.tree(createGenericInvoke(builder, source, current, createReplaceCall(builder, current, "root", null))); return builder.getRoot(); } @@ -1559,7 +1781,7 @@ return builder.getRoot(); } - private CodeTree encloseThrowsWithFallThrough(SpecializationData current, CodeTree tree) { + private CodeTree encloseThrowsWithFallThrough(SpecializationData current, CodeTree tree, String restoreNodeVarName) { if (current.getExceptions().isEmpty()) { return tree; } @@ -1569,6 +1791,16 @@ builder.tree(tree); for (SpecializationThrowsData exception : current.getExceptions()) { builder.end().startCatchBlock(exception.getJavaClass(), "rewriteEx"); + if (restoreNodeVarName != null) { + builder.startStatement().startCall(restoreNodeVarName, "replace").string("this"); + builder.startGroup(); + builder.startCall("createInfo0").doubleQuote("Rewrite exception thrown " + Utils.getSimpleName(exception.getJavaClass()) + "."); + addInternalValueParameterNames(builder, current, current, null, false, true); + builder.end(); + builder.end(); + builder.end().end(); + } + builder.string("// fall through").newLine(); } builder.end(); @@ -1576,9 +1808,28 @@ return builder.getRoot(); } - protected CodeTree createReturnRewriteAndInvoke(CodeTreeBuilder parent, String target, String message, SpecializationData source, SpecializationData current) { + protected CodeTree createGenericInvoke(CodeTreeBuilder parent, SpecializationData source, SpecializationData current, CodeTree replaceCall) { + CodeTreeBuilder builder = parent.create(); + if (current.isGeneric()) { + builder.startReturn().tree(replaceCall).string(".").startCall(EXECUTE_GENERIC_NAME); + addInternalValueParameterNames(builder, source, current, null, current.getNode().needsFrame(), true); + builder.end().end(); + + } else if (current.getMethod() == null) { + builder.statement(replaceCall); + emitEncounteredSynthetic(builder, current); + } else if (!current.canBeAccessedByInstanceOf(getContext(), source.getNode().getNodeType())) { + builder.statement(replaceCall); + builder.startReturn().tree(createTemplateMethodCall(parent, null, source, current, null)).end(); + } else { + replaceCall.add(new CodeTree(CodeTreeKind.STRING, null, ".")); + builder.startReturn().tree(createTemplateMethodCall(parent, replaceCall, source, current, null)).end(); + } + return builder.getRoot(); + } + + protected CodeTree createReplaceCall(CodeTreeBuilder builder, SpecializationData current, String target, String message) { String className = nodeSpecializationClassName(current); - CodeTreeBuilder builder = parent.create(); CodeTreeBuilder replaceCall = builder.create(); if (target != null) { replaceCall.startCall(target, "replace"); @@ -1592,24 +1843,7 @@ replaceCall.doubleQuote(message); } replaceCall.end(); - - if (current.isGeneric()) { - replaceCall.string("."); - builder.startReturn().tree(replaceCall.getRoot()).startCall(EXECUTE_GENERIC_NAME); - addInternalValueParameterNames(builder, source, current, null, current.getNode().needsFrame(), true); - builder.end().end(); - - } else if (current.getMethod() == null) { - builder.statement(replaceCall.getRoot()); - emitEncounteredSynthetic(builder, current); - } else if (!current.canBeAccessedByInstanceOf(getContext(), source.getNode().getNodeType())) { - builder.statement(replaceCall.getRoot()); - builder.startReturn().tree(createTemplateMethodCall(builder, null, source, current, null)).end(); - } else { - replaceCall.string("."); - builder.startReturn().tree(createTemplateMethodCall(builder, replaceCall.getRoot(), source, current, null)).end(); - } - return builder.getRoot(); + return replaceCall.getRoot(); } private CodeTree createRewritePolymorphic(CodeTreeBuilder parent, NodeData node) { @@ -2261,7 +2495,8 @@ builder.startIf().string("depth > ").string(String.valueOf(node.getPolymorphicDepth())).end(); builder.startBlock(); String message = ("Polymorphic limit reached (" + node.getPolymorphicDepth() + ")"); - builder.tree(createReturnRewriteAndInvoke(builder, "root", message, node.getGenericPolymorphicSpecialization(), node.getGenericSpecialization())); + builder.tree(createGenericInvoke(builder, node.getGenericPolymorphicSpecialization(), node.getGenericSpecialization(), + createReplaceCall(builder, node.getGenericSpecialization(), "root", message))); builder.end(); builder.startElseBlock(); @@ -2489,4 +2724,9 @@ } + private interface CodeBlock<T> { + + CodeTree create(CodeTreeBuilder parent, T value); + + } }