# HG changeset patch # User Christian Humer # Date 1380810669 -7200 # Node ID 7aa2a8c69ba3bb77e3abe5e00f3b96968ecd3176 # Parent 5151a758838428e0fe46363a767696ff4ba34d53 TruffleDSL: improved code generation layout for implicit casts. diff -r 5151a7588384 -r 7aa2a8c69ba3 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ImplicitCastTest.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ImplicitCastTest.java Wed Oct 02 15:57:17 2013 +0200 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ImplicitCastTest.java Thu Oct 03 16:31:09 2013 +0200 @@ -54,13 +54,13 @@ public abstract Object executeEvaluated(VirtualFrame frame, Object value2); - @Specialization(order = 1) - public String op1(String value) throws RuntimeException { + @Specialization + public String op1(String value) { return value; } - @Specialization(order = 2) - public boolean op1(boolean value) throws RuntimeException { + @Specialization + public boolean op1(boolean value) { return value; } @@ -77,6 +77,38 @@ Assert.assertEquals(true, root.getNode().executeEvaluated(null, true)); } +// @TypeSystemReference(ImplicitCast0Types.class) +// @NodeChild(value = "operand", type = ImplicitCast0Node.class) +// abstract static class ImplicitCast1Node extends ValueNode { +// +// @Specialization +// public String op0(String value) { +// return value; +// } +// +// @Specialization(order = 1, rewriteOn = RuntimeException.class) +// public boolean op1(@SuppressWarnings("unused") boolean value) throws RuntimeException { +// throw new RuntimeException(); +// } +// +// @Specialization(order = 2) +// public boolean op2(boolean value) { +// return value; +// } +// +// } +// +// @Test +// public void testImplicitCast1() { +// ImplicitCast0Node node = ImplicitCast0NodeFactory.create(null); +// TestRootNode root = new TestRootNode<>(node); +// Assert.assertEquals("2", root.getNode().executeEvaluated(null, "2")); +// Assert.assertEquals(true, root.getNode().executeEvaluated(null, 1)); +// Assert.assertEquals("1", root.getNode().executeEvaluated(null, "1")); +// Assert.assertEquals(true, root.getNode().executeEvaluated(null, 1)); +// Assert.assertEquals(true, root.getNode().executeEvaluated(null, true)); +// } + // TODO assert implicit casts only in one direction // test example that covers the most cases diff -r 5151a7588384 -r 7aa2a8c69ba3 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java Wed Oct 02 15:57:17 2013 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java Thu Oct 03 16:31:09 2013 +0200 @@ -42,6 +42,7 @@ import com.oracle.truffle.dsl.processor.template.*; import com.oracle.truffle.dsl.processor.template.TemplateMethod.Signature; import com.oracle.truffle.dsl.processor.typesystem.*; +import com.sun.org.apache.xml.internal.dtm.ref.DTMDefaultBaseIterators.*; public class NodeCodeGenerator extends CompilationUnitFactory { @@ -953,6 +954,10 @@ } } + for (CodeExecutableElement method : createImplicitChildrenAccessors(node, clazz)) { + clazz.add(method); + } + clazz.add(createGenericExecuteAndSpecialize(node, rootGroup)); clazz.add(createInfoMessage(node)); } @@ -962,6 +967,50 @@ } } + private List createImplicitChildrenAccessors(NodeData node, CodeTypeElement clazz) { + List methods = new ArrayList<>(); + Map> expectTypes = new HashMap<>(); + for (ExecutableTypeData executableType : node.getExecutableTypes()) { + for (int i = 0; i < executableType.getEvaluatedCount(); i++) { + ActualParameter parameter = executableType.getSignatureParameter(i); + NodeChildData child = node.findChild(parameter.getSpecification().getName()); + Set types = expectTypes.get(child); + if (types == null) { + types = new TreeSet<>(); + expectTypes.put(child, types); + } + types.add(parameter.getTypeSystemType()); + } + } + + Map> visitedMap = new HashMap<>(); + for (SpecializationData spec : node.getSpecializations()) { + for (ActualParameter param : spec.getParameters()) { + if (!param.getSpecification().isSignature()) { + continue; + } + NodeChildData child = node.findChild(param.getSpecification().getName()); + Set visitedTypeData = visitedMap.get(child); + if (visitedTypeData == null) { + visitedTypeData = new TreeSet<>(); + visitedMap.put(child, visitedTypeData); + } + if (visitedTypeData.contains(param.getTypeSystemType())) { + continue; + } + visitedTypeData.add(param.getTypeSystemType()); + + Set expect = expectTypes.get(child); + if (expect == null) { + expect = Collections.emptySet(); + } + + methods.addAll(createExecuteChilds(param, expect)); + } + } + return methods; + } + private CodeTree truffleBooleanOption(CodeTreeBuilder parent, String name) { CodeTreeBuilder builder = parent.create(); builder.staticReference(getContext().getTruffleTypes().getTruffleOptions(), name); @@ -1946,37 +1995,119 @@ ActualParameter unexpectedParameter) { CodeTreeBuilder builder = parent.create(); - TypeData type = param.getTypeSystemType(); - List targetTypes = child.getNodeData().getTypeSystem().lookupSourceTypes(type); - - if (targetTypes.size() > 1) { - boolean elseIf = false; - int index = 0; - for (TypeData typeData : targetTypes) { - if (index < targetTypes.size() - 1) { - elseIf = builder.startIf(elseIf); - builder.string(typeName(param)).string(" == ").typeLiteral(typeData.getPrimitiveType()); - builder.end(); - builder.startBlock(); - } else { - builder.startElseBlock(); + ActualParameter sourceParameter = sourceExecutable.findParameter(param.getLocalName()); + + String childExecuteName = createExecuteChildMethodName(param, sourceParameter != null); + if (childExecuteName != null) { + builder.string(valueName(param)); + builder.string(" = "); + builder.startCall(childExecuteName); + + for (ActualParameter parameters : sourceExecutable.getParameters()) { + if (parameters.getSpecification().isSignature()) { + continue; } - - ExecutableTypeData implictExecutableTypeData = child.getNodeData().findExecutableType(typeData, targetExecutable.getEvaluatedCount()); - ImplicitCastData cast = child.getNodeData().getTypeSystem().lookupCast(typeData, param.getTypeSystemType()); - CodeTree execute = createExecuteExpression(parent, child, sourceExecutable, implictExecutableTypeData, param, unexpectedParameter, cast); - builder.statement(execute); - builder.end(); - index++; + builder.string(parameters.getLocalName()); + } + + if (sourceParameter != null) { + builder.string(valueNameEvaluated(sourceParameter)); } + + builder.string(typeName(param)); + + builder.end(); } else { - builder.tree(createExecuteExpression(parent, child, sourceExecutable, targetExecutable, param, unexpectedParameter, null)); + TypeData expectType = sourceParameter != null ? sourceParameter.getTypeSystemType() : null; + builder.tree(createExecuteExpression(parent, child, expectType, targetExecutable, param, unexpectedParameter, null)); } return builder.getRoot(); } - private CodeTree createExecuteExpression(CodeTreeBuilder parent, NodeChildData child, ExecutableTypeData sourceExecutable, ExecutableTypeData targetExecutable, - ActualParameter targetParameter, ActualParameter unexpectedParameter, ImplicitCastData cast) { + private String createExecuteChildMethodName(ActualParameter param, boolean expect) { + NodeChildData child = getModel().getNode().findChild(param.getSpecification().getName()); + List sourceTypes = child.getNodeData().getTypeSystem().lookupSourceTypes(param.getTypeSystemType()); + if (sourceTypes.size() <= 1) { + return null; + } + String prefix = expect ? "expect" : "execute"; + return prefix + Utils.firstLetterUpperCase(child.getName()) + Utils.firstLetterUpperCase(Utils.getSimpleName(param.getType())) + param.getIndex(); + } + + private List createExecuteChilds(ActualParameter param, Set expectTypes) { + CodeExecutableElement executeMethod = createExecuteChild(param, null); + if (executeMethod == null) { + return Collections.emptyList(); + } + List childs = new ArrayList<>(); + childs.add(executeMethod); + + for (TypeData expectType : expectTypes) { + CodeExecutableElement method = createExecuteChild(param, expectType); + if (method != null) { + childs.add(method); + } + } + return childs; + } + + private CodeExecutableElement createExecuteChild(ActualParameter param, TypeData expectType) { + String childExecuteName = createExecuteChildMethodName(param, expectType != null); + if (childExecuteName == null) { + return null; + } + + NodeData node = getModel().getNode(); + NodeChildData child = node.findChild(param.getSpecification().getName()); + List sourceTypes = node.getTypeSystem().lookupSourceTypes(param.getTypeSystemType()); + assert sourceTypes.size() >= 1; + + CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, expectType != null ? STATIC : FINAL), param.getType(), childExecuteName); + + method.addParameter(new CodeVariableElement(getContext().getTruffleTypes().getFrame(), "frameValue")); + if (expectType != null) { + method.addParameter(new CodeVariableElement(expectType.getPrimitiveType(), valueNameEvaluated(param))); + } + method.addParameter(new CodeVariableElement(getContext().getType(Class.class), typeName(param))); + CodeTreeBuilder builder = method.createBuilder(); + + builder.declaration(param.getType(), valueName(param)); + + boolean unexpected = false; + boolean elseIf = false; + int index = 0; + for (TypeData typeData : sourceTypes) { + if (index < sourceTypes.size() - 1) { + elseIf = builder.startIf(elseIf); + builder.string(typeName(param)).string(" == ").typeLiteral(typeData.getPrimitiveType()); + builder.end(); + builder.startBlock(); + } else { + builder.startElseBlock(); + } + + ExecutableTypeData implictExecutableTypeData = child.getNodeData().findExecutableType(typeData, child.getExecuteWith().size()); + if (!unexpected && implictExecutableTypeData.hasUnexpectedValue(getContext())) { + unexpected = true; + } + ImplicitCastData cast = child.getNodeData().getTypeSystem().lookupCast(typeData, param.getTypeSystemType()); + CodeTree execute = createExecuteExpression(builder, child, expectType, implictExecutableTypeData, param, null, cast); + builder.statement(execute); + builder.end(); + index++; + } + + builder.startReturn().string(valueName(param)).end(); + + if (unexpected) { + method.getThrownTypes().add(getContext().getTruffleTypes().getUnexpectedValueException()); + } + + return method; + } + + private CodeTree createExecuteExpression(CodeTreeBuilder parent, NodeChildData child, TypeData expectType, ExecutableTypeData targetExecutable, ActualParameter targetParameter, + ActualParameter unexpectedParameter, ImplicitCastData cast) { CodeTreeBuilder builder = parent.create(); builder.string(valueName(targetParameter)); builder.string(" = "); @@ -1989,12 +2120,11 @@ } NodeData node = getModel().getNode(); - ActualParameter sourceParameter = sourceExecutable.findParameter(targetParameter.getLocalName()); - if (sourceParameter == null) { + if (expectType == null) { builder.tree(createExecuteChildExpression(builder, child, targetParameter, targetExecutable, unexpectedParameter)); } else { CodeTree var = CodeTreeBuilder.singleString(valueNameEvaluated(targetParameter)); - builder.tree(createExpectExecutableType(node, sourceParameter.getTypeSystemType(), targetExecutable, var)); + builder.tree(createExpectExecutableType(node, expectType, targetExecutable, var)); } if (targetExecutable.getType().needsCastTo(context, targetParameter.getTypeSystemType())) {