# HG changeset patch # User Christian Humer # Date 1381758717 -7200 # Node ID bfcae72b61a05f04449bc4a6763b9a6a1ff9519f # Parent 85dcc7f59c34f59ceb9c9abb8dd71755b41b2f51# Parent ce5e6f9075b608d0af8863382f316ac815de69e0 merge. diff -r ce5e6f9075b6 -r bfcae72b61a0 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 Mon Oct 14 13:49:46 2013 +0200 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ImplicitCastTest.java Mon Oct 14 15:51:57 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; @@ -55,12 +57,12 @@ public abstract Object executeEvaluated(VirtualFrame frame, Object value2); @Specialization(order = 1) - public String op1(String value) throws RuntimeException { + public String op1(String value) { return value; } @Specialization(order = 2) - public boolean op1(boolean value) throws RuntimeException { + public boolean op1(boolean value) { return value; } @@ -77,8 +79,79 @@ Assert.assertEquals(true, root.getNode().executeEvaluated(null, true)); } - // TODO assert implicit casts only in one direction + @TypeSystemReference(ImplicitCast0Types.class) + @NodeChild(value = "operand", type = ImplicitCast1Node.class) + // TODO temporary workaround + 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)); + } - // test example that covers the most cases + @TypeSystemReference(ImplicitCast0Types.class) + @NodeChildren({@NodeChild(value = "operand0", type = ImplicitCast2Node.class), @NodeChild(value = "operand1", type = ImplicitCast2Node.class, executeWith = "operand0")}) + // TODO temporary workaround + 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(); + } + + @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("42", root.getNode().executeEvaluated(null, "4", "2")); + Assert.assertEquals(true, root.getNode().executeEvaluated(null, 1, 1)); + Assert.assertEquals("42", root.getNode().executeEvaluated(null, "4", "2")); + Assert.assertEquals(true, root.getNode().executeEvaluated(null, 1, 1)); + Assert.assertEquals(true, root.getNode().executeEvaluated(null, true, true)); + } } diff -r ce5e6f9075b6 -r bfcae72b61a0 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/SlowPathTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/SlowPathTest.java Mon Oct 14 15:51:57 2013 +0200 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.dsl.test; + +import org.junit.*; + +import com.oracle.truffle.api.CompilerDirectives.SlowPath; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.dsl.test.SlowPathTestFactory.SlowPathOnGeneric0Factory; +import com.oracle.truffle.api.dsl.test.SlowPathTestFactory.SlowPathOnGeneric1Factory; +import com.oracle.truffle.api.dsl.test.TypeSystemTest.ValueNode; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; + +/** Tests the generated placement of {@link SlowPath} in generated methods. */ +public class SlowPathTest { + + @Test + public void testSlowPathOnGeneric0() throws NoSuchMethodException, SecurityException { + Node node = SlowPathOnGeneric0Factory.create(null); + Assert.assertNull(node.getClass().getSuperclass().getDeclaredMethod("executeGeneric0", VirtualFrame.class, Object.class).getAnnotation(SlowPath.class)); + } + + @NodeChild + abstract static class SlowPathOnGeneric0 extends ValueNode { + + @Specialization + @SuppressWarnings("unused") + Object doObject0(VirtualFrame frame, int value0) { + throw new AssertionError(); + } + + } + + @Test + public void testSlowPathOnGeneric1() throws NoSuchMethodException, SecurityException { + Node node = SlowPathOnGeneric1Factory.create(null); + Assert.assertNotNull(node.getClass().getSuperclass().getDeclaredMethod("executeGeneric0", Object.class).getAnnotation(SlowPath.class)); + } + + @NodeChild + abstract static class SlowPathOnGeneric1 extends ValueNode { + + @Specialization + @SuppressWarnings("unused") + Object doObject0(int value0) { + throw new AssertionError(); + } + + } + +} diff -r ce5e6f9075b6 -r bfcae72b61a0 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/SpecializationGroupingTest.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/SpecializationGroupingTest.java Mon Oct 14 13:49:46 2013 +0200 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/SpecializationGroupingTest.java Mon Oct 14 15:51:57 2013 +0200 @@ -37,7 +37,8 @@ /** * Tests execution counts of guards. While we do not make guarantees for guard invocation except for - * their execution order our implementation reduces the calls to guards as much as possible. + * their execution order our implementation reduces the calls to guards as much as possible for the + * generic case. */ public class SpecializationGroupingTest { @@ -47,7 +48,7 @@ MockAssumption a2 = new MockAssumption(false); MockAssumption a3 = new MockAssumption(true); - TestRootNode root = TestHelper.createRoot(TestGroupingFactory.getInstance(), a1, a2, a3); + TestRootNode root = TestHelper.createGenericRoot(TestGroupingFactory.getInstance(), a1, a2, a3); SimpleTypes.intCast = 0; SimpleTypes.intCheck = 0; @@ -71,16 +72,16 @@ Assert.assertEquals(42, TestHelper.executeWith(root, 21, 21)); Assert.assertEquals(2, TestGrouping.true1); - Assert.assertEquals(1, TestGrouping.false1); + Assert.assertEquals(2, TestGrouping.false1); Assert.assertEquals(2, TestGrouping.true2); Assert.assertEquals(2, TestGrouping.false2); Assert.assertEquals(2, TestGrouping.true3); Assert.assertEquals(2, a1.checked); - Assert.assertEquals(1, a2.checked); + Assert.assertEquals(2, a2.checked); Assert.assertEquals(2, a3.checked); - Assert.assertEquals(2, SimpleTypes.intCheck); - Assert.assertEquals(2, SimpleTypes.intCast); + Assert.assertEquals(4, SimpleTypes.intCheck); + Assert.assertEquals(4, SimpleTypes.intCast); } diff -r ce5e6f9075b6 -r bfcae72b61a0 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TestHelper.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TestHelper.java Mon Oct 14 13:49:46 2013 +0200 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TestHelper.java Mon Oct 14 15:51:57 2013 +0200 @@ -61,10 +61,18 @@ return factory.createNode(argumentList.toArray(new Object[argumentList.size()])); } + static E createGenericNode(NodeFactory factory, Object... constants) { + return factory.createNodeGeneric(createNode(factory, constants)); + } + static TestRootNode createRoot(NodeFactory factory, Object... constants) { return new TestRootNode<>(createNode(factory, constants)); } + static TestRootNode createGenericRoot(NodeFactory factory, Object... constants) { + return new TestRootNode<>(createGenericNode(factory, constants)); + } + static CallTarget createCallTarget(ValueNode node) { return createCallTarget(new TestRootNode<>(node)); } diff -r ce5e6f9075b6 -r bfcae72b61a0 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/nodes/serial/PostOrderDeserializerTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/nodes/serial/PostOrderDeserializerTest.java Mon Oct 14 15:51:57 2013 +0200 @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.test.nodes.serial; + +import java.nio.*; +import java.util.*; + +import org.junit.*; + +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.api.nodes.serial.*; +import com.oracle.truffle.api.test.nodes.serial.TestNodes.EmptyNode; +import com.oracle.truffle.api.test.nodes.serial.TestNodes.NodeWithArray; +import com.oracle.truffle.api.test.nodes.serial.TestNodes.NodeWithFields; +import com.oracle.truffle.api.test.nodes.serial.TestNodes.NodeWithOneChild; +import com.oracle.truffle.api.test.nodes.serial.TestNodes.NodeWithThreeChilds; +import com.oracle.truffle.api.test.nodes.serial.TestNodes.NodeWithTwoArray; +import com.oracle.truffle.api.test.nodes.serial.TestNodes.NodeWithTwoChilds; +import com.oracle.truffle.api.test.nodes.serial.TestNodes.StringNode; + +public class PostOrderDeserializerTest { + + private PostOrderDeserializer d; + private TestSerializerConstantPool cp; + + @Before + public void setUp() { + cp = new TestSerializerConstantPool(); + d = new PostOrderDeserializer(cp); + } + + @After + public void tearDown() { + d = null; + cp = null; + } + + private Node deserialize(byte[] bytes) { + return d.deserialize(bytes, Node.class); + } + + @Test + public void testNull() { + createCP(); + Node ast = deserialize(createBytes(VariableLengthIntBuffer.NULL)); + Assert.assertNull(ast); + } + + @Test + public void testSingleNode() { + createCP(EmptyNode.class); + Node expectedAst = new EmptyNode(); + Node ast = deserialize(createBytes(0)); + assertAST(expectedAst, ast); + } + + @Test + public void testThreeChilds() { + createCP(EmptyNode.class, NodeWithThreeChilds.class); + Node expectedAst = new NodeWithThreeChilds(new EmptyNode(), null, new EmptyNode()); + Node ast = deserialize(createBytes(0, VariableLengthIntBuffer.NULL, 0, 1)); + assertAST(expectedAst, ast); + } + + @Test + public void testFields() { + createCP(NodeWithFields.class, "test", Integer.MIN_VALUE, Integer.MAX_VALUE, Long.MIN_VALUE, Long.MAX_VALUE, Float.MIN_VALUE, Float.MAX_VALUE, Double.MIN_VALUE, Double.MAX_VALUE, + (int) Character.MIN_VALUE, (int) Character.MAX_VALUE, (int) Short.MIN_VALUE, (int) Short.MAX_VALUE, (int) Byte.MIN_VALUE, (int) Byte.MAX_VALUE, 1); + NodeWithFields expectedAst = new NodeWithFields("test", Integer.MIN_VALUE, Integer.MAX_VALUE, Long.MIN_VALUE, Long.MAX_VALUE, Float.MIN_VALUE, Float.MAX_VALUE, Double.MIN_VALUE, + Double.MAX_VALUE, Character.MIN_VALUE, Character.MAX_VALUE, Short.MIN_VALUE, Short.MAX_VALUE, Byte.MIN_VALUE, Byte.MAX_VALUE, Boolean.TRUE, Boolean.FALSE); + Node ast = deserialize(createBytes(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 10)); + assertAST(expectedAst, ast); + } + + @Test + public void testFieldsNull() { + createCP(NodeWithFields.class, "test", 0, 0L, 0.0F, 0.0D); + NodeWithFields expectedAst = new NodeWithFields("test", 0, null, 0L, null, 0f, null, 0d, null, (char) 0, null, (short) 0, null, (byte) 0, null, false, null); + int nil = VariableLengthIntBuffer.NULL; + Node ast = deserialize(createBytes(0, 1, 2, nil, 3, nil, 4, nil, 5, nil, 2, nil, 2, nil, 2, nil, 2, nil)); + assertAST(expectedAst, ast); + } + + @Test + public void testNullChilds() { + createCP(Node[].class, NodeWithArray.class); + Node expectedAst = new NodeWithArray(null); + Node ast = deserialize(createBytes(0, VariableLengthIntBuffer.NULL, 1)); + assertAST(expectedAst, ast); + } + + @Test + public void testNChilds() { + Node expectedAst = new NodeWithArray(new Node[]{new EmptyNode(), new NodeWithArray(new Node[]{new EmptyNode(), new EmptyNode(), new EmptyNode()}), new EmptyNode(), new EmptyNode()}); + createCP(Node[].class, 4, EmptyNode.class, 3, NodeWithArray.class); + Node ast = deserialize(createBytes(0, 1, 2, 0, 3, 2, 2, 2, 4, 2, 2, 4)); + + assertAST(expectedAst, ast); + } + + @Test + public void test2xNChilds() { + Node expectedAst = new NodeWithTwoArray(new Node[]{new StringNode("a0"), new StringNode("a1")}, new Node[]{new StringNode("b0"), new StringNode("b1"), new StringNode("b2")}); + createCP(Node[].class, 2, StringNode.class, "a0", "a1", 3, "b0", "b1", "b2", NodeWithTwoArray.class); + Node ast = deserialize(createBytes(0, 1, 2, 3, 2, 4, 0, 5, 2, 6, 2, 7, 2, 8, 9)); + + assertAST(expectedAst, ast); + } + + @Test + public void testBug0() { + Node expectedAst = new NodeWithArray(new Node[]{new NodeWithOneChild(new EmptyNode())}); + + createCP(Node[].class, 1, EmptyNode.class, NodeWithOneChild.class, NodeWithArray.class); + Node ast = deserialize(createBytes(0, 1, 2, 3, 4)); + assertAST(expectedAst, ast); + } + + @Test + public void testBug1() { + Node expectedAst = new NodeWithArray(new Node[]{new NodeWithTwoChilds(new EmptyNode(), new EmptyNode())}); + + createCP(Node[].class, 1, EmptyNode.class, NodeWithTwoChilds.class, NodeWithArray.class); + Node ast = deserialize(createBytes(0, 1, 2, 2, 3, 4)); + assertAST(expectedAst, ast); + } + + private static void assertAST(Node expectedAst, Node actualAst) { + if (expectedAst == null) { + Assert.assertNull(actualAst); + return; + } + + Assert.assertNotNull(actualAst); + // fields are asserted using the corresponding equals implementation + Assert.assertEquals(expectedAst, actualAst); + + Iterable expectedChildIterator = expectedAst.getChildren(); + Iterator actualChildIterator = actualAst.getChildren().iterator(); + for (Node node : expectedChildIterator) { + Assert.assertTrue(actualChildIterator.hasNext()); + assertAST(node, actualChildIterator.next()); + } + Assert.assertFalse(actualChildIterator.hasNext()); + } + + private static byte[] createBytes(int... refs) { + VariableLengthIntBuffer buf = new VariableLengthIntBuffer(ByteBuffer.allocate(512)); + for (int i = 0; i < refs.length; i++) { + buf.put(refs[i]); + } + return buf.getBytes(); + } + + private void createCP(Object... cpData) { + for (int i = 0; i < cpData.length; i++) { + Object object = cpData[i]; + + cp.putObject(object.getClass(), object); + + } + } + +} diff -r ce5e6f9075b6 -r bfcae72b61a0 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/nodes/serial/PostOrderSerializerTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/nodes/serial/PostOrderSerializerTest.java Mon Oct 14 15:51:57 2013 +0200 @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.test.nodes.serial; + +import org.junit.*; + +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.api.nodes.serial.*; +import com.oracle.truffle.api.test.nodes.serial.TestNodes.EmptyNode; +import com.oracle.truffle.api.test.nodes.serial.TestNodes.NodeWithArray; +import com.oracle.truffle.api.test.nodes.serial.TestNodes.NodeWithFields; +import com.oracle.truffle.api.test.nodes.serial.TestNodes.NodeWithThreeChilds; +import com.oracle.truffle.api.test.nodes.serial.TestNodes.NodeWithTwoArray; +import com.oracle.truffle.api.test.nodes.serial.TestNodes.StringNode; + +public class PostOrderSerializerTest { + + private PostOrderSerializer s; + private TestSerializerConstantPool cp; + + @Before + public void setUp() { + cp = new TestSerializerConstantPool(); + s = new PostOrderSerializer(cp); + } + + @After + public void tearDown() { + cp = null; + s = null; + } + + @Test + public void testNull() { + Node ast = null; + assertBytes(s.serialize(ast), VariableLengthIntBuffer.NULL); + assertCP(); + } + + @Test + public void testSingleEmptyNode() { + Node ast = new EmptyNode(); + assertBytes(s.serialize(ast), 0); + assertCP(EmptyNode.class); + } + + @Test + public void testThreeChilds() { + Node ast = new NodeWithThreeChilds(new EmptyNode(), null, new EmptyNode()); + assertBytes(s.serialize(ast), 0, VariableLengthIntBuffer.NULL, 0, 1); + assertCP(EmptyNode.class, NodeWithThreeChilds.class); + } + + @Test + public void testFields() { + NodeWithFields ast = new NodeWithFields("test", Integer.MIN_VALUE, Integer.MAX_VALUE, Long.MIN_VALUE, Long.MAX_VALUE, Float.MIN_VALUE, Float.MAX_VALUE, Double.MIN_VALUE, Double.MAX_VALUE, + Character.MIN_VALUE, Character.MAX_VALUE, Short.MIN_VALUE, Short.MAX_VALUE, Byte.MIN_VALUE, Byte.MAX_VALUE, Boolean.TRUE, Boolean.FALSE); + assertBytes(s.serialize(ast), 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 10); + assertCP(NodeWithFields.class, "test", Integer.MIN_VALUE, Integer.MAX_VALUE, Long.MIN_VALUE, Long.MAX_VALUE, Float.MIN_VALUE, Float.MAX_VALUE, Double.MIN_VALUE, Double.MAX_VALUE, + (int) Character.MIN_VALUE, (int) Character.MAX_VALUE, (int) Short.MIN_VALUE, (int) Short.MAX_VALUE, (int) Byte.MIN_VALUE, (int) Byte.MAX_VALUE, 1); + } + + @Test + public void testFieldsNull() { + NodeWithFields ast = new NodeWithFields("test", 0, null, 0L, null, 0f, null, 0d, null, (char) 0, null, (short) 0, null, (byte) 0, null, false, null); + int nil = VariableLengthIntBuffer.NULL; + assertBytes(s.serialize(ast), 0, 1, 2, nil, 3, nil, 4, nil, 5, nil, 2, nil, 2, nil, 2, nil, 2, nil); + assertCP(NodeWithFields.class, "test", 0, 0L, 0.0F, 0.0D); + } + + @Test + public void testNChilds() { + Node ast = new NodeWithArray(new Node[]{new EmptyNode(), new NodeWithArray(new Node[]{new EmptyNode(), new EmptyNode(), new EmptyNode()}), new EmptyNode(), new EmptyNode()}); + assertBytes(s.serialize(ast), 0, 1, 2, 0, 3, 2, 2, 2, 4, 2, 2, 4); + assertCP(Node[].class, 4, EmptyNode.class, 3, NodeWithArray.class); + } + + @Test + public void testNullChilds() { + Node ast = new NodeWithArray(null); + assertBytes(s.serialize(ast), 0, VariableLengthIntBuffer.NULL, 1); + assertCP(Node[].class, NodeWithArray.class); + } + + @Test + public void test2xNChilds() { + Node ast = new NodeWithTwoArray(new Node[]{new StringNode("a0"), new StringNode("a1")}, new Node[]{new StringNode("b0"), new StringNode("b1"), new StringNode("b2")}); + assertBytes(s.serialize(ast), 0, 1, 2, 3, 2, 4, 0, 5, 2, 6, 2, 7, 2, 8, 9); + assertCP(Node[].class, 2, StringNode.class, "a0", "a1", 3, "b0", "b1", "b2", NodeWithTwoArray.class); + } + + private static void assertBytes(byte[] actualBytes, int... expectedIndexes) { + VariableLengthIntBuffer buf = new VariableLengthIntBuffer(actualBytes); + for (int i = 0; i < expectedIndexes.length; i++) { + Assert.assertTrue("Unexpected EOF " + i, buf.hasRemaining()); + Assert.assertEquals("Index at pos " + i + ".", expectedIndexes[i], buf.get()); + } + Assert.assertFalse(buf.hasRemaining()); + } + + private void assertCP(Object... object) { + for (int i = 0; i < object.length; i++) { + Object cpvalue = object[i]; + Assert.assertNotNull("CP at index " + i, cpvalue); + Assert.assertEquals("CP at index " + i, cpvalue, cp.getObject(cpvalue.getClass(), i)); + } + Assert.assertEquals(object.length, cp.getIndex()); + } + +} diff -r ce5e6f9075b6 -r bfcae72b61a0 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/nodes/serial/TestNodes.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/nodes/serial/TestNodes.java Mon Oct 14 15:51:57 2013 +0200 @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.test.nodes.serial; + +import java.util.*; + +import com.oracle.truffle.api.nodes.*; + +final class TestNodes { + + private TestNodes() { + } + + static class StringNode extends Node { + + private final String name; + + public StringNode(String name) { + this.name = name; + } + + @Override + public int hashCode() { + return Objects.hash(name); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } else if (obj.getClass() != getClass()) { + return false; + } else if ((((Node) obj).getParent() != null) && !((Node) obj).getParent().equals(getParent())) { + return false; + } else if (!Objects.equals(name, ((StringNode) obj).name)) { + return false; + } + return true; + } + } + + static class EmptyNode extends Node { + + @Override + public int hashCode() { + return super.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } else if (obj.getClass() != getClass()) { + return false; + } else if ((((Node) obj).getParent() != null) && !((Node) obj).getParent().equals(getParent())) { + return false; + } + return true; + } + } + + static class NodeWithOneChild extends EmptyNode { + + @Child Node child; + + public NodeWithOneChild(Node child) { + this.child = adoptChild(child); + } + + } + + static class NodeWithTwoChilds extends EmptyNode { + + @Child Node child1; + @Child Node child2; + + public NodeWithTwoChilds(Node child1, Node child2) { + this.child1 = adoptChild(child1); + this.child2 = adoptChild(child2); + } + + } + + static class NodeWithThreeChilds extends EmptyNode { + + @Child Node child1; + @Child Node child2; + @Child Node child3; + + public NodeWithThreeChilds(Node child1, Node child2, Node child3) { + this.child1 = adoptChild(child1); + this.child2 = adoptChild(child2); + this.child3 = adoptChild(child3); + } + + } + + static class NodeWithArray extends EmptyNode { + + @Children private final Node[] childNodes; + + NodeWithArray(Node[] children) { + this.childNodes = adoptChildren(children); + } + + Node[] getChildNodes() { + return childNodes; + } + } + + static class NodeWithTwoArray extends EmptyNode { + + @Children private final Node[] childNodes1; + @Children private final Node[] childNodes2; + + NodeWithTwoArray(Node[] childs1, Node[] childs2) { + this.childNodes1 = adoptChildren(childs1); + this.childNodes2 = adoptChildren(childs2); + } + + Node[] getChildNodes1() { + return childNodes1; + } + + Node[] getChildNodes2() { + return childNodes2; + } + } + + static class NodeWithFields extends EmptyNode { + + String stringField; + int integerField; + Integer integerObjectField; + long longField; + Long longObjectField; + float floatField; + Float floatObjectField; + double doubleField; + Double doubleObjectField; + char charField; + Character charObjectField; + short shortField; + Short shortObjecField; + byte byteField; + Byte byteObjectField; + boolean booleanField; + Boolean booleanObjectfield; + + public NodeWithFields(String stringField, int integerField, Integer integerObjectField, long longField, Long longObjectField, float floatField, Float floatObjectField, double doubleField, + Double doubleObjectField, char charField, Character charObjectField, short shortField, Short shortObjecField, byte byteField, Byte byteObjectField, boolean booleanField, + Boolean booleanObjectfield) { + this.stringField = stringField; + this.integerField = integerField; + this.integerObjectField = integerObjectField; + this.longField = longField; + this.longObjectField = longObjectField; + this.floatField = floatField; + this.floatObjectField = floatObjectField; + this.doubleField = doubleField; + this.doubleObjectField = doubleObjectField; + this.charField = charField; + this.charObjectField = charObjectField; + this.shortField = shortField; + this.shortObjecField = shortObjecField; + this.byteField = byteField; + this.byteObjectField = byteObjectField; + this.booleanField = booleanField; + this.booleanObjectfield = booleanObjectfield; + } + + @Override + public int hashCode() { + return Objects.hash(stringField, integerField, integerObjectField, longField, longObjectField, floatField, floatObjectField, doubleField, doubleObjectField, charField, charObjectField, + shortField, shortObjecField, byteField, byteObjectField, booleanField, booleanObjectfield); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj.getClass() != getClass()) { + return false; + } + NodeWithFields o = (NodeWithFields) obj; + return Objects.deepEquals(fieldArray(), o.fieldArray()); + } + + private Object[] fieldArray() { + return array(stringField, integerField, integerObjectField, longField, longObjectField, floatField, floatObjectField, doubleField, doubleObjectField, charField, charObjectField, + shortField, shortObjecField, byteField, byteObjectField, booleanField, booleanObjectfield); + } + + private static Object[] array(Object... values) { + return values; + } + + } + +} diff -r ce5e6f9075b6 -r bfcae72b61a0 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/nodes/serial/TestSerializerConstantPool.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/nodes/serial/TestSerializerConstantPool.java Mon Oct 14 15:51:57 2013 +0200 @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.test.nodes.serial; + +import java.util.*; + +import com.oracle.truffle.api.nodes.serial.*; + +class TestSerializerConstantPool implements SerializerConstantPool { + + private final Map int2object = new HashMap<>(); + private final Map object2int = new HashMap<>(); + + private int index; + + public void setIndex(int index) { + this.index = index; + } + + public int getIndex() { + return index; + } + + @Override + public double getDouble(int cpi) { + return (Double) int2object.get(cpi); + } + + @Override + public float getFloat(int cpi) { + return (Float) int2object.get(cpi); + } + + @Override + public Object getObject(Class clazz, int cpi) throws UnsupportedConstantPoolTypeException { + return int2object.get(cpi); + } + + @Override + public int putDouble(double value) { + return put(value); + } + + public int putFloat(float value) { + return put(value); + } + + public int putObject(java.lang.Class clazz, Object value) throws UnsupportedConstantPoolTypeException { + return put(value); + } + + @Override + public int putClass(Class clazz) { + return put(clazz); + } + + private int put(Object o) { + Integer currentIndex = object2int.get(o); + if (currentIndex == null) { + int2object.put(index, o); + object2int.put(o, index); + return index++; + } else { + return currentIndex; + } + } + + @Override + public Class getClass(int idx) { + return (Class) int2object.get(idx); + } + + @Override + public int putInt(int constant) { + return put(constant); + } + + @Override + public int getInt(int idx) { + return (Integer) int2object.get(idx); + } + + @Override + public long getLong(int idx) { + return (Long) int2object.get(idx); + } + + @Override + public int putLong(long value) { + return put(value); + } + +} diff -r ce5e6f9075b6 -r bfcae72b61a0 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/nodes/serial/VariableLengthIntBufferTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/nodes/serial/VariableLengthIntBufferTest.java Mon Oct 14 15:51:57 2013 +0200 @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.test.nodes.serial; + +import java.nio.*; + +import org.junit.*; + +import com.oracle.truffle.api.nodes.serial.*; + +public class VariableLengthIntBufferTest { + + private VariableLengthIntBuffer buf; + + @Before + public void setUp() { + buf = new VariableLengthIntBuffer(ByteBuffer.allocate(512)); + } + + @After + public void tearDown() { + buf = null; + } + + @Test + public void testPutNull() { + buf.put(VariableLengthIntBuffer.NULL); + assertBytes(0xFF); + } + + @Test + public void testPutByteCornerCase0() { + buf.put(0x00); // 0 + assertBytes(0x00); + } + + @Test + public void testPutByteCornerCase1() { + buf.put(0x7F); // 127 + assertBytes(0x7F); + } + + @Test + public void testPutByteCornerCase2() { + buf.put(0x3FFF_FFFF); + assertBytes(0xBF, 0xFF, 0xFF, 0xFF); + } + + @Test(expected = IllegalArgumentException.class) + public void testPutByteCornerCase3() { + buf.put(0x4000_0000); // out of encodeable + } + + @Test + public void testGetNull() { + create(0xFF); + assertGet(VariableLengthIntBuffer.NULL); + } + + @Test + public void testGetCornerCase0() { + create(0x00); + assertGet(0x00); + } + + @Test + public void testGetCornerCase1() { + create(0x7F); + assertGet(0x7F); + } + + @Test + public void testGetCornerCase2() { + create(0xBF, 0xFF, 0xFF, 0xFF); + assertGet(0x3FFF_FFFF); + } + + @Test(expected = AssertionError.class) + public void testGetCornerCase3() { + create(0xFF, 0xFF, 0xFF, 0xFF); + assertGet(0x0); + } + + private void create(int... bytes) { + byte[] convBytes = new byte[bytes.length]; + for (int i = 0; i < bytes.length; i++) { + convBytes[i] = (byte) bytes[i]; + } + buf = new VariableLengthIntBuffer(convBytes); + } + + private void assertGet(int expected) { + Assert.assertEquals(expected, buf.get()); + } + + private void assertBytes(int... expectedBytes) { + byte[] actualBytes = buf.getBytes(); + Assert.assertEquals(expectedBytes.length, actualBytes.length); + for (int i = 0; i < expectedBytes.length; i++) { + Assert.assertTrue(actualBytes[i] == (byte) expectedBytes[i]); + } + } + +} diff -r ce5e6f9075b6 -r bfcae72b61a0 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/serial/PostOrderDeserializer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/serial/PostOrderDeserializer.java Mon Oct 14 15:51:57 2013 +0200 @@ -0,0 +1,366 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.nodes.serial; + +import java.lang.reflect.*; +import java.util.*; + +import sun.misc.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.api.nodes.NodeUtil.*; + +/** + * Experimental API. May change without notice. + */ +public final class PostOrderDeserializer { + + private static final Unsafe unsafe = loadUnsafe(); + + private final SerializerConstantPool cp; + + private final HierarchicalStack stack = new HierarchicalStack(); + + /** + * Constructs a new serializer using a custom {@link SerializerConstantPool} implementation. For + * the {@link SerializerConstantPool} implementation at least the following methods must be + * implemented: + *
    + *
  • {@link SerializerConstantPool#getInt(int)}
  • + *
  • {@link SerializerConstantPool#getClass(int)}
  • + *
+ */ + public PostOrderDeserializer(SerializerConstantPool cp) { + this.cp = cp; + } + + /** + * Deserializes the byte stream and returns the deserialized Truffle AST node. + * + * @param bytes the trimmed byte array containing the serialized data + * @param expectedType the expected root node type. Throws an exception if the root node is not + * assignable from this type. + * @return the deserialized Truffle AST represented by the root Node. + * + * @throws UnsupportedConstantPoolTypeException thrown if a type is encountered that is not + * supported by the constant pool implementation. + */ + @SuppressWarnings("unchecked") + public T deserialize(byte[] bytes, Class expectedType) throws UnsupportedConstantPoolTypeException { + VariableLengthIntBuffer buffer = new VariableLengthIntBuffer(bytes); + + while (buffer.hasRemaining()) { + int classCPI = buffer.get(); + if (classCPI == VariableLengthIntBuffer.NULL) { + pushNode(null); + } else { + Class clazz = cp.getClass(classCPI); + if (clazz.isArray()) { + int lengthCPI = buffer.get(); + if (lengthCPI == VariableLengthIntBuffer.NULL) { + pushArray(null); + } else { + pushArray((Node[]) Array.newInstance(clazz.getComponentType(), cp.getInt(lengthCPI))); + } + } else { + pushNode(invokeDeserialize(buffer, clazz.asSubclass(Node.class))); + } + } + } + T returnNode = (T) popNode(null, expectedType); + + assert stack.dynamicStack.isEmpty(); + + return returnNode; + } + + private void pushNode(Node node) { + stack.push(node); + } + + private void pushArray(Node[] array) { + stack.pushStack(array); + } + + private Node[] popArray(Node parent, Class expectedType) { + Node[] array = (Node[]) stack.popStack(); + if (array != null) { + assertType(array, expectedType); + for (int i = 0; i < array.length; i++) { + updateParent(parent, array[i]); + } + } + return array; + } + + private Node popNode(Node parent, Class expectedType) { + Object o = stack.pop(); + assertType(o, expectedType); + updateParent(parent, (Node) o); + return (Node) o; + } + + private static void assertType(Object o, Class expectedType) { + if (o != null && !expectedType.isAssignableFrom(o.getClass())) { + throw new AssertionError("Expected element type '" + expectedType.getName() + "' but was '" + o.getClass().getName() + "'."); + } + } + + private Node invokeDeserialize(VariableLengthIntBuffer buffer, Class nodeClass) throws UnsupportedConstantPoolTypeException { + if (nodeClass == null) { + return null; + } + + Object object; + try { + object = unsafe.allocateInstance(nodeClass); + } catch (InstantiationException e) { + throw new RuntimeException("Unable to allocate truffle node " + nodeClass, e); + } + if (!(object instanceof Node)) { + throw new RuntimeException("Class is not a truffle node " + nodeClass); + } + + Node node = (Node) object; + + NodeField[] nodeFields = NodeClass.get(nodeClass).getFields(); + deserializeChildrenFields(node, nodeFields); + deserializeChildFields(node, nodeFields); + deserializeDataFields(buffer, node, nodeFields); + + return node; + } + + private void deserializeDataFields(VariableLengthIntBuffer buffer, Node nodeInstance, NodeField[] nodeFields) throws UnsupportedConstantPoolTypeException { + for (int i = 0; i < nodeFields.length; i++) { + NodeField field = nodeFields[i]; + if (field.getKind() == NodeFieldKind.DATA) { + Class fieldClass = field.getType(); + long offset = field.getOffset(); + + // source sections are not serialized + // TODO add support for source sections + if (field.getType().isAssignableFrom(SourceSection.class)) { + continue; + } + + int cpi = buffer.get(); + if (cpi == VariableLengthIntBuffer.NULL) { + if (fieldClass == int.class) { + unsafe.putInt(nodeInstance, offset, 0); + } else if (fieldClass == long.class) { + unsafe.putLong(nodeInstance, offset, 0L); + } else if (fieldClass == float.class) { + unsafe.putFloat(nodeInstance, offset, 0.0F); + } else if (fieldClass == double.class) { + unsafe.putDouble(nodeInstance, offset, 0.0D); + } else if (fieldClass == byte.class) { + unsafe.putByte(nodeInstance, offset, (byte) 0); + } else if (fieldClass == short.class) { + unsafe.putShort(nodeInstance, offset, (short) 0); + } else if (fieldClass == char.class) { + unsafe.putChar(nodeInstance, offset, (char) 0); + } else if (fieldClass == boolean.class) { + unsafe.putBoolean(nodeInstance, offset, false); + } else { + unsafe.putObject(nodeInstance, offset, null); + } + } else { + if (fieldClass == int.class) { + unsafe.putInt(nodeInstance, offset, cp.getInt(cpi)); + } else if (fieldClass == long.class) { + unsafe.putLong(nodeInstance, offset, cp.getLong(cpi)); + } else if (fieldClass == float.class) { + unsafe.putFloat(nodeInstance, offset, cp.getFloat(cpi)); + } else if (fieldClass == double.class) { + unsafe.putDouble(nodeInstance, offset, cp.getDouble(cpi)); + } else if (fieldClass == byte.class) { + unsafe.putByte(nodeInstance, offset, (byte) cp.getInt(cpi)); + } else if (fieldClass == short.class) { + unsafe.putShort(nodeInstance, offset, (short) cp.getInt(cpi)); + } else if (fieldClass == char.class) { + unsafe.putChar(nodeInstance, offset, (char) cp.getInt(cpi)); + } else if (fieldClass == boolean.class) { + unsafe.putBoolean(nodeInstance, offset, cp.getInt(cpi) == 1 ? true : false); + } else if (fieldClass == Integer.class) { + unsafe.putObject(nodeInstance, offset, cp.getInt(cpi)); + } else if (fieldClass == Long.class) { + unsafe.putObject(nodeInstance, offset, cp.getLong(cpi)); + } else if (fieldClass == Float.class) { + unsafe.putObject(nodeInstance, offset, cp.getFloat(cpi)); + } else if (fieldClass == Double.class) { + unsafe.putObject(nodeInstance, offset, cp.getDouble(cpi)); + } else if (fieldClass == Byte.class) { + unsafe.putObject(nodeInstance, offset, (byte) cp.getInt(cpi)); + } else if (fieldClass == Short.class) { + unsafe.putObject(nodeInstance, offset, (short) cp.getInt(cpi)); + } else if (fieldClass == Character.class) { + unsafe.putObject(nodeInstance, offset, (char) cp.getInt(cpi)); + } else if (fieldClass == Boolean.class) { + unsafe.putObject(nodeInstance, offset, cp.getInt(cpi) == 1 ? Boolean.TRUE : Boolean.FALSE); + } else { + unsafe.putObject(nodeInstance, offset, cp.getObject(fieldClass, cpi)); + } + } + } + } + } + + private void deserializeChildFields(Node parent, NodeField[] nodeFields) { + for (int i = nodeFields.length - 1; i >= 0; i--) { + NodeField field = nodeFields[i]; + if (field.getKind() == NodeFieldKind.CHILD) { + unsafe.putObject(parent, field.getOffset(), popNode(parent, field.getType())); + } + } + } + + private void deserializeChildrenFields(Node parent, NodeField[] nodeFields) { + for (int i = nodeFields.length - 1; i >= 0; i--) { + NodeField field = nodeFields[i]; + if (field.getKind() == NodeFieldKind.CHILDREN) { + unsafe.putObject(parent, field.getOffset(), popArray(parent, field.getType())); + } + } + } + + private static Node updateParent(Node parent, Node child) { + if (child != null) { + long parentOffset = NodeClass.get(child.getClass()).getParentOffset(); + unsafe.putObject(child, parentOffset, parent); + } + return child; + } + + private static Unsafe loadUnsafe() { + try { + return Unsafe.getUnsafe(); + } catch (SecurityException e) { + } + try { + Field theUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe"); + theUnsafeInstance.setAccessible(true); + return (Unsafe) theUnsafeInstance.get(Unsafe.class); + } catch (Exception e) { + throw new RuntimeException("exception while trying to get Unsafe.theUnsafe via reflection:", e); + } + } + + private static class HierarchicalStack { + + private static final Object NULL_STACK = new Object(); + + private final List dynamicStack = new ArrayList<>(); + + void pushStack(Object[] array) { + if (array == null) { + dynamicStack.add(NULL_STACK); + } else { + dynamicStack.add(new FixedSizeNodeStack(array)); + } + } + + private FixedSizeNodeStack getTosStack() { + if (dynamicStack.isEmpty()) { + return null; + } + Object peekTos = dynamicStack.get(dynamicStack.size() - 1); + if (peekTos != null && peekTos.getClass() == FixedSizeNodeStack.class) { + return (FixedSizeNodeStack) peekTos; + } + return null; + } + + Object[] popStack() { + Object tos = dynamicStack.remove(dynamicStack.size() - 1); + if (tos == NULL_STACK) { + return null; + } + return ((FixedSizeNodeStack) tos).getArray(); + } + + void push(Object o) { + FixedSizeNodeStack tosStack = getTosStack(); + if (tosStack != null && !tosStack.isFull()) { + tosStack.push(o); + } else { + dynamicStack.add(o); + } + } + + Object pop() { + FixedSizeNodeStack tosStack = getTosStack(); + Object value; + if (tosStack != null) { + assert !tosStack.isEmpty(); + value = tosStack.pop(); + } else { + value = dynamicStack.remove(dynamicStack.size() - 1); + } + assert value != NULL_STACK; + return value; + } + + } + + private static class FixedSizeNodeStack { + + private final Object[] array; + + private int tos; + + FixedSizeNodeStack(Object[] array) { + this.array = array; + } + + boolean isFull() { + return tos == array.length; + } + + boolean isEmpty() { + return tos == 0; + } + + private void push(Object node) { + if (tos >= array.length) { + throw new ArrayIndexOutOfBoundsException(); + } + unsafe.putObject(array, Unsafe.ARRAY_OBJECT_BASE_OFFSET + Unsafe.ARRAY_OBJECT_INDEX_SCALE * (long) (tos++), node); + } + + private Object pop() { + if (tos <= 0) { + throw new ArrayIndexOutOfBoundsException(); + } + return unsafe.getObject(array, Unsafe.ARRAY_OBJECT_BASE_OFFSET + Unsafe.ARRAY_OBJECT_INDEX_SCALE * (long) (--tos)); + } + + private Object[] getArray() { + return array; + } + } + +} diff -r ce5e6f9075b6 -r bfcae72b61a0 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/serial/PostOrderSerializer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/serial/PostOrderSerializer.java Mon Oct 14 15:51:57 2013 +0200 @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.nodes.serial; + +import java.lang.reflect.*; +import java.nio.*; + +import sun.misc.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.api.nodes.NodeUtil.NodeClass; +import com.oracle.truffle.api.nodes.NodeUtil.NodeField; +import com.oracle.truffle.api.nodes.NodeUtil.NodeFieldKind; + +/** + * Experimental API. May change without notice. + */ +public final class PostOrderSerializer { + + private static final Unsafe unsafe = loadUnsafe(); + + private final SerializerConstantPool cp; + + /** + * Constructs a new deserializer using a custom {@link SerializerConstantPool} implementation. + * For the {@link SerializerConstantPool} implementation at least the following methods must be + * implemented: + *
    + *
  • {@link SerializerConstantPool#putInt(int)}
  • + *
  • {@link SerializerConstantPool#putClass(Class)}
  • + *
+ */ + public PostOrderSerializer(SerializerConstantPool cp) { + this.cp = cp; + } + + /** + * Serializes the node AST and returns the serialized data as byte array. + * + * @param node the root node that represents the Truffle AST that should be serialized. + * @return a trimmed byte array that contains the serialized data. + * + * @throws UnsupportedConstantPoolTypeException thrown if a type is encountered that is not + * supported by the constant pool implementation. + */ + public byte[] serialize(Node node) throws UnsupportedConstantPoolTypeException { + VariableLengthIntBuffer buffer = new VariableLengthIntBuffer(ByteBuffer.allocate(512)); + serialize(buffer, node); + return buffer.getBytes(); + } + + private void serialize(VariableLengthIntBuffer buffer, Node node) throws UnsupportedConstantPoolTypeException { + if (node == null) { + buffer.put(VariableLengthIntBuffer.NULL); + return; + } + Class nodeClass = node.getClass(); + + NodeField[] nodeFields = NodeClass.get(nodeClass).getFields(); + serializeChildFields(buffer, node, nodeFields); + serializeChildrenFields(buffer, node, nodeFields); + buffer.put(cp.putClass(node.getClass())); + serializeDataFields(buffer, node, nodeFields); + } + + private void serializeDataFields(VariableLengthIntBuffer buffer, Node node, NodeField[] nodeFields) throws UnsupportedConstantPoolTypeException { + for (int i = 0; i < nodeFields.length; i++) { + NodeField field = nodeFields[i]; + if (field.getKind() == NodeFieldKind.DATA) { + Class fieldClass = field.getType(); + long offset = field.getOffset(); + int cpi; + + if (field.getType().isAssignableFrom(SourceSection.class)) { + continue; + } + + if (fieldClass == int.class) { + cpi = cp.putInt(unsafe.getInt(node, offset)); + } else if (fieldClass == long.class) { + cpi = cp.putLong(unsafe.getLong(node, offset)); + } else if (fieldClass == float.class) { + cpi = cp.putFloat(unsafe.getFloat(node, offset)); + } else if (fieldClass == double.class) { + cpi = cp.putDouble(unsafe.getDouble(node, offset)); + } else if (fieldClass == byte.class) { + cpi = cp.putInt(unsafe.getByte(node, offset)); + } else if (fieldClass == short.class) { + cpi = cp.putInt(unsafe.getShort(node, offset)); + } else if (fieldClass == char.class) { + cpi = cp.putInt(unsafe.getChar(node, offset)); + } else if (fieldClass == boolean.class) { + cpi = cp.putInt(unsafe.getBoolean(node, offset) ? 1 : 0); + } else { + Object value = unsafe.getObject(node, offset); + if (value == null) { + cpi = VariableLengthIntBuffer.NULL; + } else if (fieldClass == Integer.class) { + cpi = cp.putInt((Integer) value); + } else if (fieldClass == Long.class) { + cpi = cp.putLong((Long) value); + } else if (fieldClass == Float.class) { + cpi = cp.putFloat((Float) value); + } else if (fieldClass == Double.class) { + cpi = cp.putDouble((Double) value); + } else if (fieldClass == Byte.class) { + cpi = cp.putInt((Byte) value); + } else if (fieldClass == Short.class) { + cpi = cp.putInt((Short) value); + } else if (fieldClass == Character.class) { + cpi = cp.putInt((Character) value); + } else if (fieldClass == Boolean.class) { + cpi = cp.putInt((Boolean) value ? 1 : 0); + } else { + cpi = cp.putObject(fieldClass, value); + } + } + + buffer.put(cpi); + } + } + } + + private void serializeChildrenFields(VariableLengthIntBuffer buffer, Node nodeInstance, NodeField[] nodeFields) throws UnsupportedConstantPoolTypeException { + for (int i = 0; i < nodeFields.length; i++) { + NodeField field = nodeFields[i]; + if (field.getKind() == NodeFieldKind.CHILDREN) { + Object childArrayObject = unsafe.getObject(nodeInstance, field.getOffset()); + if (childArrayObject != null && !(childArrayObject instanceof Node[])) { + throw new AssertionError("Node children must be instanceof Node[]"); + } + + buffer.put(cp.putClass(field.getType())); + + Node[] childArray = (Node[]) childArrayObject; + if (childArray == null) { + buffer.put(VariableLengthIntBuffer.NULL); + } else { + buffer.put(cp.putInt(childArray.length)); + + for (int j = 0; j < childArray.length; j++) { + serialize(buffer, childArray[j]); + } + } + } + } + } + + private void serializeChildFields(VariableLengthIntBuffer buffer, Node nodeInstance, NodeField[] nodeFields) throws UnsupportedConstantPoolTypeException { + for (int i = 0; i < nodeFields.length; i++) { + NodeField field = nodeFields[i]; + if (field.getKind() == NodeFieldKind.CHILD) { + Object childObject = unsafe.getObject(nodeInstance, field.getOffset()); + if (childObject != null && !(childObject instanceof Node)) { + throw new AssertionError("Node children must be instanceof Node"); + } + serialize(buffer, (Node) childObject); + } + } + } + + private static Unsafe loadUnsafe() { + try { + return Unsafe.getUnsafe(); + } catch (SecurityException e) { + } + try { + Field theUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe"); + theUnsafeInstance.setAccessible(true); + return (Unsafe) theUnsafeInstance.get(Unsafe.class); + } catch (Exception e) { + throw new RuntimeException("exception while trying to get Unsafe.theUnsafe via reflection:", e); + } + } + +} diff -r ce5e6f9075b6 -r bfcae72b61a0 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/serial/SerializerConstantPool.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/serial/SerializerConstantPool.java Mon Oct 14 15:51:57 2013 +0200 @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.nodes.serial; + +/** + * Experimental API. May change without notice. This interface is used as bridge between the + * {@link PostOrderDeserializer}, {@link PostOrderSerializer} and underlying constant pool + * implementation. A constant pool stores a value and returns an identifying index, with which the + * object can later be returned from the pool again. All methods of this class are optional and may + * throw a {@link UnsupportedOperationException}. + */ +public interface SerializerConstantPool { + + /** + * Returns the constant pool index of a value that is not a java native type, a java + * native-wrapper class or a {@link Class} instance. The implementor should support all + * additional types that are necessary to serialize a truffle AST for a specific truffle + * implementation. If a type is not supported by this constant pool implementation a + * {@link UnsupportedConstantPoolTypeException} should be thrown. + * + * @param clazz the {@link Class} of the value + * @param value the value to be stored. Must be at least a subclass of the given clazz. + * @return the constant pool index + * @throws UnsupportedConstantPoolTypeException if a type is not supported for persistence in + * the constant pool. + */ + int putObject(Class clazz, Object value) throws UnsupportedConstantPoolTypeException; + + /** + * Stores a value in the constant pool that is not a java native type, a java native-wrapper + * class or a {@link Class} instance. The implementor should support all additional types that + * are necessary to serialize a truffle AST for a specific truffle implementation. If a type is + * not supported by this constant pool implementation a + * {@link UnsupportedConstantPoolTypeException} should be thrown. + * + * @param clazz the {@link Class} of the value in the constant pool. + * @param cpi the previously returned index + * @return the value stored inside the constant pool + * @throws UnsupportedConstantPoolTypeException if a type is not supported for persistence in + * the constant pool. + * @throws IllegalArgumentException if the provided cpi is not a valid constant pool index. + */ + Object getObject(Class clazz, int cpi) throws UnsupportedConstantPoolTypeException; + + /** + * Stores a Class instance in the constant pool and returns the constant pool index. + * + * @param value the class to store + * @return the new or existing constant pool index of the Class + */ + int putClass(Class value); + + /** + * Returns the {@link Class} instance to the given constant pool index. + * + * @param cpi the constant pool index + * @return stored value + * @throws IllegalArgumentException if the constant pool indes is invalid. + */ + Class getClass(int cpi); + + /** + * Stores an int value in the constant pool and returns the constant pool index. + * + * @param value the value to store + * @return the new or existing constant pool index of the value + */ + int putInt(int value); + + /** + * Returns the stored int value to the given constant pool index from the constant pool. + * + * @param cpi the constant pool index + * @return stored value + * @throws IllegalArgumentException if the constant pool index is invalid. + */ + int getInt(int cpi); + + /** + * Stores a long value in the constant pool and returns the constant pool index. + * + * @param value the value to store + * @return the new or existing constant pool index of the value + */ + int putLong(long value); + + /** + * Returns the stored long value to the given constant pool index from the constant pool. + * + * @param cpi the constant pool index + * @return the stored value + * @throws IllegalArgumentException if the constant pool index is invalid. + */ + long getLong(int cpi); + + /** + * Stores a double value in the constant pool and returns the constant pool index. + * + * @param value the value to store + * @return the new or existing constant pool index of the value + */ + int putDouble(double value); + + /** + * Returns the stored double value to the given constant pool index from the constant pool. + * + * @param cpi the constant pool index + * @return the stored value + * @throws IllegalArgumentException if the constant pool index is invalid. + */ + double getDouble(int cpi); + + /** + * Stores a float value in the constant pool and returns the constant pool index. + * + * @param value the value to store + * @return the new or existing constant pool index of the value + */ + int putFloat(float value); + + /** + * Returns the stored float value to the given constant pool index from the constant pool. + * + * @param cpi the constant pool index + * @return the stored value + * @throws IllegalArgumentException if the constant pool index is invalid. + */ + float getFloat(int cpi); + +} diff -r ce5e6f9075b6 -r bfcae72b61a0 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/serial/UnsupportedConstantPoolTypeException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/serial/UnsupportedConstantPoolTypeException.java Mon Oct 14 15:51:57 2013 +0200 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.nodes.serial; + +/** + * Experimental API. May change without notice. + */ +public class UnsupportedConstantPoolTypeException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + public UnsupportedConstantPoolTypeException() { + super(); + } + + public UnsupportedConstantPoolTypeException(String message, Throwable cause) { + super(message, cause); + } + + public UnsupportedConstantPoolTypeException(String message) { + super(message); + } + + public UnsupportedConstantPoolTypeException(Throwable cause) { + super(cause); + } + +} diff -r ce5e6f9075b6 -r bfcae72b61a0 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/serial/VariableLengthIntBuffer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/serial/VariableLengthIntBuffer.java Mon Oct 14 15:51:57 2013 +0200 @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.nodes.serial; + +import java.nio.*; + +/** + * Experimental API. May change without notice. Simple variable length unsigned int buffer backed by + * a byte buffer. + */ +public class VariableLengthIntBuffer { + + public static final int NULL = -1; + + private ByteBuffer buffer; + + public VariableLengthIntBuffer(ByteBuffer buffer) { + this.buffer = buffer; + } + + public VariableLengthIntBuffer(byte[] array) { + buffer = ByteBuffer.wrap(array); + } + + /** + * Returns the backing byte buffer. + */ + public ByteBuffer getBuffer() { + return buffer; + } + + public byte[] getBytes() { + int pos = buffer.position(); + byte[] bytes = new byte[buffer.position()]; + buffer.rewind(); + buffer.get(bytes); + buffer.position(pos); + return bytes; + } + + public int get() { + byte peekByte = buffer.get(buffer.position()); + if ((peekByte & 0x80) == 0) { + // single byte encoding with prefix 0 (range 127) + return buffer.get(); // no bit to be masked + } else { + if (peekByte == (byte) 0xFF) { + buffer.get(); // skip one byte + return NULL; + } + int result = buffer.getInt() & 0x7FFF_FFFF; // first bit masked out + assert (result & 0x4000_0000) == 0; + return result; + } + } + + public void put(int i) { + ensureCapacity(); + if (i == NULL) { + buffer.put((byte) 0xFF); + } else if ((i & 0xFFFF_FF80) == 0) { // 7 bits data + buffer.put((byte) i); + } else if ((i & 0xC000_0000) == 0) { // 32 bits data + buffer.putInt(i | 0x8000_0000); // append leading 1 + } else { + throw new IllegalArgumentException("Integer out of encodeable " + i); + } + } + + private void ensureCapacity() { + if (buffer.position() + 4 > buffer.capacity()) { + ByteBuffer newBuffer = ByteBuffer.allocate(buffer.capacity() * 2); + + int pos = buffer.position(); + buffer.rewind(); + newBuffer.put(buffer); + newBuffer.position(pos); + + buffer = newBuffer; + } + } + + public boolean hasRemaining() { + return buffer.hasRemaining(); + } + +} diff -r ce5e6f9075b6 -r bfcae72b61a0 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/TruffleTypes.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/TruffleTypes.java Mon Oct 14 13:49:46 2013 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/TruffleTypes.java Mon Oct 14 15:51:57 2013 +0200 @@ -58,6 +58,7 @@ private final DeclaredType slowPath; private final DeclaredType sourceSection; private final DeclaredType truffleOptions; + private final DeclaredType compilationFinal; private final TypeElement expectError; private final List errors = new ArrayList<>(); @@ -78,9 +79,14 @@ slowPath = getRequired(context, SlowPath.class); sourceSection = getRequired(context, SourceSection.class); truffleOptions = getRequired(context, TruffleOptions.class); + compilationFinal = getRequired(context, CompilationFinal.class); expectError = (TypeElement) getRequired(context, ExpectError.class).asElement(); } + public DeclaredType getCompilationFinal() { + return compilationFinal; + } + public TypeElement getExpectError() { return expectError; } diff -r ce5e6f9075b6 -r bfcae72b61a0 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeElement.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeElement.java Mon Oct 14 13:49:46 2013 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeElement.java Mon Oct 14 15:51:57 2013 +0200 @@ -78,6 +78,13 @@ return element; } + public E addOptional(E element) { + if (element != null) { + add(element); + } + return element; + } + public void remove(E element) { getEnclosedElements().remove(element); } diff -r ce5e6f9075b6 -r bfcae72b61a0 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/ExecutableTypeData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/ExecutableTypeData.java Mon Oct 14 13:49:46 2013 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/ExecutableTypeData.java Mon Oct 14 15:51:57 2013 +0200 @@ -37,6 +37,9 @@ super(method, executable); this.typeSystem = typeSystem; this.type = type; + if (executable.getParameters().size() < method.getMethod().getParameters().size()) { + throw new IllegalArgumentException(String.format("Method parameter count mismatch %s != %s.", executable.getParameters(), method.getMethod().getParameters())); + } } public TypeData getType() { diff -r ce5e6f9075b6 -r bfcae72b61a0 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 Mon Oct 14 13:49:46 2013 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java Mon Oct 14 15:51:57 2013 +0200 @@ -40,7 +40,6 @@ import com.oracle.truffle.dsl.processor.node.NodeChildData.ExecutionKind; import com.oracle.truffle.dsl.processor.node.SpecializationGroup.TypeGuard; import com.oracle.truffle.dsl.processor.template.*; -import com.oracle.truffle.dsl.processor.template.TemplateMethod.Signature; import com.oracle.truffle.dsl.processor.typesystem.*; public class NodeCodeGenerator extends CompilationUnitFactory { @@ -50,6 +49,8 @@ private static final String EXECUTE_GENERIC_NAME = "executeGeneric0"; private static final String EXECUTE_SPECIALIZE_NAME = "executeAndSpecialize0"; + private static final String UPDATE_TYPES_NAME = "updateTypes"; + public NodeCodeGenerator(ProcessorContext context) { super(context); } @@ -62,15 +63,6 @@ return node.getNodeId() + "Factory"; } - private static String nodeCastClassName(NodeData node, TypeData type) { - String nodeid = resolveNodeId(node); - if (type == null) { - return nodeid + "ImplicitCast"; - } else { - return Utils.firstLetterUpperCase(Utils.getSimpleName(type.getPrimitiveType())) + "Cast"; - } - } - private static String nodeSpecializationClassName(SpecializationData specialization) { String nodeid = resolveNodeId(specialization.getNode()); String name = Utils.firstLetterUpperCase(nodeid); @@ -103,8 +95,12 @@ return valueName(targetParameter) + "Evaluated"; } - private static String typeName(ActualParameter param) { - return param.getLocalName() + "Type"; + private static String implicitTypeName(ActualParameter param) { + return param.getLocalName() + "ImplicitType"; + } + + private static String polymorphicTypeName(ActualParameter param) { + return param.getLocalName() + "PolymorphicType"; } private static String valueName(ActualParameter param) { @@ -299,7 +295,7 @@ builder.string(targetParameter.getSpecification().getName()); builder.end(); } else if (unexpectedValueName != null && targetParameter.getLocalName().equals(unexpectedValueName)) { - builder.string("ex.getResult()"); + builder.cast(targetParameter.getType(), CodeTreeBuilder.singleString("ex.getResult()")); } else if (!Utils.needsCastTo(getContext(), valueType, targetType)) { builder.startGroup(); builder.string(valueName(targetParameter)); @@ -321,16 +317,18 @@ return name; } - private static CodeTree createCallTypeSystemMethod(ProcessorContext context, CodeTreeBuilder parent, NodeData node, String methodName, CodeTree value) { + private static CodeTree createCallTypeSystemMethod(ProcessorContext context, CodeTreeBuilder parent, NodeData node, String methodName, CodeTree... args) { CodeTreeBuilder builder = new CodeTreeBuilder(parent); - startCallTypeSystemMethod(context, builder, node, methodName); - builder.tree(value); + startCallTypeSystemMethod(context, builder, node.getTypeSystem(), methodName); + for (CodeTree arg : args) { + builder.tree(arg); + } 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()); + private static void startCallTypeSystemMethod(ProcessorContext context, CodeTreeBuilder body, TypeSystemData typeSystem, String methodName) { + VariableElement singleton = TypeSystemCodeGenerator.findSingleton(context, typeSystem); assert singleton != null; body.startGroup(); @@ -456,7 +454,7 @@ } } - protected CodeTree createCastType(NodeData node, TypeData sourceType, TypeData targetType, boolean expect, CodeTree value) { + protected CodeTree createCastType(TypeSystemData typeSystem, TypeData sourceType, TypeData targetType, boolean expect, CodeTree value) { if (targetType == null) { return value; } else if (sourceType != null && !sourceType.needsCastTo(getContext(), targetType)) { @@ -470,12 +468,16 @@ } else { targetMethodName = TypeSystemCodeGenerator.asTypeMethodName(targetType); } - startCallTypeSystemMethod(getContext(), builder, node, targetMethodName); + startCallTypeSystemMethod(getContext(), builder, typeSystem, targetMethodName); builder.tree(value); builder.end().end(); return builder.getRoot(); } + protected CodeTree createExpectType(TypeSystemData typeSystem, TypeData sourceType, TypeData targetType, CodeTree expression) { + return createCastType(typeSystem, sourceType, targetType, true, expression); + } + private class NodeFactoryFactory extends ClassElementFactory { private final Map> childTypes; @@ -504,6 +506,7 @@ Modifier createVisibility = Utils.getVisibility(clazz.getModifiers()); + CodeTypeElement polymorphicNode = null; if (node.needsFactory()) { NodeBaseFactory factory = new NodeBaseFactory(context); add(factory, node.getGenericSpecialization() == null ? node.getSpecializations().get(0) : node.getGenericSpecialization()); @@ -516,15 +519,9 @@ createFactoryMethods(node, clazz, createVisibility); if (node.isPolymorphic()) { - PolymorphicNodeFactory generic = new PolymorphicNodeFactory(getContext(), generatedNode, true); + PolymorphicNodeFactory generic = new PolymorphicNodeFactory(getContext(), generatedNode); add(generic, node.getGenericPolymorphicSpecialization()); - - for (SpecializationData specialization : node.getPolymorphicSpecializations()) { - if (specialization == node.getGenericPolymorphicSpecialization()) { - continue; - } - add(new PolymorphicNodeFactory(context, generic.getElement(), false), specialization); - } + polymorphicNode = generic.getElement(); } for (SpecializationData specialization : node.getSpecializations()) { if (!specialization.isReachable()) { @@ -544,6 +541,10 @@ clazz.add(createInstanceConstant(node, clazz.asType())); } + if (polymorphicNode != null) { + patchParameterType(clazz, UPDATE_TYPES_NAME, generatedNode.asType(), polymorphicNode.asType()); + } + for (NodeData childNode : childTypes.keySet()) { if (childNode.getTemplateType().getModifiers().contains(Modifier.PRIVATE)) { continue; @@ -570,6 +571,19 @@ } + private void patchParameterType(CodeTypeElement enclosingClass, String methodName, TypeMirror originalType, TypeMirror newType) { + for (TypeElement enclosedType : ElementFilter.typesIn(enclosingClass.getEnclosedElements())) { + CodeTypeElement type = (CodeTypeElement) enclosedType; + ExecutableElement method = type.getMethod(methodName); + for (VariableElement v : method.getParameters()) { + CodeVariableElement var = (CodeVariableElement) v; + if (Utils.typeEquals(var.getType(), originalType)) { + var.setType(newType); + } + } + } + } + private CodeExecutableElement createGetNodeClassMethod(NodeData node) { TypeMirror returnType = Utils.getDeclaredType(Utils.fromTypeMirror(getContext().getType(Class.class)), node.getNodeType()); CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), returnType, "getNodeClass"); @@ -941,16 +955,14 @@ builder.statement("this.next0 = adoptChild(next0)"); clazz.add(setter); - createIsCompatible(clazz, null); - - CodeExecutableElement genericCachedExecute = createCachedExecute(node, node.getGenericPolymorphicSpecialization(), null); + CodeExecutableElement genericCachedExecute = createCachedExecute(node, node.getGenericPolymorphicSpecialization()); clazz.add(genericCachedExecute); - for (SpecializationData polymorph : node.getPolymorphicSpecializations()) { - if (polymorph == node.getGenericPolymorphicSpecialization()) { - continue; - } - clazz.add(createCachedExecute(node, polymorph, genericCachedExecute)); - } + + getElement().add(createUpdateTypes(clazz.asType())); + } + + for (CodeExecutableElement method : createImplicitChildrenAccessors()) { + clazz.add(method); } clazz.add(createGenericExecuteAndSpecialize(node, rootGroup)); @@ -962,6 +974,59 @@ } } + private List createImplicitChildrenAccessors() { + NodeData node = getModel().getNode(); +// Map> expectTypes = new HashMap<>(); + @SuppressWarnings("unchecked") + List> expectTypes = Arrays.> asList(new Set[node.getGenericSpecialization().getParameters().size()]); + + for (ExecutableTypeData executableType : node.getExecutableTypes()) { + for (int i = 0; i < executableType.getEvaluatedCount(); i++) { + ActualParameter parameter = executableType.getSignatureParameter(i); + if (i >= expectTypes.size()) { + break; + } + Set types = expectTypes.get(i); + if (types == null) { + types = new TreeSet<>(); + expectTypes.set(i, types); + } + types.add(parameter.getTypeSystemType()); + } + } + + List methods = new ArrayList<>(); + @SuppressWarnings("unchecked") + List> visitedList = Arrays.> asList(new Set[node.getGenericSpecialization().getParameters().size()]); + for (SpecializationData spec : node.getSpecializations()) { + int signatureIndex = -1; + for (ActualParameter param : spec.getParameters()) { + if (!param.getSpecification().isSignature()) { + continue; + } + signatureIndex++; + Set visitedTypeData = visitedList.get(signatureIndex); + if (visitedTypeData == null) { + visitedTypeData = new TreeSet<>(); + visitedList.set(signatureIndex, visitedTypeData); + } + + if (visitedTypeData.contains(param.getTypeSystemType())) { + continue; + } + visitedTypeData.add(param.getTypeSystemType()); + + Set expect = expectTypes.get(signatureIndex); + 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); @@ -1028,53 +1093,10 @@ return method; } - protected void createIsCompatible(CodeTypeElement clazz, SpecializationData specialization) { - CodeExecutableElement isCompatible = new CodeExecutableElement(modifiers(PROTECTED), context.getType(boolean.class), "isCompatible0"); - isCompatible.addParameter(new CodeVariableElement(getContext().getType(Class.class), "type")); - - if (specialization == null) { - isCompatible.getModifiers().add(ABSTRACT); - } else if (specialization.isGeneric()) { - isCompatible.createBuilder().startThrow().startNew(getContext().getType(AssertionError.class)).end().end(); - } else if (specialization.isPolymorphic()) { - isCompatible.createBuilder().startReturn().string("type != getClass() && next0.isCompatible0(type)").end(); - } else if (specialization.isUninitialized()) { - isCompatible.createBuilder().returnTrue(); - } else { - NodeData node = specialization.getNode(); - CodeTreeBuilder builder = isCompatible.createBuilder(); - - Signature specializationSignature = specialization.getSignature(); - List compatible = new ArrayList<>(); - for (SpecializationData polymorphic : node.getPolymorphicSpecializations()) { - if (specializationSignature.isCompatibleTo(polymorphic.getSignature())) { - compatible.add(polymorphic); - } - } - - if (compatible.isEmpty()) { - builder.returnFalse(); - } else { - builder.startIf(); - String and = ""; - for (SpecializationData polymorphic : compatible) { - builder.string(and); - builder.string("type == ").string(nodePolymorphicClassName(node, polymorphic)).string(".class"); - and = " || "; - } - builder.end().startBlock(); - builder.startReturn().startCall("next0", "isCompatible0").string("type").end().end(); - builder.end(); - builder.returnFalse(); - } - } - - clazz.add(isCompatible); - } - - private CodeExecutableElement createCachedExecute(NodeData node, SpecializationData polymorph, CodeExecutableElement genericPolymorphMethod) { + private CodeExecutableElement createCachedExecute(NodeData node, SpecializationData polymorph) { String name = executeCachedName(polymorph); - CodeExecutableElement cachedExecute = new CodeExecutableElement(modifiers(PROTECTED), polymorph.getReturnType().getType(), name); + CodeExecutableElement cachedExecute = new CodeExecutableElement(modifiers(PROTECTED, ABSTRACT), polymorph.getReturnType().getType(), name); + addInternalValueParameters(cachedExecute, polymorph, true, true); ExecutableTypeData sourceExecutableType = node.findExecutableType(polymorph.getReturnType().getTypeSystemType(), 0); boolean sourceThrowsUnexpected = sourceExecutableType != null && sourceExecutableType.hasUnexpectedValue(getContext()); @@ -1084,18 +1106,6 @@ if (sourceThrowsUnexpected) { cachedExecute.getThrownTypes().add(getContext().getType(UnexpectedResultException.class)); } - addInternalValueParameters(cachedExecute, polymorph, true, true); - - if (polymorph == node.getGenericPolymorphicSpecialization()) { - cachedExecute.getModifiers().add(ABSTRACT); - } else { - SpecializationData genericPolymorph = node.getGenericPolymorphicSpecialization(); - CodeTreeBuilder builder = cachedExecute.createBuilder(); - ExecutableTypeData genericExecutable = new ExecutableTypeData(genericPolymorph, genericPolymorphMethod, node.getTypeSystem(), genericPolymorph.getReturnType().getTypeSystemType()); - ExecutableTypeData specificExecutable = new ExecutableTypeData(polymorph, cachedExecute, node.getTypeSystem(), polymorph.getReturnType().getTypeSystemType()); - builder.tree(createCastingExecute(builder, polymorph, specificExecutable, genericExecutable)); - } - return cachedExecute; } @@ -1271,7 +1281,7 @@ public CodeTree create(CodeTreeBuilder b, SpecializationData current) { return createGenericInvokeAndSpecialize(b, node.getGenericSpecialization(), current, currentNodeVar); } - }, null, false, true)); + }, null, false, true, false)); boolean firstUnreachable = true; for (SpecializationData current : node.getSpecializations()) { @@ -1305,8 +1315,9 @@ TypeMirror genericReturnType = node.getGenericSpecialization().getReturnType().getType(); CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED), genericReturnType, EXECUTE_GENERIC_NAME); - method.getAnnotationMirrors().add(new CodeAnnotationMirror(getContext().getTruffleTypes().getSlowPath())); - + if (!node.getGenericSpecialization().hasFrame(getContext())) { + method.getAnnotationMirrors().add(new CodeAnnotationMirror(getContext().getTruffleTypes().getSlowPath())); + } addInternalValueParameters(method, node.getGenericSpecialization(), node.needsFrame(), false); final CodeTreeBuilder builder = method.createBuilder(); @@ -1315,7 +1326,7 @@ public CodeTree create(CodeTreeBuilder b, SpecializationData current) { return createGenericInvoke(builder, current.getNode().getGenericSpecialization(), current); } - }, null, false, true)); + }, null, false, true, false)); emitUnreachableSpecializations(builder, node); @@ -1332,7 +1343,7 @@ } protected CodeTree createExecuteTree(CodeTreeBuilder outerParent, final SpecializationData source, final SpecializationGroup group, final boolean checkMinimumState, - final CodeBlock guardedblock, final CodeTree elseBlock, boolean forceElse, final boolean emitAssumptions) { + final CodeBlock guardedblock, final CodeTree elseBlock, boolean forceElse, final boolean emitAssumptions, final boolean typedCasts) { return guard(outerParent, source, group, checkMinimumState, new CodeBlock() { public CodeTree create(CodeTreeBuilder parent, Integer ifCount) { @@ -1345,20 +1356,20 @@ } else { for (SpecializationGroup childGroup : group.getChildren()) { - builder.tree(createExecuteTree(builder, source, childGroup, checkMinimumState, guardedblock, null, false, emitAssumptions)); + builder.tree(createExecuteTree(builder, source, childGroup, checkMinimumState, guardedblock, null, false, emitAssumptions, typedCasts)); } } return builder.getRoot(); } - }, elseBlock, forceElse, emitAssumptions); + }, elseBlock, forceElse, emitAssumptions, typedCasts); } private CodeTree guard(CodeTreeBuilder parent, SpecializationData source, SpecializationGroup group, boolean checkMinimumState, CodeBlock bodyBlock, CodeTree elseBlock, - boolean forceElse, boolean emitAssumptions) { + boolean forceElse, boolean emitAssumptions, boolean typedCasts) { CodeTreeBuilder builder = parent.create(); - int ifCount = emitGuards(builder, source, group, checkMinimumState, emitAssumptions); + int ifCount = emitGuards(builder, source, group, checkMinimumState, emitAssumptions, typedCasts); if (isReachableGroup(group, ifCount, checkMinimumState)) { builder.tree(bodyBlock.create(builder, ifCount)); @@ -1380,7 +1391,7 @@ return true; } SpecializationGroup previous = group.getPreviousGroup(); - if (previous == null || previous.getElseConnectableGuards().isEmpty()) { + if (previous == null || previous.findElseConnectableGuards(checkMinimumState).isEmpty()) { return true; } @@ -1396,7 +1407,7 @@ return true; } - private int emitGuards(CodeTreeBuilder builder, SpecializationData source, SpecializationGroup group, boolean checkMinimumState, boolean emitAssumptions) { + private int emitGuards(CodeTreeBuilder builder, SpecializationData source, SpecializationGroup group, boolean checkMinimumState, boolean emitAssumptions, boolean typedCasts) { NodeData node = source.getNode(); CodeTreeBuilder guardsBuilder = builder.create(); @@ -1406,30 +1417,11 @@ String guardsAnd = ""; String guardsCastAnd = ""; - List elseGuards = group.getElseConnectableGuards(); - 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) { + int groupMaxIndex = group.getUncheckedSpecializationIndex(); + + if (groupMaxIndex > -1) { guardsBuilder.string(guardsAnd); guardsBuilder.string("minimumState < " + groupMaxIndex); guardsAnd = " && "; @@ -1466,18 +1458,19 @@ throw new IllegalStateException(); } - CodeTree implicitGuard = createTypeGuard(guardsBuilder, child, valueParam, typeGuard.getType()); + CodeTree implicitGuard = createTypeGuard(guardsBuilder, child, valueParam, typeGuard.getType(), typedCasts); if (implicitGuard != null) { guardsBuilder.string(guardsAnd); guardsBuilder.tree(implicitGuard); guardsAnd = " && "; } - CodeTree cast = createCast(castBuilder, child, valueParam, typeGuard.getType(), checkMinimumState); + CodeTree cast = createCast(castBuilder, child, valueParam, typeGuard.getType(), checkMinimumState, typedCasts); if (cast != null) { castBuilder.tree(cast); } } + List elseGuards = group.findElseConnectableGuards(checkMinimumState); for (GuardData guard : group.getGuards()) { if (elseGuards.contains(guard)) { @@ -1544,7 +1537,7 @@ return false; } - private CodeTree createTypeGuard(CodeTreeBuilder parent, NodeChildData field, ActualParameter source, TypeData targetType) { + private CodeTree createTypeGuard(CodeTreeBuilder parent, NodeChildData field, ActualParameter source, TypeData targetType, boolean typedCasts) { NodeData node = field.getNodeData(); CodeTreeBuilder builder = new CodeTreeBuilder(parent); @@ -1566,15 +1559,22 @@ } String castMethodName; + String castTypeName = null; List types = getModel().getNode().getTypeSystem().lookupSourceTypes(targetType); if (types.size() > 1) { castMethodName = TypeSystemCodeGenerator.isImplicitTypeMethodName(targetType); + if (typedCasts) { + castTypeName = implicitTypeName(source); + } } else { castMethodName = TypeSystemCodeGenerator.isTypeMethodName(targetType); } - startCallTypeSystemMethod(getContext(), builder, node, castMethodName); + startCallTypeSystemMethod(getContext(), builder, node.getTypeSystem(), castMethodName); builder.string(valueName(source)); + if (castTypeName != null) { + builder.string(castTypeName); + } builder.end().end(); // call if (field.isShortCircuit()) { @@ -1586,7 +1586,8 @@ return builder.getRoot(); } - private CodeTree createCast(CodeTreeBuilder parent, NodeChildData field, ActualParameter source, TypeData targetType, boolean checkMinimumState) { + // TODO merge redundancies with #createTypeGuard + private CodeTree createCast(CodeTreeBuilder parent, NodeChildData field, ActualParameter source, TypeData targetType, boolean checkMinimumState, boolean typedCasts) { NodeData node = field.getNodeData(); TypeData sourceType = source.getTypeSystemType(); @@ -1602,20 +1603,30 @@ } String castMethodName; + String castTypeName = null; List types = getModel().getNode().getTypeSystem().lookupSourceTypes(targetType); if (types.size() > 1) { castMethodName = TypeSystemCodeGenerator.asImplicitTypeMethodName(targetType); + if (typedCasts) { + castTypeName = implicitTypeName(source); + } } else { castMethodName = TypeSystemCodeGenerator.asTypeMethodName(targetType); } - CodeTree value = createCallTypeSystemMethod(context, parent, node, castMethodName, CodeTreeBuilder.singleString(valueName(source))); + List args = new ArrayList<>(); + args.add(CodeTreeBuilder.singleString(valueName(source))); + if (castTypeName != null) { + args.add(CodeTreeBuilder.singleString(castTypeName)); + } + + CodeTree value = createCallTypeSystemMethod(context, parent, node, castMethodName, args.toArray(new CodeTree[0])); CodeTreeBuilder builder = parent.create(); builder.tree(createLazyAssignment(parent, castValueName(source), targetType.getPrimitiveType(), condition, value)); if (checkMinimumState && types.size() > 1) { CodeTree castType = createCallTypeSystemMethod(context, parent, node, TypeSystemCodeGenerator.getImplicitClass(targetType), CodeTreeBuilder.singleString(valueName(source))); - builder.tree(createLazyAssignment(builder, typeName(source), getContext().getType(Class.class), condition, castType)); + builder.tree(createLazyAssignment(builder, implicitTypeName(source), getContext().getType(Class.class), condition, castType)); } return builder.getRoot(); @@ -1765,7 +1776,7 @@ NodeChildData child = getModel().getNode().findChild(param.getSpecification().getName()); List types = child.getNodeData().getTypeSystem().lookupSourceTypes(param.getTypeSystemType()); if (types.size() > 1) { - replaceCall.string(typeName(param)); + replaceCall.string(implicitTypeName(param)); } } replaceCall.end().end(); @@ -1897,7 +1908,7 @@ protected CodeTree createExpectExecutableType(NodeData node, TypeData sourceType, ExecutableTypeData castedType, CodeTree value) { boolean hasUnexpected = castedType.hasUnexpectedValue(getContext()); - return createCastType(node, sourceType, castedType.getType(), hasUnexpected, value); + return createCastType(node.getTypeSystem(), sourceType, castedType.getType(), hasUnexpected, value); } protected CodeTree createExecuteChildren(CodeTreeBuilder parent, ExecutableTypeData sourceExecutable, SpecializationData specialization, List targetParameters, @@ -1909,27 +1920,13 @@ if (!targetParameter.getSpecification().isSignature()) { continue; } - TypeData targetType = targetParameter.getTypeSystemType(); - ExecutableTypeData targetExecutable = null; - if (child != null) { - targetExecutable = child.findExecutableType(getContext(), targetType); - } - - if (targetExecutable == null) { - // TODO what to do? assertion? - continue; - } - - CodeTree executionExpressions = createExecutionExpresssions(builder, child, sourceExecutable, targetExecutable, targetParameter, unexpectedParameter); - - String targetVarName = valueName(targetParameter); - CodeTree unexpectedTree = createCatchUnexpectedTree(builder, executionExpressions, targetVarName, specialization, sourceExecutable, targetExecutable, targetParameter, - isShortCircuit(child)); - CodeTree shortCircuitTree = createShortCircuitTree(builder, unexpectedTree, targetVarName, specialization, targetParameter, unexpectedParameter); + CodeTree executionExpressions = createExecuteChild(builder, child, sourceExecutable, targetParameter, unexpectedParameter); + CodeTree unexpectedTree = createCatchUnexpectedTree(builder, executionExpressions, specialization, sourceExecutable, targetParameter, isShortCircuit(child), unexpectedParameter); + CodeTree shortCircuitTree = createShortCircuitTree(builder, unexpectedTree, specialization, targetParameter, unexpectedParameter); if (shortCircuitTree == executionExpressions) { if (containsNewLine(executionExpressions)) { - builder.declaration(sourceExecutable.getType().getPrimitiveType(), targetVarName); + builder.declaration(targetParameter.getType(), valueName(targetParameter)); builder.tree(shortCircuitTree); } else { builder.startStatement().type(targetParameter.getType()).string(" ").tree(shortCircuitTree).end(); @@ -1942,69 +1939,229 @@ return builder.getRoot(); } - private CodeTree createExecutionExpresssions(CodeTreeBuilder parent, NodeChildData child, ExecutableTypeData sourceExecutable, ExecutableTypeData targetExecutable, ActualParameter param, - ActualParameter unexpectedParameter) { - CodeTreeBuilder builder = parent.create(); - - TypeData type = param.getTypeSystemType(); - List targetTypes = child.getNodeData().getTypeSystem().lookupSourceTypes(type); - - if (targetTypes.size() > 1) { + private ExecutableTypeData resolveExecutableType(NodeChildData child, TypeData type) { + ExecutableTypeData targetExecutable = child.findExecutableType(getContext(), type); + if (targetExecutable == null) { + targetExecutable = child.findAnyGenericExecutableType(getContext()); + } + return targetExecutable; + } + + private CodeTree createExecuteChild(CodeTreeBuilder parent, NodeChildData child, ExecutableTypeData sourceExecutable, ActualParameter targetParameter, ActualParameter unexpectedParameter) { + SpecializationData specialization = getModel(); + TreeSet possiblePolymorphicTypes = lookupPolymorphicTargetTypes(targetParameter); + if (specialization.isPolymorphic() && targetParameter.getTypeSystemType().isGeneric() && unexpectedParameter == null && possiblePolymorphicTypes.size() > 1) { + + CodeTreeBuilder builder = parent.create(); + 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(); + for (TypeData possiblePolymoprhicType : possiblePolymorphicTypes) { + if (possiblePolymoprhicType.isGeneric()) { + 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); + elseIf = builder.startIf(elseIf); + + ActualParameter sourceParameter = sourceExecutable.findParameter(targetParameter.getLocalName()); + TypeData sourceType = sourceParameter != null ? sourceParameter.getTypeSystemType() : null; + builder.string(polymorphicTypeName(targetParameter)).string(" == ").typeLiteral(possiblePolymoprhicType.getPrimitiveType()); + builder.end().startBlock(); + builder.startStatement(); + builder.tree(createExecuteChildExpression(parent, child, sourceType, new ActualParameter(targetParameter, possiblePolymoprhicType), unexpectedParameter, null)); + builder.end(); builder.end(); - index++; + } + + builder.startElseBlock(); + builder.startStatement().tree(createExecuteChildImplicit(parent, child, sourceExecutable, targetParameter, unexpectedParameter)).end(); + builder.end(); + + return builder.getRoot(); + } else { + return createExecuteChildImplicit(parent, child, sourceExecutable, targetParameter, unexpectedParameter); + } + } + + protected final TreeSet lookupPolymorphicTargetTypes(ActualParameter param) { + SpecializationData specialization = getModel(); + TreeSet possiblePolymorphicTypes = new TreeSet<>(); + for (SpecializationData otherSpecialization : specialization.getNode().getSpecializations()) { + if (!otherSpecialization.isSpecialized()) { + continue; + } + ActualParameter otherParameter = otherSpecialization.findParameter(param.getLocalName()); + if (otherParameter != null) { + possiblePolymorphicTypes.add(otherParameter.getTypeSystemType()); } + } + return possiblePolymorphicTypes; + } + + private CodeTree createExecuteChildImplicit(CodeTreeBuilder parent, NodeChildData child, ExecutableTypeData sourceExecutable, ActualParameter param, ActualParameter unexpectedParameter) { + CodeTreeBuilder builder = parent.create(); + 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; + } + builder.string(parameters.getLocalName()); + } + + if (sourceParameter != null) { + builder.string(valueNameEvaluated(sourceParameter)); + } + + builder.string(implicitTypeName(param)); + + builder.end(); } else { - builder.tree(createExecuteExpression(parent, child, sourceExecutable, targetExecutable, param, unexpectedParameter, null)); + List sourceTypes = child.getNodeData().getTypeSystem().lookupSourceTypes(param.getTypeSystemType()); + TypeData expectType = sourceParameter != null ? sourceParameter.getTypeSystemType() : null; + if (sourceTypes.size() > 1) { + builder.tree(createExecuteChildImplicitExpressions(parent, param, expectType)); + } else { + builder.tree(createExecuteChildExpression(parent, child, expectType, 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()); + if (child.getExecuteWith().size() > 0) { + return null; + } + 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; + } + + 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), implicitTypeName(param))); + + CodeTreeBuilder builder = method.createBuilder(); + builder.declaration(param.getType(), valueName(param)); + builder.tree(createExecuteChildImplicitExpressions(builder, param, expectType)); + builder.startReturn().string(valueName(param)).end(); + + return method; + } + + private CodeTree createExecuteChildImplicitExpressions(CodeTreeBuilder parent, ActualParameter targetParameter, TypeData expectType) { + CodeTreeBuilder builder = parent.create(); + NodeData node = getModel().getNode(); + NodeChildData child = node.findChild(targetParameter.getSpecification().getName()); + List sourceTypes = node.getTypeSystem().lookupSourceTypes(targetParameter.getTypeSystemType()); + boolean elseIf = false; + int index = 0; + for (TypeData sourceType : sourceTypes) { + if (index < sourceTypes.size() - 1) { + elseIf = builder.startIf(elseIf); + builder.string(implicitTypeName(targetParameter)).string(" == ").typeLiteral(sourceType.getPrimitiveType()); + builder.end(); + builder.startBlock(); + } else { + builder.startElseBlock(); + } + + ExecutableTypeData implictExecutableTypeData = child.findExecutableType(getContext(), sourceType); + 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(sourceType, targetParameter.getTypeSystemType()); + CodeTree execute = createExecuteChildExpression(builder, child, expectType, targetParameter, null, cast); + builder.statement(execute); + builder.end(); + index++; + } + return builder.getRoot(); + } + + private CodeTree createExecuteChildExpression(CodeTreeBuilder parent, NodeChildData child, TypeData sourceParameterType, ActualParameter targetParameter, ActualParameter unexpectedParameter, + ImplicitCastData cast) { + // assignments: targetType <- castTargetType <- castSourceType <- sourceType + TypeData sourceType = sourceParameterType; + TypeData targetType = targetParameter.getTypeSystemType(); + TypeData castSourceType = targetType; + TypeData castTargetType = targetType; + + if (cast != null) { + castSourceType = cast.getSourceType(); + castTargetType = cast.getTargetType(); + } + + CodeTree expression; + if (sourceType == null) { + ExecutableTypeData targetExecutable = resolveExecutableType(child, targetType); + expression = createExecuteChildExpression(parent, child, targetParameter, targetExecutable, unexpectedParameter); + sourceType = targetExecutable.getType(); + } else { + expression = CodeTreeBuilder.singleString(valueNameEvaluated(targetParameter)); + } + + // target = expectTargetType(implicitCast(expectCastSourceType(source))) + TypeSystemData typeSystem = child.getNodeData().getTypeSystem(); + expression = createExpectType(typeSystem, sourceType, castSourceType, expression); + expression = createImplicitCast(parent, typeSystem, cast, expression); + expression = createExpectType(typeSystem, castTargetType, targetType, expression); + CodeTreeBuilder builder = parent.create(); builder.string(valueName(targetParameter)); builder.string(" = "); - if (cast != null) { - 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())); + builder.tree(expression); + return builder.getRoot(); + } + + private CodeTree createImplicitCast(CodeTreeBuilder parent, TypeSystemData typeSystem, ImplicitCastData cast, CodeTree expression) { + if (cast == null) { + return expression; } - - NodeData node = getModel().getNode(); - ActualParameter sourceParameter = sourceExecutable.findParameter(targetParameter.getLocalName()); - if (sourceParameter == null) { - builder.tree(createExecuteChildExpression(builder, child, targetParameter, targetExecutable, unexpectedParameter)); - } else { - CodeTree var = CodeTreeBuilder.singleString(valueNameEvaluated(targetParameter)); - builder.tree(createExpectExecutableType(node, sourceParameter.getTypeSystemType(), targetExecutable, var)); - } - - if (targetExecutable.getType().needsCastTo(context, targetParameter.getTypeSystemType())) { - builder.end().end(); - } - - if (cast != null) { - builder.end().end(); - } - + CodeTreeBuilder builder = parent.create(); + startCallTypeSystemMethod(getContext(), builder, typeSystem, cast.getMethodName()); + builder.tree(expression); + builder.end().end(); return builder.getRoot(); } @@ -2021,49 +2178,67 @@ return false; } - private boolean hasUnexpected(ExecutableTypeData target, ActualParameter sourceParameter, ActualParameter targetParameter) { - List types = getModel().getNode().getTypeSystem().lookupSourceTypes(targetParameter.getTypeSystemType()); + private boolean hasUnexpected(ActualParameter sourceParameter, ActualParameter targetParameter, ActualParameter unexpectedParameter) { NodeChildData child = getModel().getNode().findChild(targetParameter.getSpecification().getName()); - boolean hasUnexpected = false; - for (TypeData type : types) { - if (hasUnexpected) { - continue; + + if (getModel().isPolymorphic() && targetParameter.getTypeSystemType().isGeneric() && unexpectedParameter == null) { + // check for other polymorphic types + TreeSet polymorphicTargetTypes = lookupPolymorphicTargetTypes(targetParameter); + if (polymorphicTargetTypes.size() > 1) { + for (TypeData polymorphicTargetType : polymorphicTargetTypes) { + if (hasUnexpectedType(child, sourceParameter, polymorphicTargetType)) { + return true; + } + } } - ExecutableTypeData execTarget = target; - if (type != execTarget.getType()) { - execTarget = child.findExecutableType(getContext(), type); - } - hasUnexpected = hasUnexpected || hasUnexpectedType(execTarget, sourceParameter, type); } - return hasUnexpected; - } - - private boolean hasUnexpectedType(ExecutableTypeData target, ActualParameter sourceParameter, TypeData type) { - boolean targetCast = target.getType().needsCastTo(context, type); - if (targetCast && getModel().getNode().getTypeSystem().lookupCast(target.getType(), type) == null) { + + if (hasUnexpectedType(child, sourceParameter, targetParameter.getTypeSystemType())) { return true; } - if (sourceParameter == null) { - return target.hasUnexpectedValue(getContext()); - } else { - if (sourceParameter.getTypeSystemType().needsCastTo(getContext(), type)) { - return target.hasUnexpectedValue(getContext()); + return false; + } + + private boolean hasUnexpectedType(NodeChildData child, ActualParameter sourceParameter, TypeData targetType) { + List implicitSourceTypes = getModel().getNode().getTypeSystem().lookupSourceTypes(targetType); + + for (TypeData implicitSourceType : implicitSourceTypes) { + TypeData sourceType; + ExecutableTypeData targetExecutable = resolveExecutableType(child, implicitSourceType); + if (sourceParameter != null) { + sourceType = sourceParameter.getTypeSystemType(); + } else { + if (targetExecutable.hasUnexpectedValue(getContext())) { + return true; + } + sourceType = targetExecutable.getType(); } - return false; + + ImplicitCastData cast = getModel().getNode().getTypeSystem().lookupCast(implicitSourceType, targetType); + if (cast != null) { + if (cast.getSourceType().needsCastTo(getContext(), targetType)) { + return true; + } + } + + if (sourceType.needsCastTo(getContext(), targetType)) { + return true; + } } + return false; } - private CodeTree createCatchUnexpectedTree(CodeTreeBuilder parent, CodeTree body, String targetVariableName, SpecializationData specialization, ExecutableTypeData currentExecutable, - ExecutableTypeData targetExecutable, ActualParameter param, boolean shortCircuit) { + private CodeTree createCatchUnexpectedTree(CodeTreeBuilder parent, CodeTree body, SpecializationData specialization, ExecutableTypeData currentExecutable, ActualParameter param, + boolean shortCircuit, ActualParameter unexpectedParameter) { CodeTreeBuilder builder = new CodeTreeBuilder(parent); ActualParameter sourceParameter = currentExecutable.findParameter(param.getLocalName()); - boolean unexpected = hasUnexpected(targetExecutable, sourceParameter, param); + boolean unexpected = hasUnexpected(sourceParameter, param, unexpectedParameter); if (!unexpected) { return body; } if (!shortCircuit) { - builder.declaration(param.getType(), targetVariableName); + builder.declaration(param.getType(), valueName(param)); } builder.startTryBlock(); @@ -2078,7 +2253,6 @@ ActualParameter genericParameter = generic.findParameter(param.getLocalName()); List genericParameters = generic.getParametersAfter(genericParameter); - builder.tree(createDeoptimize(builder)); builder.tree(createExecuteChildren(parent, currentExecutable, generic, genericParameters, genericParameter)); if (specialization.isPolymorphic()) { builder.tree(createReturnOptimizeTypes(builder, currentExecutable, specialization, param)); @@ -2097,6 +2271,8 @@ SpecializationData generic = node.getGenericPolymorphicSpecialization(); CodeTreeBuilder builder = new CodeTreeBuilder(parent); + builder.startStatement().string(polymorphicTypeName(param)).string(" = ").typeLiteral(getContext().getType(Object.class)).end(); + builder.startReturn(); CodeTreeBuilder execute = new CodeTreeBuilder(builder); @@ -2186,8 +2362,7 @@ return builder.getRoot(); } - private CodeTree createShortCircuitTree(CodeTreeBuilder parent, CodeTree body, String targetVariableName, SpecializationData specialization, ActualParameter parameter, - ActualParameter exceptionParam) { + private CodeTree createShortCircuitTree(CodeTreeBuilder parent, CodeTree body, SpecializationData specialization, ActualParameter parameter, ActualParameter exceptionParam) { NodeChildData forField = specialization.getNode().findChild(parameter.getSpecification().getName()); if (!isShortCircuit(forField)) { return body; @@ -2196,7 +2371,7 @@ CodeTreeBuilder builder = new CodeTreeBuilder(parent); ActualParameter shortCircuitParam = specialization.getPreviousParam(parameter); builder.tree(createShortCircuitValue(builder, specialization, forField, shortCircuitParam, exceptionParam)); - builder.declaration(parameter.getType(), targetVariableName, CodeTreeBuilder.createBuilder().defaultValue(parameter.getType())); + builder.declaration(parameter.getType(), valueName(parameter), CodeTreeBuilder.createBuilder().defaultValue(parameter.getType())); builder.startIf().string(shortCircuitParam.getLocalName()).end(); builder.startBlock(); @@ -2260,32 +2435,78 @@ return builder.getRoot(); } + + protected final CodeExecutableElement createUpdateTypes(TypeMirror polymorphicType) { + CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED), getContext().getType(void.class), UPDATE_TYPES_NAME); + method.getParameters().add(new CodeVariableElement(polymorphicType, "polymorphic")); + CodeTreeBuilder builder = method.createBuilder(); + + if (getModel().isPolymorphic()) { + builder.startStatement(); + builder.startCall("next0", "updateTypes").string("polymorphic").end(); + builder.end(); + } else if (getModel().isSpecialized()) { + for (ActualParameter parameter : getModel().getParameters()) { + if (!parameter.getSpecification().isSignature()) { + continue; + } + if (lookupPolymorphicTargetTypes(parameter).size() <= 1) { + continue; + } + builder.startStatement(); + builder.startCall("polymorphic", createUpdateTypeName(parameter)); + builder.typeLiteral(parameter.getType()); + builder.end().end(); + } + + builder.startStatement().startCall("super", UPDATE_TYPES_NAME).string("polymorphic").end().end(); + } + return method; + } + + protected String createUpdateTypeName(ActualParameter parameter) { + return "update" + Utils.firstLetterUpperCase(parameter.getLocalName()) + "Type"; + } } private class PolymorphicNodeFactory extends SpecializedNodeFactory { - private final boolean generic; - - public PolymorphicNodeFactory(ProcessorContext context, CodeTypeElement nodeGen, boolean generic) { + public PolymorphicNodeFactory(ProcessorContext context, CodeTypeElement nodeGen) { super(context, nodeGen); - this.generic = generic; } @Override - public CodeTypeElement create(SpecializationData specialization) { - NodeData node = specialization.getNode(); + public CodeTypeElement create(SpecializationData polymorph) { + NodeData node = polymorph.getNode(); TypeMirror baseType = node.getNodeType(); if (nodeGen != null) { baseType = nodeGen.asType(); } - CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, STATIC), nodePolymorphicClassName(node, specialization), baseType, false); - - if (!generic) { - clazz.getModifiers().add(Modifier.FINAL); - } + CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, STATIC, FINAL), nodePolymorphicClassName(node, polymorph), baseType, false); clazz.getAnnotationMirrors().add(createNodeInfo(node, Kind.POLYMORPHIC)); + for (ActualParameter polymorphParameter : polymorph.getParameters()) { + if (!polymorphParameter.getSpecification().isSignature()) { + continue; + } + if (!polymorphParameter.getTypeSystemType().isGeneric()) { + continue; + } + Set types = new HashSet<>(); + for (SpecializationData specialization : node.getSpecializations()) { + if (!specialization.isSpecialized()) { + continue; + } + ActualParameter parameter = specialization.findParameter(polymorphParameter.getLocalName()); + assert parameter != null; + types.add(parameter.getTypeSystemType()); + } + CodeVariableElement var = new CodeVariableElement(modifiers(PRIVATE), getContext().getType(Class.class), polymorphicTypeName(polymorphParameter)); + var.getAnnotationMirrors().add(new CodeAnnotationMirror(getContext().getTruffleTypes().getCompilationFinal())); + clazz.add(var); + } + return clazz; } @@ -2296,273 +2517,39 @@ createConstructors(clazz); createExecuteMethods(specialization); - if (generic) { - getElement().add(createOptimizeTypes()); - createCachedExecuteMethods(specialization); - createIsCompatible(clazz, specialization); - } - } - - private CodeExecutableElement createOptimizeTypes() { - NodeData node = getModel().getNode(); - CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, FINAL), getContext().getType(void.class), "optimizeTypes"); - CodeTreeBuilder builder = method.createBuilder(); - - boolean elseIf = false; - for (SpecializationData polymorphic : node.getPolymorphicSpecializations()) { - String className = nodePolymorphicClassName(node, polymorphic); - - String sep = ""; - StringBuilder reason = new StringBuilder("Optimized polymorphic types for ("); - for (ActualParameter parameter : polymorphic.getReturnTypeAndParameters()) { - if (!parameter.getSpecification().isSignature()) { - continue; - } - reason.append(sep).append(Utils.getSimpleName(parameter.getType())); - sep = ", "; + getElement().add(createUpdateTypes(nodeGen.asType())); + + for (ActualParameter parameter : specialization.getParameters()) { + if (!parameter.getSpecification().isSignature()) { + continue; } - reason.append(")"); - - elseIf = builder.startIf(elseIf); - builder.startCall("isCompatible0"); - builder.startGroup().string(className).string(".class").end(); - builder.end().end().startBlock(); - - builder.startStatement().startCall("super", "replace"); - builder.startNew(className).string("this").end(); - builder.doubleQuote(reason.toString()); - builder.end().end(); // call - builder.end(); - } - return method; - } - } - - private class BaseCastNodeFactory extends ClassElementFactory { - - protected final Set usedTargetTypes; - - public BaseCastNodeFactory(ProcessorContext context, Set usedTargetTypes) { - super(context); - this.usedTargetTypes = usedTargetTypes; - } - - @Override - protected CodeTypeElement create(NodeData m) { - CodeTypeElement type = createClass(m, modifiers(STATIC), nodeCastClassName(m, null), context.getTruffleTypes().getNode(), false); - - CodeVariableElement delegate = new CodeVariableElement(m.getNodeType(), "delegate"); - delegate.getModifiers().add(PROTECTED); - delegate.getAnnotationMirrors().add(new CodeAnnotationMirror(getContext().getTruffleTypes().getChildAnnotation())); - - type.add(delegate); - type.add(createConstructorUsingFields(modifiers(), type)); - return type; - } - - @Override - protected void createChildren(NodeData m) { - CodeTypeElement type = getElement(); - type.add(createExecute(EXECUTE_SPECIALIZE_NAME, true)); - type.add(createExecute(EXECUTE_GENERIC_NAME, false)); - - for (ExecutableTypeData targetExecutable : m.getExecutableTypes()) { - if (!usedTargetTypes.contains(targetExecutable.getType()) && targetExecutable.hasUnexpectedValue(getContext())) { + if (lookupPolymorphicTargetTypes(parameter).size() <= 1) { continue; } - CodeExecutableElement execute = createCastExecute(targetExecutable, targetExecutable, false); - CodeExecutableElement expect = createCastExecute(targetExecutable, targetExecutable, true); - if (execute != null) { - getElement().add(execute); - } - if (expect != null) { - getElement().add(expect); - } - } - Set sourceTypes = new TreeSet<>(); - List casts = getModel().getTypeSystem().getImplicitCasts(); - for (ImplicitCastData cast : casts) { - sourceTypes.add(cast.getSourceType()); - } - - CodeTypeElement baseType = getElement(); - for (TypeData sourceType : sourceTypes) { - add(new SpecializedCastNodeFactory(context, baseType, sourceType, usedTargetTypes), getModel()); - } - } - - private CodeExecutableElement createExecute(String name, boolean specialize) { - NodeData node = getModel(); - TypeMirror objectType = node.getTypeSystem().getGenericType(); - CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), objectType, name, new CodeVariableElement(objectType, "value")); - if (specialize) { - method.getModifiers().add(FINAL); + getElement().add(createUpdateType(parameter)); } + + createCachedExecuteMethods(specialization); + + } + + private ExecutableElement createUpdateType(ActualParameter parameter) { + CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED), getContext().getType(void.class), createUpdateTypeName(parameter)); + method.getParameters().add(new CodeVariableElement(getContext().getType(Class.class), "type")); CodeTreeBuilder builder = method.createBuilder(); - List casts = node.getTypeSystem().getImplicitCasts(); - boolean elseIf = false; - for (ImplicitCastData cast : casts) { - elseIf = builder.startIf(elseIf); - startCallTypeSystemMethod(context, builder, getModel(), TypeSystemCodeGenerator.isTypeMethodName(cast.getSourceType())); - builder.string("value"); - builder.end().end(); - builder.end(); - builder.startBlock(); - - if (specialize) { - builder.startStatement().startCall("replace").startNew(nodeCastClassName(getModel(), cast.getSourceType())).string("delegate").end().doubleQuote("Added cast").end().end(); - } - builder.startReturn(); - - startCallTypeSystemMethod(context, builder, getModel(), cast.getMethodName()); - startCallTypeSystemMethod(context, builder, getModel(), TypeSystemCodeGenerator.asTypeMethodName(cast.getSourceType())); - builder.string("value"); - builder.end().end(); - builder.end().end(); - - builder.end(); - builder.end(); - } - - builder.startReturn().string("value").end(); + String fieldName = polymorphicTypeName(parameter); + builder.startIf().string(fieldName).isNull().end().startBlock(); + builder.startStatement().string(fieldName).string(" = ").string("type").end(); + builder.end(); + builder.startElseIf().string(fieldName).string(" != ").string("type").end(); + builder.startBlock(); + builder.startStatement().string(fieldName).string(" = ").typeLiteral(getContext().getType(Object.class)).end(); + builder.end(); return method; } - protected CodeExecutableElement createCastExecute(ExecutableTypeData sourceExecutable, ExecutableTypeData targetExecutable, boolean expect) { - ImplicitCastData cast = null; - if (!sourceExecutable.getType().equals(targetExecutable.getType())) { - cast = getModel().getTypeSystem().lookupCast(sourceExecutable.getType(), targetExecutable.getType()); - if (cast == null) { - return null; - } - } - - if (expect) { - if (targetExecutable.getEvaluatedCount() > 0) { - return null; - } else if (Utils.isObject(targetExecutable.getType().getPrimitiveType())) { - return null; - } - } - - boolean hasTargetUnexpected = targetExecutable.hasUnexpectedValue(getContext()); - boolean hasSourceUnexpected = sourceExecutable.hasUnexpectedValue(getContext()); - - CodeExecutableElement method = copyTemplateMethod(targetExecutable); - method.getModifiers().add(PUBLIC); - - CodeTreeBuilder builder = method.createBuilder(); - - if (hasSourceUnexpected && cast != null) { - builder.startTryBlock(); - } - - if (expect) { - method.getParameters().clear(); - String expectMethodName; - if (hasTargetUnexpected) { - expectMethodName = TypeSystemCodeGenerator.expectTypeMethodName(targetExecutable.getType()); - } else { - expectMethodName = TypeSystemCodeGenerator.asTypeMethodName(targetExecutable.getType()); - } - method.setSimpleName(CodeNames.of(expectMethodName)); - method.addParameter(new CodeVariableElement(getModel().getTypeSystem().getGenericType(), "value")); - } - - builder.startReturn(); - CodeTree executeCall; - if (expect) { - executeCall = createCastType(getModel(), getModel().getTypeSystem().getGenericTypeData(), sourceExecutable.getType(), hasSourceUnexpected, CodeTreeBuilder.singleString("value")); - } else { - executeCall = createTemplateMethodCall(builder, CodeTreeBuilder.singleString("delegate."), targetExecutable, sourceExecutable, null); - } - if (cast != null) { - startCallTypeSystemMethod(context, builder, getModel(), cast.getMethodName()); - builder.tree(executeCall); - builder.end().end(); - } else { - builder.tree(executeCall); - } - builder.end(); - - if (hasSourceUnexpected && cast != null) { - builder.end(); - builder.startCatchBlock(getContext().getTruffleTypes().getUnexpectedValueException(), "ex"); - builder.startStatement().startCall("replace").startNew(nodeCastClassName(getModel(), null)).string("delegate").end().doubleQuote("Removed cast").end().end(); - - if (hasTargetUnexpected) { - builder.startThrow().string("ex").end(); - } else { - builder.startThrow().startNew(getContext().getType(AssertionError.class)).end().end(); - } - builder.end(); - } - - return method; - } - - private CodeExecutableElement copyTemplateMethod(TemplateMethod targetExecutable) { - CodeExecutableElement method = CodeExecutableElement.clone(getContext().getEnvironment(), targetExecutable.getMethod()); - method.getModifiers().remove(ABSTRACT); - method.getAnnotationMirrors().clear(); - Modifier visibility = Utils.getVisibility(method.getModifiers()); - if (visibility != null) { - method.getModifiers().remove(visibility); - } - int index = 0; - for (ActualParameter parameter : targetExecutable.getParameters()) { - ((CodeVariableElement) method.getParameters().get(index)).setName(parameter.getLocalName()); - index++; - } - return method; - } - - } - - private class SpecializedCastNodeFactory extends BaseCastNodeFactory { - - private final CodeTypeElement baseType; - private final TypeData sourceType; - - public SpecializedCastNodeFactory(ProcessorContext context, CodeTypeElement baseType, TypeData type, Set usedTargetTypes) { - super(context, usedTargetTypes); - this.baseType = baseType; - this.sourceType = type; - } - - @Override - protected CodeTypeElement create(NodeData m) { - CodeTypeElement type = createClass(m, modifiers(PRIVATE, STATIC, FINAL), nodeCastClassName(m, sourceType), baseType.asType(), false); - type.add(createConstructorUsingFields(modifiers(), type)); - return type; - } - - @Override - protected void createChildren(NodeData node) { - for (TypeData targetType : usedTargetTypes) { - for (ExecutableTypeData targetExecutable : node.getExecutableTypes()) { - if (targetExecutable.getType().equals(targetType)) { - ExecutableTypeData sourceExecutable = node.findExecutableType(sourceType, targetExecutable.getEvaluatedCount()); - if (sourceExecutable == null) { - // TODO what if there is no evaluated version? - continue; - } - CodeExecutableElement execute = createCastExecute(sourceExecutable, targetExecutable, false); - CodeExecutableElement expect = createCastExecute(sourceExecutable, targetExecutable, true); - if (execute != null) { - getElement().add(execute); - } - if (expect != null) { - getElement().add(expect); - } - } - } - - } - } - } private class SpecializedNodeFactory extends NodeBaseFactory { @@ -2615,14 +2602,11 @@ CodeTypeElement clazz = getElement(); createConstructors(clazz); - NodeData node = specialization.getNode(); - - if (node.needsRewrites(getContext()) && node.isPolymorphic()) { - createIsCompatible(clazz, specialization); - } - createExecuteMethods(specialization); createCachedExecuteMethods(specialization); + if (specialization.getNode().isPolymorphic()) { + getElement().add(createUpdateTypes(nodeGen.asType())); + } } protected void createConstructors(CodeTypeElement clazz) { @@ -2659,11 +2643,11 @@ NodeChildData child = getModel().getNode().findChild(param.getSpecification().getName()); List types = child.getNodeData().getTypeSystem().lookupSourceTypes(param.getTypeSystemType()); if (types.size() > 1) { - clazz.add(new CodeVariableElement(modifiers(PRIVATE, FINAL), getContext().getType(Class.class), typeName(param))); - superConstructor.getParameters().add(new CodeVariableElement(getContext().getType(Class.class), typeName(param))); + clazz.add(new CodeVariableElement(modifiers(PRIVATE, FINAL), getContext().getType(Class.class), implicitTypeName(param))); + superConstructor.getParameters().add(new CodeVariableElement(getContext().getType(Class.class), implicitTypeName(param))); builder.startStatement(); - builder.string("this.").string(typeName(param)).string(" = ").string(typeName(param)); + builder.string("this.").string(implicitTypeName(param)).string(" = ").string(implicitTypeName(param)); builder.end(); } } @@ -2695,39 +2679,45 @@ protected void createCachedExecuteMethods(SpecializationData specialization) { NodeData node = specialization.getNode(); + if (!node.isPolymorphic()) { + return; + } + CodeTypeElement clazz = getElement(); - for (final SpecializationData polymorphic : node.getPolymorphicSpecializations()) { - if (!specialization.getSignature().isCompatibleTo(polymorphic.getSignature())) { - continue; - } - ExecutableElement executeCached = nodeGen.getMethod(executeCachedName(polymorphic)); - ExecutableTypeData execType = new ExecutableTypeData(polymorphic, executeCached, node.getTypeSystem(), polymorphic.getReturnType().getTypeSystemType()); - - CodeExecutableElement executeMethod = createExecutableTypeOverride(execType, false); - CodeTreeBuilder builder = executeMethod.createBuilder(); - - if (specialization.isGeneric() || specialization.isPolymorphic()) { - builder.startThrow().startNew(getContext().getType(AssertionError.class)); - builder.doubleQuote("Should not be reached."); - builder.end().end(); - } else if (specialization.isUninitialized()) { - builder.tree(createAppendPolymorphic(builder, specialization)); - } else { - CodeTreeBuilder elseBuilder = new CodeTreeBuilder(builder); - elseBuilder.startReturn().startCall("this.next0", executeCachedName(polymorphic)); - addInternalValueParameterNames(elseBuilder, polymorphic, polymorphic, null, true, true, null); - elseBuilder.end().end(); - - boolean forceElse = specialization.getExceptions().size() > 0; - builder.tree(createExecuteTree(builder, polymorphic, SpecializationGroup.create(specialization), false, new CodeBlock() { - - public CodeTree create(CodeTreeBuilder b, SpecializationData current) { - return createGenericInvoke(b, polymorphic, current); - } - }, elseBuilder.getRoot(), forceElse, true)); - } - clazz.add(executeMethod); + + final SpecializationData polymorphic = node.getGenericPolymorphicSpecialization(); + + ExecutableElement executeCached = nodeGen.getMethod(executeCachedName(polymorphic)); +// ExecutableTypeData execType = new ExecutableTypeData(polymorphic, executeCached, +// node.getTypeSystem(), polymorphic.getReturnType().getTypeSystemType()); + + ExecutableTypeMethodParser parser = new ExecutableTypeMethodParser(getContext(), node); + ExecutableTypeData execType = parser.parse(Arrays.asList(executeCached)).get(0); + + CodeExecutableElement executeMethod = createExecutableTypeOverride(execType, false); + CodeTreeBuilder builder = executeMethod.createBuilder(); + + if (specialization.isGeneric() || specialization.isPolymorphic()) { + builder.startThrow().startNew(getContext().getType(AssertionError.class)); + builder.doubleQuote("Should not be reached."); + builder.end().end(); + } else if (specialization.isUninitialized()) { + builder.tree(createAppendPolymorphic(builder, specialization)); + } else { + CodeTreeBuilder elseBuilder = new CodeTreeBuilder(builder); + elseBuilder.startReturn().startCall("this.next0", executeCachedName(polymorphic)); + addInternalValueParameterNames(elseBuilder, polymorphic, polymorphic, null, true, true, null); + elseBuilder.end().end(); + + boolean forceElse = specialization.getExceptions().size() > 0; + builder.tree(createExecuteTree(builder, polymorphic, SpecializationGroup.create(specialization), false, new CodeBlock() { + + public CodeTree create(CodeTreeBuilder b, SpecializationData current) { + return createGenericInvoke(b, polymorphic, current); + } + }, elseBuilder.getRoot(), forceElse, true, true)); } + clazz.add(executeMethod); } private CodeTree createAppendPolymorphic(CodeTreeBuilder parent, SpecializationData specialization) { @@ -2763,8 +2753,9 @@ builder.declaration(node.getGenericSpecialization().getReturnType().getType(), "result", specializeCall.getRoot()); + CodeTree root = builder.create().cast(nodePolymorphicClassName(node, node.getGenericPolymorphicSpecialization())).string("root").getRoot(); builder.startIf().string("this.next0 != null").end().startBlock(); - builder.startStatement().string("(").cast(nodePolymorphicClassName(node, node.getGenericPolymorphicSpecialization())).string("root).optimizeTypes()").end(); + builder.startStatement().string("(").tree(root).string(").").startCall(UPDATE_TYPES_NAME).tree(root).end().end(); builder.end(); if (Utils.isVoid(builder.findMethod().getReturnType())) { @@ -2880,7 +2871,7 @@ public CodeTree create(CodeTreeBuilder b, SpecializationData current) { return createExecute(b, executable, specialization); } - }, returnSpecialized, false, false)); + }, returnSpecialized, false, false, false)); return builder.getRoot(); } diff -r ce5e6f9075b6 -r bfcae72b61a0 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeParser.java Mon Oct 14 13:49:46 2013 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeParser.java Mon Oct 14 15:51:57 2013 +0200 @@ -223,62 +223,44 @@ return; } - Signature genericSignature = node.getGenericSpecialization().getSignature(); - Set signatures = new TreeSet<>(); + SpecializationData generic = node.getGenericSpecialization(); - for (SpecializationData specialization1 : node.getSpecializations()) { - Signature signature = specialization1.getSignature(); + List polymorphicSignature = new ArrayList<>(); + // TODO we should support more optimized for boxing +// List updatePolymorphic = generic.getReturnTypeAndParameters(); + List updatePolymorphic = Arrays.asList(); + for (ActualParameter genericParameter : updatePolymorphic) { + if (!genericParameter.getSpecification().isSignature()) { + continue; + } - for (SpecializationData specialization2 : node.getSpecializations()) { - if (specialization1 == specialization2) { + Set usedTypes = new HashSet<>(); + for (SpecializationData specialization : node.getSpecializations()) { + if (!specialization.isSpecialized()) { continue; } - signatures.add(signature.combine(genericSignature, specialization2.getSignature())); + ActualParameter parameter = specialization.findParameter(genericParameter.getLocalName()); + if (parameter == null) { + throw new AssertionError("Parameter existed in generic specialization but not in specialized. param = " + genericParameter.getLocalName()); + } + usedTypes.add(parameter.getTypeSystemType()); } + + TypeData polymorphicType; + if (usedTypes.size() == 1) { + polymorphicType = usedTypes.iterator().next(); + } else { + polymorphicType = node.getTypeSystem().getGenericTypeData(); + } + polymorphicSignature.add(polymorphicType); } - while (true) { - List newSignatures = new ArrayList<>(); - for (Signature signature1 : signatures) { - for (Signature signature2 : signatures) { - if (signature1 == signature2) { - continue; - } - newSignatures.add(signature1.combine(genericSignature, signature2)); - } - } - if (!signatures.addAll(newSignatures)) { - break; - } - } - - List sortedSignatures = new ArrayList<>(signatures); - - SpecializationData polymorphicGeneric = null; - List specializations = new ArrayList<>(); - SpecializationData generic = node.getGenericSpecialization(); - for (Signature signature : sortedSignatures) { - SpecializationData specialization = new SpecializationData(generic, false, false, true); - - for (Iterator iterator = specialization.getParameters().iterator(); iterator.hasNext();) { - ActualParameter param = iterator.next(); - if (param.getSpecification().isLocal()) { - iterator.remove(); - } - } - - specialization.forceFrame(context.getTruffleTypes().getFrame()); - specialization.setNode(node); - specialization.updateSignature(signature); - specializations.add(specialization); - - if (genericSignature.equals(signature)) { - polymorphicGeneric = specialization; - } - } - - node.setGenericPolymorphicSpecialization(polymorphicGeneric); - node.setPolymorphicSpecializations(specializations); + SpecializationData specialization = new SpecializationData(generic, false, false, true); + specialization.updateSignature(new Signature(polymorphicSignature)); + specialization.setNode(node); + node.setGenericPolymorphicSpecialization(specialization); + // TODO remove polymoprhic specializations + node.setPolymorphicSpecializations(Collections. emptyList()); } private NodeData parseNodeData(TypeElement templateType, TypeMirror nodeType, List elements, List typeHierarchy) { diff -r ce5e6f9075b6 -r bfcae72b61a0 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/SpecializationData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/SpecializationData.java Mon Oct 14 13:49:46 2013 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/SpecializationData.java Mon Oct 14 15:51:57 2013 +0200 @@ -188,6 +188,10 @@ return order; } + public boolean isSpecialized() { + return !isGeneric() && !isUninitialized() && !isPolymorphic(); + } + public boolean isGeneric() { return generic; } @@ -268,4 +272,13 @@ } return false; } + + public boolean hasFrame(ProcessorContext context) { + for (ActualParameter param : getParameters()) { + if (Utils.typeEquals(param.getType(), context.getTruffleTypes().getFrame())) { + return true; + } + } + return false; + } } diff -r ce5e6f9075b6 -r bfcae72b61a0 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/SpecializationGroup.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/SpecializationGroup.java Mon Oct 14 13:49:46 2013 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/SpecializationGroup.java Mon Oct 14 15:51:57 2013 +0200 @@ -90,7 +90,14 @@ return null; } - public List getElseConnectableGuards() { + public List findElseConnectableGuards(boolean minimumStateCheck) { + if (minimumStateCheck) { + /* + * TODO investigate further if we really cannot else connect guards if minimum state is + * required + */ + return Collections.emptyList(); + } if (!getTypeGuards().isEmpty() || !getAssumptions().isEmpty()) { return Collections.emptyList(); } @@ -101,7 +108,7 @@ List elseConnectableGuards = new ArrayList<>(); int guardIndex = 0; - while (guardIndex < getGuards().size() && findNegatedGuardInPrevious(getGuards().get(guardIndex)) != null) { + while (guardIndex < getGuards().size() && findNegatedGuardInPrevious(getGuards().get(guardIndex), minimumStateCheck) != null) { elseConnectableGuards.add(getGuards().get(guardIndex)); guardIndex++; } @@ -109,17 +116,18 @@ return elseConnectableGuards; } - private GuardData findNegatedGuardInPrevious(GuardData guard) { + private GuardData findNegatedGuardInPrevious(GuardData guard, boolean minimumStateCheck) { SpecializationGroup previous = this.getPreviousGroup(); if (previous == null) { return null; } - List elseConnectedGuards = previous.getElseConnectableGuards(); + List elseConnectedGuards = previous.findElseConnectableGuards(minimumStateCheck); if (previous == null || previous.getGuards().size() != elseConnectedGuards.size() + 1) { return null; } + /* Guard is else branch can be connected in previous specialization. */ if (elseConnectedGuards.contains(guard)) { return guard; } @@ -341,6 +349,28 @@ return parent.children.get(index - 1); } + public int getUncheckedSpecializationIndex() { + int groupMaxIndex = getMaxSpecializationIndex(); + + int genericIndex = node.getSpecializations().indexOf(node.getGenericSpecialization()); + if (groupMaxIndex >= genericIndex) { + // no minimum state check for an generic index + groupMaxIndex = -1; + } + + if (groupMaxIndex > -1) { + // no minimum state check if already checked by parent group + int parentMaxIndex = -1; + if (getParent() != null) { + parentMaxIndex = getParent().getMaxSpecializationIndex(); + } + if (groupMaxIndex == parentMaxIndex) { + groupMaxIndex = -1; + } + } + return groupMaxIndex; + } + public int getMaxSpecializationIndex() { if (specialization != null) { return specialization.getNode().getSpecializations().indexOf(specialization); diff -r ce5e6f9075b6 -r bfcae72b61a0 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/TemplateMethod.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/TemplateMethod.java Mon Oct 14 13:49:46 2013 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/TemplateMethod.java Mon Oct 14 15:51:57 2013 +0200 @@ -237,6 +237,9 @@ if (!parameter.getSpecification().isSignature()) { continue; } + if (signatureIndex >= signature.size()) { + break; + } TypeData newType = signature.get(signatureIndex++); if (!parameter.getTypeSystemType().equals(newType)) { replaceParameter(parameter.getLocalName(), new ActualParameter(parameter, newType)); diff -r ce5e6f9075b6 -r bfcae72b61a0 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/TypeSystemCodeGenerator.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/TypeSystemCodeGenerator.java Mon Oct 14 13:49:46 2013 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/TypeSystemCodeGenerator.java Mon Oct 14 15:51:57 2013 +0200 @@ -97,35 +97,18 @@ for (TypeData type : typeSystem.getTypes()) { if (!type.isGeneric()) { - CodeExecutableElement isType = createIsTypeMethod(type); - if (isType != null) { - clazz.add(isType); - } - CodeExecutableElement asType = createAsTypeMethod(type); - if (asType != null) { - clazz.add(asType); - } + clazz.addOptional(createIsTypeMethod(type)); + clazz.addOptional(createAsTypeMethod(type)); for (TypeData sourceType : collectExpectSourceTypes(type)) { - CodeExecutableElement expect = createExpectTypeMethod(type, sourceType); - if (expect != null) { - clazz.add(expect); - } + clazz.addOptional(createExpectTypeMethod(type, sourceType)); } - CodeExecutableElement asImplicit = createAsImplicitTypeMethod(type); - if (asImplicit != null) { - clazz.add(asImplicit); - } - CodeExecutableElement isImplicit = createIsImplicitTypeMethod(type); - if (isImplicit != null) { - clazz.add(isImplicit); - } - - CodeExecutableElement typeIndex = createGetTypeIndex(type); - if (typeIndex != null) { - clazz.add(typeIndex); - } + clazz.addOptional(createAsImplicitTypeMethod(type, true)); + clazz.addOptional(createAsImplicitTypeMethod(type, false)); + clazz.addOptional(createIsImplicitTypeMethod(type, true)); + clazz.addOptional(createIsImplicitTypeMethod(type, false)); + clazz.addOptional(createGetTypeIndex(type)); } } @@ -159,7 +142,7 @@ return field; } - private CodeExecutableElement createIsImplicitTypeMethod(TypeData type) { + private CodeExecutableElement createIsImplicitTypeMethod(TypeData type, boolean typed) { TypeSystemData typeSystem = getModel(); List casts = typeSystem.lookupByTargetType(type); if (casts.isEmpty()) { @@ -167,6 +150,9 @@ } CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), getContext().getType(boolean.class), TypeSystemCodeGenerator.isImplicitTypeMethodName(type)); method.addParameter(new CodeVariableElement(getContext().getType(Object.class), LOCAL_VALUE)); + if (typed) { + method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "typeHint")); + } CodeTreeBuilder builder = method.createBuilder(); List sourceTypes = typeSystem.lookupSourceTypes(type); @@ -175,14 +161,27 @@ String sep = ""; for (TypeData sourceType : sourceTypes) { builder.string(sep); + if (typed) { + builder.string("(typeHint == ").typeLiteral(sourceType.getPrimitiveType()).string(" && "); + } builder.startCall(isTypeMethodName(sourceType)).string(LOCAL_VALUE).end(); + if (typed) { + builder.string(")"); + } + if (sourceTypes.lastIndexOf(sourceType) != sourceTypes.size() - 1) { + builder.newLine(); + } + if (sep.equals("")) { + builder.startIndention(); + } sep = " || "; } builder.end(); + builder.end(); return method; } - private CodeExecutableElement createAsImplicitTypeMethod(TypeData type) { + private CodeExecutableElement createAsImplicitTypeMethod(TypeData type, boolean typed) { TypeSystemData typeSystem = getModel(); List casts = typeSystem.lookupByTargetType(type); if (casts.isEmpty()) { @@ -190,6 +189,9 @@ } CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), type.getPrimitiveType(), TypeSystemCodeGenerator.asImplicitTypeMethodName(type)); method.addParameter(new CodeVariableElement(getContext().getType(Object.class), LOCAL_VALUE)); + if (typed) { + method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "typeHint")); + } List sourceTypes = typeSystem.lookupSourceTypes(type); @@ -197,7 +199,12 @@ boolean elseIf = false; for (TypeData sourceType : sourceTypes) { elseIf = builder.startIf(elseIf); - builder.startCall(isTypeMethodName(sourceType)).string(LOCAL_VALUE).end(); + if (typed) { + builder.string("typeHint == ").typeLiteral(sourceType.getPrimitiveType()); + } else { + builder.startCall(isTypeMethodName(sourceType)).string(LOCAL_VALUE).end(); + } + builder.end().startBlock(); builder.startReturn(); diff -r ce5e6f9075b6 -r bfcae72b61a0 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/NodeFactory.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/NodeFactory.java Mon Oct 14 13:49:46 2013 +0200 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/NodeFactory.java Mon Oct 14 15:51:57 2013 +0200 @@ -63,7 +63,7 @@ } public TypedNode createStringLiteral(String value) { - return StringLiteralNodeFactory.create(value); + return new StringLiteralNode(value); } public StatementNode createAssignment(String name, TypedNode right) { @@ -112,9 +112,9 @@ public TypedNode createNumericLiteral(String value) { try { - return IntegerLiteralNodeFactory.create(Integer.parseInt(value)); + return new IntegerLiteralNode(Integer.parseInt(value)); } catch (NumberFormatException ex) { - return BigIntegerLiteralNodeFactory.create(new BigInteger(value)); + return new BigIntegerLiteralNode(new BigInteger(value)); } } diff -r ce5e6f9075b6 -r bfcae72b61a0 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLTypes.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLTypes.java Mon Oct 14 13:49:46 2013 +0200 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLTypes.java Mon Oct 14 15:51:57 2013 +0200 @@ -46,32 +46,9 @@ } } - @TypeCheck - public boolean isBigInteger(Object value) { - return value instanceof Integer || value instanceof BigInteger; - } - - @TypeCast - public BigInteger asBigInteger(Object value) { - if (value instanceof Integer) { - return BigInteger.valueOf((int) value); - } else { - return (BigInteger) value; - } + @ImplicitCast + public BigInteger castBigInteger(int integer) { + return BigInteger.valueOf(integer); } - @TypeCast - public BigInteger asBigInteger(int value) { - return BigInteger.valueOf(value); - } - - @TypeCheck - public boolean isBigInteger(@SuppressWarnings("unused") int value) { - return true; - } - - @ImplicitCast - public BigInteger castBigInteger(int value) { - return BigInteger.valueOf(value); - } } diff -r ce5e6f9075b6 -r bfcae72b61a0 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/BigIntegerLiteralNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/BigIntegerLiteralNode.java Mon Oct 14 13:49:46 2013 +0200 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/BigIntegerLiteralNode.java Mon Oct 14 15:51:57 2013 +0200 @@ -24,9 +24,10 @@ import java.math.*; -import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; -public abstract class BigIntegerLiteralNode extends TypedNode { +public final class BigIntegerLiteralNode extends TypedNode { private final BigInteger value; @@ -34,8 +35,14 @@ this.value = value; } - @Specialization - public BigInteger doBigInteger() { + @Override + public BigInteger executeBigInteger(VirtualFrame frame) throws UnexpectedResultException { return value; } + + @Override + public Object executeGeneric(VirtualFrame frame) { + return value; + } + } diff -r ce5e6f9075b6 -r bfcae72b61a0 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/IntegerLiteralNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/IntegerLiteralNode.java Mon Oct 14 13:49:46 2013 +0200 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/IntegerLiteralNode.java Mon Oct 14 15:51:57 2013 +0200 @@ -22,9 +22,10 @@ */ package com.oracle.truffle.sl.nodes; -import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; -public abstract class IntegerLiteralNode extends TypedNode { +public final class IntegerLiteralNode extends TypedNode { private final int value; @@ -32,8 +33,13 @@ this.value = value; } - @Specialization - protected int doInteger() { - return this.value; + @Override + public int executeInteger(VirtualFrame frame) throws UnexpectedResultException { + return value; + } + + @Override + public Object executeGeneric(VirtualFrame frame) { + return value; } } diff -r ce5e6f9075b6 -r bfcae72b61a0 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/StringLiteralNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/StringLiteralNode.java Mon Oct 14 13:49:46 2013 +0200 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/StringLiteralNode.java Mon Oct 14 15:51:57 2013 +0200 @@ -22,9 +22,9 @@ */ package com.oracle.truffle.sl.nodes; -import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.frame.*; -public abstract class StringLiteralNode extends TypedNode { +public final class StringLiteralNode extends TypedNode { private final String value; @@ -32,8 +32,14 @@ this.value = value; } - @Specialization - protected String doString() { + @Override + public String executeString(VirtualFrame frame) { return value; } + + @Override + public Object executeGeneric(VirtualFrame frame) { + return value; + } + }