# HG changeset patch # User Christian Humer # Date 1380816479 -7200 # Node ID 4e26955b6da280d9988877f8c7877df705211d88 # Parent 7aa2a8c69ba3bb77e3abe5e00f3b96968ecd3176 Truffle-DSL: new implicit cast code generation layout supports now executeWith. diff -r 7aa2a8c69ba3 -r 4e26955b6da2 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 Thu Oct 03 16:31:09 2013 +0200 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ImplicitCastTest.java Thu Oct 03 18:07:59 2013 +0200 @@ -26,6 +26,8 @@ import com.oracle.truffle.api.dsl.*; import com.oracle.truffle.api.dsl.test.ImplicitCastTestFactory.ImplicitCast0NodeFactory; +import com.oracle.truffle.api.dsl.test.ImplicitCastTestFactory.ImplicitCast1NodeFactory; +import com.oracle.truffle.api.dsl.test.ImplicitCastTestFactory.ImplicitCast2NodeFactory; import com.oracle.truffle.api.dsl.test.NodeContainerTest.Str; import com.oracle.truffle.api.dsl.test.TypeSystemTest.TestRootNode; import com.oracle.truffle.api.dsl.test.TypeSystemTest.ValueNode; @@ -54,12 +56,12 @@ public abstract Object executeEvaluated(VirtualFrame frame, Object value2); - @Specialization + @Specialization(order = 1) public String op1(String value) { return value; } - @Specialization + @Specialization(order = 2) public boolean op1(boolean value) { return value; } @@ -77,40 +79,81 @@ 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)); -// } + @TypeSystemReference(ImplicitCast0Types.class) + @NodeChild(value = "operand", type = ImplicitCast1Node.class) + // TODO temporary workaround + @PolymorphicLimit(1) + abstract static class ImplicitCast1Node extends ValueNode { + + public abstract Object executeEvaluated(VirtualFrame frame, Object operand); + + @Specialization(order = 0) + 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() { + ImplicitCast1Node node = ImplicitCast1NodeFactory.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 + @TypeSystemReference(ImplicitCast0Types.class) + @NodeChildren({@NodeChild(value = "operand0", type = ImplicitCast2Node.class), @NodeChild(value = "operand1", type = ImplicitCast2Node.class, executeWith = "operand0")}) + // TODO temporary workaround + @PolymorphicLimit(1) + abstract static class ImplicitCast2Node extends ValueNode { + + @Specialization(order = 0) + public String op0(String v0, String v1) { + return v0 + v1; + } + + @SuppressWarnings("unused") + @Specialization(order = 1, rewriteOn = RuntimeException.class) + public boolean op1(boolean v0, boolean v1) throws RuntimeException { + throw new RuntimeException(); + } - // test example that covers the most cases + @Specialization(order = 2) + public boolean op2(boolean v0, boolean v1) { + return v0 && v1; + } + + public abstract Object executeEvaluated(VirtualFrame frame, Object v1); + + public abstract Object executeEvaluated(VirtualFrame frame, Object v1, Object v2); + + public abstract Object executeEvaluated(VirtualFrame frame, boolean v1, boolean v2); + + } + + @Test + public void testImplicitCast2() { + ImplicitCast2Node node = ImplicitCast2NodeFactory.create(null, 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)); + } } diff -r 7aa2a8c69ba3 -r 4e26955b6da2 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 Thu Oct 03 16:31:09 2013 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java Thu Oct 03 18:07:59 2013 +0200 @@ -42,7 +42,6 @@ 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 { @@ -954,7 +953,7 @@ } } - for (CodeExecutableElement method : createImplicitChildrenAccessors(node, clazz)) { + for (CodeExecutableElement method : createImplicitChildrenAccessors()) { clazz.add(method); } @@ -967,7 +966,8 @@ } } - private List createImplicitChildrenAccessors(NodeData node, CodeTypeElement clazz) { + private List createImplicitChildrenAccessors() { + NodeData node = getModel().getNode(); List methods = new ArrayList<>(); Map> expectTypes = new HashMap<>(); for (ExecutableTypeData executableType : node.getExecutableTypes()) { @@ -2018,14 +2018,22 @@ builder.end(); } else { + List sourceTypes = child.getNodeData().getTypeSystem().lookupSourceTypes(param.getTypeSystemType()); TypeData expectType = sourceParameter != null ? sourceParameter.getTypeSystemType() : null; - builder.tree(createExecuteExpression(parent, child, expectType, targetExecutable, param, unexpectedParameter, null)); + if (sourceTypes.size() > 1) { + builder.tree(createExecuteExpressions(parent, param, expectType)); + } else { + builder.tree(createExecuteExpression(parent, child, expectType, targetExecutable, param, unexpectedParameter, null)); + } } return builder.getRoot(); } private String createExecuteChildMethodName(ActualParameter param, boolean expect) { NodeChildData child = getModel().getNode().findChild(param.getSpecification().getName()); + if (child.getExecuteWith().size() > 0) { + return null; + } List sourceTypes = child.getNodeData().getTypeSystem().lookupSourceTypes(param.getTypeSystemType()); if (sourceTypes.size() <= 1) { return null; @@ -2057,53 +2065,56 @@ 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.getThrownTypes().add(getContext().getTruffleTypes().getUnexpectedValueException()); 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; + builder.tree(createExecuteExpressions(builder, param, expectType)); + builder.startReturn().string(valueName(param)).end(); + + return method; + } + + private CodeTree createExecuteExpressions(CodeTreeBuilder parent, ActualParameter param, TypeData expectType) { + CodeTreeBuilder builder = parent.create(); + NodeData node = getModel().getNode(); + NodeChildData child = node.findChild(param.getSpecification().getName()); + List sourceTypes = node.getTypeSystem().lookupSourceTypes(param.getTypeSystemType()); boolean elseIf = false; int index = 0; - for (TypeData typeData : sourceTypes) { + for (TypeData sourceType : sourceTypes) { if (index < sourceTypes.size() - 1) { elseIf = builder.startIf(elseIf); - builder.string(typeName(param)).string(" == ").typeLiteral(typeData.getPrimitiveType()); + builder.string(typeName(param)).string(" == ").typeLiteral(sourceType.getPrimitiveType()); builder.end(); builder.startBlock(); } else { builder.startElseBlock(); } - ExecutableTypeData implictExecutableTypeData = child.getNodeData().findExecutableType(typeData, child.getExecuteWith().size()); - if (!unexpected && implictExecutableTypeData.hasUnexpectedValue(getContext())) { - unexpected = true; + ExecutableTypeData implictExecutableTypeData = child.getNodeData().findExecutableType(sourceType, child.getExecuteWith().size()); + if (implictExecutableTypeData == null) { + /* + * For children with executeWith.size() > 0 an executable type may not exist so + * use the generic executable type which is guaranteed to exist. An expect call + * is inserted automatically by #createExecuteExpression. + */ + implictExecutableTypeData = child.getNodeData().findExecutableType(node.getTypeSystem().getGenericTypeData(), child.getExecuteWith().size()); } - ImplicitCastData cast = child.getNodeData().getTypeSystem().lookupCast(typeData, param.getTypeSystemType()); + + ImplicitCastData cast = child.getNodeData().getTypeSystem().lookupCast(sourceType, 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; + return builder.getRoot(); } private CodeTree createExecuteExpression(CodeTreeBuilder parent, NodeChildData child, TypeData expectType, ExecutableTypeData targetExecutable, ActualParameter targetParameter, @@ -2115,8 +2126,13 @@ startCallTypeSystemMethod(getContext(), builder, child.getNodeData(), cast.getMethodName()); } - if (targetExecutable.getType().needsCastTo(context, targetParameter.getTypeSystemType()) && cast == null) { - startCallTypeSystemMethod(getContext(), builder, child.getNodeData(), TypeSystemCodeGenerator.expectTypeMethodName(targetParameter.getTypeSystemType())); + TypeData expectTarget = targetParameter.getTypeSystemType(); + if (cast != null) { + expectTarget = cast.getSourceType(); + } + + if (targetExecutable.getType().needsCastTo(context, expectTarget)) { + startCallTypeSystemMethod(getContext(), builder, child.getNodeData(), TypeSystemCodeGenerator.expectTypeMethodName(expectTarget)); } NodeData node = getModel().getNode();