# HG changeset patch # User Christian Humer # Date 1375701606 -7200 # Node ID 1e6d5dec4a4e05bb754b30d2c1a48efd75cfacb0 # Parent 3479ab380552c352b6733e0baaf7456ec70f4ed3# Parent d0aeaf72c7bdf70cffb9bd67119d8aeb12bd3685 Merge. diff -r d0aeaf72c7bd -r 1e6d5dec4a4e graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/CodeFormatTest.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/CodeFormatTest.java Mon Aug 05 13:20:06 2013 +0200 @@ -0,0 +1,61 @@ +/* + * 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.dsl.test; + +import org.junit.*; + +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.dsl.test.CodeFormatTestFactory.LineWrappingTestFactory; +import com.oracle.truffle.api.dsl.test.TypeSystemTest.ValueNode; + +public class CodeFormatTest { + + @Test + public void test() { + Assert.assertEquals(42, TestHelper.createCallTarget(LineWrappingTestFactory.create()).call()); + } + + abstract static class LineWrappingTest extends ValueNode { + + public LineWrappingTest() { + } + + protected static boolean guardWithaReeeeeeeeaaaaaaaaaaalllllllllyyyyyyyyLLLLLLLLLLLLLoooooooonnnnnnngggggggName1() { + return true; + } + + protected static boolean guardWithaReeeeeeeeaaaaaaaaaaalllllllllyyyyyyyyLLLLLLLLLLLLLoooooooonnnnnnngggggggName2() { + return true; + } + + @Specialization(guards = {"guardWithaReeeeeeeeaaaaaaaaaaalllllllllyyyyyyyyLLLLLLLLLLLLLoooooooonnnnnnngggggggName1", + "guardWithaReeeeeeeeaaaaaaaaaaalllllllllyyyyyyyyLLLLLLLLLLLLLoooooooonnnnnnngggggggName2", + "guardWithaReeeeeeeeaaaaaaaaaaalllllllllyyyyyyyyLLLLLLLLLLLLLoooooooonnnnnnngggggggName1", + "guardWithaReeeeeeeeaaaaaaaaaaalllllllllyyyyyyyyLLLLLLLLLLLLLoooooooonnnnnnngggggggName2", + "guardWithaReeeeeeeeaaaaaaaaaaalllllllllyyyyyyyyLLLLLLLLLLLLLoooooooonnnnnnngggggggName1"}) + public int execute() { + return 42; + } + } + +} diff -r d0aeaf72c7bd -r 1e6d5dec4a4e graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/NegatedGuardsTest.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/NegatedGuardsTest.java Mon Aug 05 13:20:06 2013 +0200 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2012, 2013, 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 static com.oracle.truffle.api.dsl.test.TestHelper.*; + +import org.junit.*; + +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.dsl.test.NegatedGuardsTestFactory.NegatedGuardNodeFactory; +import com.oracle.truffle.api.dsl.test.TypeSystemTest.TestRootNode; +import com.oracle.truffle.api.dsl.test.TypeSystemTest.ValueNode; + +public class NegatedGuardsTest { + + @Test + public void testGuardGlobal() { + TestRootNode root = createRoot(NegatedGuardNodeFactory.getInstance()); + Assert.assertEquals(42, executeWith(root)); + } + + abstract static class NegatedGuardNode extends ValueNode { + + static boolean guard() { + return true; + } + + @Specialization(order = 1, guards = "!guard") + int do1() { + throw new AssertionError(); + } + + @Specialization(order = 2) + int do2() { + return 42; // the generic answer to all questions + } + } +} diff -r d0aeaf72c7bd -r 1e6d5dec4a4e graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/NodeChildNoNameTest.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/NodeChildNoNameTest.java Mon Aug 05 13:20:06 2013 +0200 @@ -0,0 +1,114 @@ +/* + * 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.dsl.*; +import com.oracle.truffle.api.dsl.test.NodeChildNoNameTestFactory.OneArgNoNameFactory; +import com.oracle.truffle.api.dsl.test.NodeChildNoNameTestFactory.ThreeArgsNoNameFactory; +import com.oracle.truffle.api.dsl.test.NodeChildNoNameTestFactory.TwoArgsNoNameFactory; +import com.oracle.truffle.api.dsl.test.TypeSystemTest.ValueNode; +import com.oracle.truffle.api.frame.*; + +public class NodeChildNoNameTest { + + @Test + public void testOneArg() { + ValueNode node = new ConstantNode(); + OneArgNoName arg = OneArgNoNameFactory.create(node); + Assert.assertEquals(node, arg.getChild0()); + Assert.assertEquals(43, TestHelper.createCallTarget(arg).call()); + } + + @Test + public void testTwoArg() { + ValueNode node1 = new ConstantNode(); + ValueNode node2 = new ConstantNode(); + TwoArgsNoName arg = TwoArgsNoNameFactory.create(node1, node2); + Assert.assertEquals(node1, arg.getChild0()); + Assert.assertEquals(node2, arg.getChild1()); + Assert.assertEquals(84, TestHelper.createCallTarget(arg).call()); + } + + @Test + public void testThreeArg() { + ValueNode node1 = new ConstantNode(); + ValueNode node2 = new ConstantNode(); + ValueNode node3 = new ConstantNode(); + ThreeArgsNoName arg = ThreeArgsNoNameFactory.create(node1, node2, node3); + Assert.assertEquals(node1, arg.getChild0()); + Assert.assertEquals(node2, arg.getChild1()); + Assert.assertEquals(node3, arg.getChild2()); + Assert.assertEquals(126, TestHelper.createCallTarget(arg).call()); + } + + private static class ConstantNode extends ValueNode { + + @Override + public Object execute(VirtualFrame frame) { + return 42; + } + } + + @NodeChild + abstract static class OneArgNoName extends ValueNode { + + public abstract ValueNode getChild0(); + + @Specialization + int doIt(int exp) { + return exp + 1; + } + + } + + @NodeChildren({@NodeChild, @NodeChild}) + abstract static class TwoArgsNoName extends ValueNode { + + public abstract ValueNode getChild0(); + + public abstract ValueNode getChild1(); + + @Specialization + int doIt(int exp0, int exp1) { + return exp0 + exp1; + } + } + + @NodeChildren({@NodeChild, @NodeChild, @NodeChild}) + abstract static class ThreeArgsNoName extends ValueNode { + + public abstract ValueNode getChild0(); + + public abstract ValueNode getChild1(); + + public abstract ValueNode getChild2(); + + @Specialization + int doIt(int exp0, int exp1, int exp2) { + return exp0 + exp1 + exp2; + } + } + +} diff -r d0aeaf72c7bd -r 1e6d5dec4a4e graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/NodeContainerTest.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/NodeContainerTest.java Mon Aug 05 11:25:14 2013 +0200 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/NodeContainerTest.java Mon Aug 05 13:20:06 2013 +0200 @@ -162,21 +162,10 @@ } @NodeChild(value = "children", type = ValueNode[].class) + @NodeField(name = "context", type = Context.class) abstract static class BuiltinNode extends ValueNode { - protected final Context context; - - public BuiltinNode(BuiltinNode node) { - this(node.context); - } - - public BuiltinNode(Context context) { - this.context = context; - } - - public Context getContext() { - return context; - } + public abstract Context getContext(); } static class Context { diff -r d0aeaf72c7bd -r 1e6d5dec4a4e graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/NodeFieldTest.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/NodeFieldTest.java Mon Aug 05 13:20:06 2013 +0200 @@ -0,0 +1,149 @@ +/* + * 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 static com.oracle.truffle.api.dsl.test.TestHelper.*; +import static org.junit.Assert.*; + +import org.junit.*; + +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.dsl.test.NodeFieldTestFactory.*; +import com.oracle.truffle.api.dsl.test.NodeFieldTestFactory.TestContainerFactory.TestContainerContainerFieldFactory; +import com.oracle.truffle.api.dsl.test.TypeSystemTest.ValueNode; + +public class NodeFieldTest { + + @Test + public void testIntField() { + assertEquals(42, createCallTarget(IntFieldTestNodeFactory.create(42)).call()); + } + + @NodeField(name = "field", type = int.class) + abstract static class IntFieldTestNode extends ValueNode { + + public abstract int getField(); + + @Specialization + int intField() { + return getField(); + } + + } + + @Test + public void testIntFieldNoGetter() { + assertEquals(42, createCallTarget(IntFieldNoGetterTestNodeFactory.create(42)).call()); + } + + @NodeField(name = "field", type = int.class) + abstract static class IntFieldNoGetterTestNode extends ValueNode { + + @Specialization + int intField(int field) { + return field; + } + + } + + @Test + public void testMultipleFields() { + assertEquals(42, createCallTarget(MultipleFieldsTestNodeFactory.create(21, 21)).call()); + } + + @NodeFields({@NodeField(name = "field0", type = int.class), @NodeField(name = "field1", type = int.class)}) + abstract static class MultipleFieldsTestNode extends ValueNode { + + public abstract int getField0(); + + public abstract int getField1(); + + @Specialization + int intField() { + return getField0() + getField1(); + } + + } + + @Test + public void testStringField() { + assertEquals("42", createCallTarget(StringFieldTestNodeFactory.create("42")).call()); + } + + @NodeField(name = "field", type = String.class) + abstract static class StringFieldTestNode extends ValueNode { + + public abstract String getField(); + + @Specialization + String stringField() { + return getField(); + } + + } + + @Test + public void testRewrite() { + assertEquals("42", createCallTarget(RewriteTestNodeFactory.create("42")).call()); + } + + @NodeField(name = "field", type = String.class) + abstract static class RewriteTestNode extends ValueNode { + + public abstract String getField(); + + @Specialization(order = 1, rewriteOn = RuntimeException.class) + String alwaysRewrite() { + throw new RuntimeException(); + } + + @Specialization(order = 2) + String returnField() { + return getField(); + } + } + + @Test + public void testStringContainer() { + assertEquals(42, createCallTarget(TestContainerContainerFieldFactory.create(42, "42")).call()); + } + + @NodeField(name = "field", type = int.class) + abstract static class IntContainerNode extends ValueNode { + + public abstract int getField(); + + } + + @NodeContainer(IntContainerNode.class) + @NodeField(name = "anotherField", type = String.class) + abstract static class TestContainer { + + @Specialization + static int containerField(int field, String anotherField) { + return anotherField.equals("42") ? field : -1; + } + + } + +} diff -r d0aeaf72c7bd -r 1e6d5dec4a4e graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/SpecializationGroupingTest.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/SpecializationGroupingTest.java Mon Aug 05 13:20:06 2013 +0200 @@ -0,0 +1,189 @@ +/* + * 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.*; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.dsl.test.SpecializationGroupingTestFactory.TestGroupingFactory; +import com.oracle.truffle.api.dsl.test.TypeSystemTest.SimpleTypes; +import com.oracle.truffle.api.dsl.test.TypeSystemTest.TestRootNode; +import com.oracle.truffle.api.dsl.test.TypeSystemTest.ValueNode; +import com.oracle.truffle.api.nodes.*; + +/** + * 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. + */ +public class SpecializationGroupingTest { + + @Test + public void testGrouping() { + MockAssumption a1 = new MockAssumption(true); + MockAssumption a2 = new MockAssumption(false); + MockAssumption a3 = new MockAssumption(true); + + TestRootNode root = TestHelper.createRoot(TestGroupingFactory.getInstance(), a1, a2, a3); + + SimpleTypes.intCast = 0; + SimpleTypes.intCheck = 0; + TestGrouping.true1 = 0; + TestGrouping.false1 = 0; + TestGrouping.true2 = 0; + TestGrouping.false2 = 0; + TestGrouping.true3 = 0; + + Assert.assertEquals(42, TestHelper.executeWith(root, 21, 21)); + Assert.assertEquals(1, TestGrouping.true1); + Assert.assertEquals(1, TestGrouping.false1); + Assert.assertEquals(1, TestGrouping.true2); + Assert.assertEquals(1, TestGrouping.false2); + Assert.assertEquals(1, TestGrouping.true3); + Assert.assertEquals(2, SimpleTypes.intCheck); + Assert.assertEquals(2, SimpleTypes.intCast); + Assert.assertEquals(1, a1.checked); + Assert.assertEquals(1, a2.checked); + Assert.assertEquals(1, a3.checked); + + Assert.assertEquals(42, TestHelper.executeWith(root, 21, 21)); + Assert.assertEquals(2, TestGrouping.true1); + Assert.assertEquals(1, 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, a3.checked); + Assert.assertEquals(2, SimpleTypes.intCheck); + Assert.assertEquals(2, SimpleTypes.intCast); + + } + + @SuppressWarnings("unused") + @NodeChildren({@NodeChild, @NodeChild}) + @NodeAssumptions({"a1", "a2", "a3"}) + public abstract static class TestGrouping extends ValueNode { + + private static int true1; + private static int false1; + private static int true2; + private static int false2; + private static int true3; + + protected boolean true1(int value) { + true1++; + return true; + } + + protected boolean false1(int value, int value2) { + false1++; + return false; + } + + protected boolean true2(int value) { + true2++; + return true; + } + + protected boolean false2(int value) { + false2++; + return false; + } + + protected boolean true3(int value) { + true3++; + return true; + } + + @Specialization(order = 1) + public int fail(int value1, String value2) { + throw new AssertionError(); + } + + @Specialization(order = 2, guards = {"true1", "false1"}) + public int fail1(int value1, int value2) { + throw new AssertionError(); + } + + @Specialization(order = 3, guards = {"true1", "true2"}, assumptions = {"a1", "a2"}) + public int fail2(int value1, int value2) { + throw new AssertionError(); + } + + @Specialization(order = 4, guards = {"true1", "true2"}, assumptions = {"a1", "a3"}, rewriteOn = RuntimeException.class) + public int throwRewrite(int value1, int value2) { + throw new RuntimeException(); + } + + @Specialization(order = 5, guards = {"true1", "true2", "false2"}, assumptions = {"a1", "a3"}) + public int fail4(int value1, int value2) { + throw new AssertionError(); + } + + @Specialization(order = 6, guards = {"true1", "true2", "!false2", "!true3"}, assumptions = {"a1", "a3"}) + public int fail5(int value1, int value2) { + throw new AssertionError(); + } + + @Specialization(order = 7, guards = {"true1", "true2", "!false2", "true3"}, assumptions = {"a1", "a3"}) + public int success(int value1, int value2) { + return value1 + value2; + } + + } + + private static class MockAssumption implements Assumption { + + int checked; + + private final boolean valid; + + public MockAssumption(boolean valid) { + this.valid = valid; + } + + public void check() throws InvalidAssumptionException { + checked++; + if (!valid) { + throw new InvalidAssumptionException(); + } + } + + public boolean isValid() { + checked++; + return valid; + } + + public void invalidate() { + throw new UnsupportedOperationException(); + } + + public String getName() { + throw new UnsupportedOperationException(); + } + + } + +} diff -r d0aeaf72c7bd -r 1e6d5dec4a4e 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 Aug 05 11:25:14 2013 +0200 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TestHelper.java Mon Aug 05 13:20:06 2013 +0200 @@ -50,12 +50,12 @@ ArgumentNode[] argumentNodes = arguments(factory.getExecutionSignature().size()); List argumentList = new ArrayList<>(); - argumentList.addAll(Arrays.asList(constants)); if (ChildrenNode.class.isAssignableFrom(factory.getNodeClass()) || BuiltinNode.class.isAssignableFrom(factory.getNodeClass())) { argumentList.add(argumentNodes); } else { argumentList.addAll(Arrays.asList(argumentNodes)); } + argumentList.addAll(Arrays.asList(constants)); return factory.createNode(argumentList.toArray(new Object[argumentList.size()])); } diff -r d0aeaf72c7bd -r 1e6d5dec4a4e graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TypeSystemTest.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TypeSystemTest.java Mon Aug 05 11:25:14 2013 +0200 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TypeSystemTest.java Mon Aug 05 13:20:06 2013 +0200 @@ -32,6 +32,22 @@ @TypeSystem({int.class, boolean.class, String.class, Str.class, CallTarget.class, Object[].class}) static class SimpleTypes { + + static int intCheck; + static int intCast; + + @TypeCheck + public boolean isInteger(Object value) { + intCheck++; + return value instanceof Integer; + } + + @TypeCast + public int asInteger(Object value) { + intCast++; + return (int) value; + } + } @TypeSystemReference(SimpleTypes.class) @@ -126,6 +142,16 @@ return frame.getArguments(TestArguments.class).get(index); } + @Override + public int executeInt(VirtualFrame frame) throws UnexpectedResultException { + // avoid casts for some tests + Object o = frame.getArguments(TestArguments.class).get(index); + if (o instanceof Integer) { + return (int) o; + } + throw new UnexpectedResultException(o); + } + } } diff -r d0aeaf72c7bd -r 1e6d5dec4a4e graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/NodeField.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/NodeField.java Mon Aug 05 13:20:06 2013 +0200 @@ -0,0 +1,43 @@ +/* + * 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; + +import java.lang.annotation.*; + +import com.oracle.truffle.api.nodes.*; + +/** + * A {@link NodeField} element defines a field for the generated {@link Node}. A {@link Node} + * contains multiple {@link NodeFields} specified in linear declaration order. The field can be + * accessed by declaring an abstract getter named + * "get" + firstLetterUpperCase({@link #name()})(). + */ +@Retention(RetentionPolicy.CLASS) +@Target({ElementType.TYPE}) +public @interface NodeField { + + String name(); + + Class type(); + +} diff -r d0aeaf72c7bd -r 1e6d5dec4a4e graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/NodeFields.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/NodeFields.java Mon Aug 05 13:20:06 2013 +0200 @@ -0,0 +1,41 @@ +/* + * 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; + +import java.lang.annotation.*; + +import com.oracle.truffle.api.nodes.*; + +/** + * A {@link NodeFields} element defines a field for the generated {@link Node}. A {@link Node} + * contains multiple {@link NodeFields} specified in linear declaration order. The field can be + * accessed by declaring an abstract getter named + * "get" + firstLetterUpperCase({@link #value()})(). + */ +@Retention(RetentionPolicy.CLASS) +@Target({ElementType.TYPE}) +public @interface NodeFields { + + NodeField[] value() default {}; + +} diff -r d0aeaf72c7bd -r 1e6d5dec4a4e graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/Specialization.java --- a/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/Specialization.java Mon Aug 05 11:25:14 2013 +0200 +++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/Specialization.java Mon Aug 05 13:20:06 2013 +0200 @@ -38,8 +38,10 @@ /** * Defines the assumptions to check for this specialization. When the specialization method is - * invoked it is guaranteed that the assigned assumptions still hold. To declare assumptions use - * the {@link NodeAssumptions} annotation at class level. + * invoked it is guaranteed that these assumptions still hold. It is not guaranteed that they + * are checked before the {@link #guards()} methods. They may be checked before after or in + * between {@link #guards()}. To declare assumptions use the {@link NodeAssumptions} annotation + * at class level. */ String[] assumptions() default {}; diff -r d0aeaf72c7bd -r 1e6d5dec4a4e graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeTreeBuilder.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeTreeBuilder.java Mon Aug 05 11:25:14 2013 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeTreeBuilder.java Mon Aug 05 13:20:06 2013 +0200 @@ -97,6 +97,9 @@ private CodeTreeBuilder push(BuilderCodeTree tree) { if (currentElement != null) { + if (!removeLastIfEnqueued(tree)) { + return this; + } currentElement.add(tree); } switch (tree.getCodeKind()) { @@ -110,9 +113,30 @@ return this; } + private boolean removeLastIfEnqueued(BuilderCodeTree tree) { + if (tree.getCodeKind() == REMOVE_LAST) { + return !clearLastRec(tree.removeLast, currentElement.getEnclosedElements()); + } + List childTree = tree.getEnclosedElements(); + if (!childTree.isEmpty()) { + CodeTree last = childTree.get(0); + if (last instanceof BuilderCodeTree) { + if (!removeLastIfEnqueued((BuilderCodeTree) last)) { + childTree.remove(0); + } + } + } + return true; + } + private void clearLast(CodeTreeKind kind) { if (clearLastRec(kind, currentElement.getEnclosedElements())) { treeCount--; + } else { + // delay clearing the last + BuilderCodeTree tree = new BuilderCodeTree(REMOVE_LAST, null, null); + tree.removeLast = kind; + push(tree); } } @@ -299,6 +323,15 @@ return startGroup().string("while ").startParanthesesCommaGroup().endAndWhitespaceAfter().startGroup().endAfter(); } + public CodeTreeBuilder startDoBlock() { + return startGroup().string("do ").startBlock(); + } + + public CodeTreeBuilder startDoWhile() { + clearLast(CodeTreeKind.NEW_LINE); + return startStatement().string(" while ").startParanthesesCommaGroup().endAfter().startGroup().endAfter(); + } + public CodeTreeBuilder startIf() { return startGroup().string("if ").startParanthesesCommaGroup().endAndWhitespaceAfter().startGroup().endAfter(); } @@ -480,6 +513,23 @@ return declaration(type, name, singleString(init)); } + public CodeTreeBuilder declaration(String type, String name, CodeTree init) { + startStatement(); + string(type); + string(" "); + string(name); + if (init != null) { + string(" = "); + tree(init); + } + end(); // statement + return this; + } + + public CodeTreeBuilder declaration(String type, String name, String init) { + return declaration(type, name, singleString(init)); + } + public CodeTreeBuilder declaration(TypeMirror type, String name, CodeTree init) { if (Utils.isVoid(type)) { startStatement(); @@ -506,6 +556,13 @@ return declaration(type, name, init.getTree()); } + public CodeTreeBuilder declaration(String type, String name, CodeTreeBuilder init) { + if (init == this) { + throw new IllegalArgumentException("Recursive builder usage."); + } + return declaration(type, name, init.getTree()); + } + public CodeTreeBuilder declaration(TypeMirror type, String name) { return declaration(type, name, (CodeTree) null); } @@ -680,6 +737,7 @@ private static class BuilderCodeTree extends CodeTree { private EndCallback atEndListener; + private CodeTreeKind removeLast; public BuilderCodeTree(CodeTreeKind kind, TypeMirror type, String string) { super(kind, type, string); diff -r d0aeaf72c7bd -r 1e6d5dec4a4e graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeTreeKind.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeTreeKind.java Mon Aug 05 11:25:14 2013 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeTreeKind.java Mon Aug 05 13:20:06 2013 +0200 @@ -23,5 +23,5 @@ package com.oracle.truffle.dsl.processor.ast; public enum CodeTreeKind { - STATIC_FIELD_REFERENCE, STATIC_METHOD_REFERENCE, GROUP, COMMA_GROUP, INDENT, STRING, NEW_LINE, TYPE; + STATIC_FIELD_REFERENCE, STATIC_METHOD_REFERENCE, GROUP, COMMA_GROUP, REMOVE_LAST, INDENT, STRING, NEW_LINE, TYPE; } diff -r d0aeaf72c7bd -r 1e6d5dec4a4e graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/codewriter/AbstractCodeWriter.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/codewriter/AbstractCodeWriter.java Mon Aug 05 11:25:14 2013 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/codewriter/AbstractCodeWriter.java Mon Aug 05 13:20:06 2013 +0200 @@ -36,7 +36,7 @@ public abstract class AbstractCodeWriter extends CodeElementScanner { - private static final int LINE_LENGTH = 200; + private static final int MAX_LINE_LENGTH = 200; private static final int LINE_WRAP_INDENTS = 3; private static final String IDENT_STRING = " "; private static final String LN = "\n"; /* unix style */ @@ -622,38 +622,79 @@ } private AbstractCodeWriter write(String m) { + if (m.isEmpty()) { + return this; + } try { - lineLength += m.length(); - if (newLine && m != LN) { + String s = m; + lineLength += s.length(); + if (newLine && s != LN) { writeIndent(); newLine = false; } - if (lineLength > LINE_LENGTH && m.length() > 0) { - char firstChar = m.charAt(0); - if (Character.isAlphabetic(firstChar)) { - if (!lineWrapping) { - indent(LINE_WRAP_INDENTS); - } - lineWrapping = true; - lineLength = 0; - write(LN); - writeIndent(); - } + if (lineLength > MAX_LINE_LENGTH) { + s = wrapLine(s); } - writer.write(m); + writer.write(s); } catch (IOException e) { throw new RuntimeException(e); } return this; } + private String wrapLine(String m) throws IOException { + assert !m.isEmpty(); + + char firstCharacter = m.charAt(0); + char lastCharacter = m.charAt(m.length() - 1); + if (firstCharacter == '\"' && lastCharacter == '\"') { + // string line wrapping + String string = m.substring(1, m.length() - 1); + if (string.isEmpty()) { + return m; + } + + // restore original line length + lineLength = lineLength - m.length(); + int size = 0; + for (int i = 0; i < string.length(); i += size) { + if (i != 0) { + write("+ "); + } + int nextSize = MAX_LINE_LENGTH - lineLength - 2; + int end = Math.min(i + nextSize, string.length()); + + assert lineLength + (end - i) + 2 < MAX_LINE_LENGTH; + write("\"" + string.substring(i, end) + "\""); + size = nextSize; + } + + return ""; + } else if (!Character.isAlphabetic(firstCharacter) && firstCharacter != '+') { + return m; + } + + if (!lineWrapping) { + indent(LINE_WRAP_INDENTS); + } + lineWrapping = true; + lineLength = 0; + write(LN); + writeIndent(); + return m; + } + private void writeIndent() throws IOException { + lineLength += indentSize(); for (int i = 0; i < indent; i++) { - lineLength += IDENT_STRING.length(); writer.write(IDENT_STRING); } } + private int indentSize() { + return IDENT_STRING.length() * indent; + } + private static class TrimTrailingSpaceWriter extends Writer { private final Writer delegate; diff -r d0aeaf72c7bd -r 1e6d5dec4a4e graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/compiler/Compiler.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/compiler/Compiler.java Mon Aug 05 11:25:14 2013 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/compiler/Compiler.java Mon Aug 05 13:20:06 2013 +0200 @@ -22,6 +22,8 @@ */ package com.oracle.truffle.dsl.processor.compiler; +import java.util.*; + import javax.annotation.processing.*; import javax.lang.model.element.*; @@ -31,4 +33,6 @@ String getHeaderComment(ProcessingEnvironment env, Element type); + List getEnclosedElementsDeclarationOrder(TypeElement type); + } diff -r d0aeaf72c7bd -r 1e6d5dec4a4e graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/compiler/JDTCompiler.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/compiler/JDTCompiler.java Mon Aug 05 11:25:14 2013 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/compiler/JDTCompiler.java Mon Aug 05 13:20:06 2013 +0200 @@ -22,6 +22,8 @@ */ package com.oracle.truffle.dsl.processor.compiler; +import java.util.*; + import javax.annotation.processing.*; import javax.lang.model.element.*; @@ -38,6 +40,65 @@ } } + public List getEnclosedElementsDeclarationOrder(TypeElement type) { + try { + Object binding = field(type, "_binding"); + + Class sourceTypeBinding = Class.forName("org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding"); + + final List declarationOrder; + if (sourceTypeBinding.isAssignableFrom(binding.getClass())) { + declarationOrder = findSourceOrder(binding); + } else { + return null; + } + + List enclosedElements = new ArrayList<>(type.getEnclosedElements()); + Collections.sort(enclosedElements, new Comparator() { + + public int compare(Element o1, Element o2) { + try { + Object o1Binding = field(o1, "_binding"); + Object o2Binding = field(o2, "_binding"); + + int i1 = declarationOrder.indexOf(o1Binding); + int i2 = declarationOrder.indexOf(o2Binding); + + return i1 - i2; + } catch (Exception e) { + return 0; + } + } + + }); + return enclosedElements; + } catch (Exception e) { + return null; + } + } + + private static List findSourceOrder(Object binding) throws Exception { + Object referenceContext = field(field(binding, "scope"), "referenceContext"); + + TreeMap orderedBindings = new TreeMap<>(); + + collectSourceOrder(orderedBindings, referenceContext, "methods"); + collectSourceOrder(orderedBindings, referenceContext, "fields"); + collectSourceOrder(orderedBindings, referenceContext, "memberTypes"); + + return new ArrayList<>(orderedBindings.values()); + } + + private static void collectSourceOrder(TreeMap orderedBindings, Object referenceContext, String fieldName) throws Exception { + Object[] declarations = (Object[]) field(referenceContext, fieldName); + if (declarations != null) { + for (int i = 0; i < declarations.length; i++) { + Integer declarationSourceStart = (Integer) field(declarations[i], "declarationSourceStart"); + orderedBindings.put(declarationSourceStart, field(declarations[i], "binding")); + } + } + } + @Override public String getMethodBody(ProcessingEnvironment env, ExecutableElement method) { try { diff -r d0aeaf72c7bd -r 1e6d5dec4a4e graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/compiler/JavaCCompiler.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/compiler/JavaCCompiler.java Mon Aug 05 11:25:14 2013 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/compiler/JavaCCompiler.java Mon Aug 05 13:20:06 2013 +0200 @@ -22,6 +22,8 @@ */ package com.oracle.truffle.dsl.processor.compiler; +import java.util.*; + import javax.annotation.processing.*; import javax.lang.model.element.*; @@ -38,6 +40,10 @@ } } + public List getEnclosedElementsDeclarationOrder(TypeElement type) { + return type.getEnclosedElements(); + } + private static final Class[] getTreeAndTopLevelSignature = new Class[]{Element.class, AnnotationMirror.class, AnnotationValue.class}; private static final Class[] getCharContentSignature = new Class[]{boolean.class}; diff -r d0aeaf72c7bd -r 1e6d5dec4a4e graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/CreateCastParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/CreateCastParser.java Mon Aug 05 11:25:14 2013 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/CreateCastParser.java Mon Aug 05 13:20:06 2013 +0200 @@ -55,7 +55,7 @@ } } MethodSpec spec = new MethodSpec(new InheritsParameterSpec(getContext(), "child", baseType)); - addDefaultFieldMethodSpec(method, spec); + addDefaultFieldMethodSpec(spec); spec.addRequired(new ParameterSpec("castedChild", baseType)).setSignature(true); return spec; } diff -r d0aeaf72c7bd -r 1e6d5dec4a4e graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/ExecutableTypeMethodParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/ExecutableTypeMethodParser.java Mon Aug 05 11:25:14 2013 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/ExecutableTypeMethodParser.java Mon Aug 05 13:20:06 2013 +0200 @@ -73,6 +73,9 @@ @Override protected List nodeTypeMirrors(NodeData nodeData) { // executable types not yet available + if (nodeData.getTypeSystem() == null) { + return Collections.emptyList(); + } List types = new ArrayList<>(nodeData.getTypeSystem().getPrimitiveTypeMirrors()); types.add(nodeData.getTypeSystem().getVoidType().getPrimitiveType()); return types; diff -r d0aeaf72c7bd -r 1e6d5dec4a4e 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 Aug 05 11:25:14 2013 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java Mon Aug 05 13:20:06 2013 +0200 @@ -32,14 +32,14 @@ import javax.lang.model.util.*; import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.nodes.NodeInfo.Kind; import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.api.nodes.NodeInfo.Kind; import com.oracle.truffle.dsl.processor.*; import com.oracle.truffle.dsl.processor.ast.*; import com.oracle.truffle.dsl.processor.node.NodeChildData.Cardinality; import com.oracle.truffle.dsl.processor.node.NodeChildData.ExecutionKind; import com.oracle.truffle.dsl.processor.template.*; -import com.oracle.truffle.dsl.processor.template.TemplateMethod.*; +import com.oracle.truffle.dsl.processor.template.TemplateMethod.Signature; import com.oracle.truffle.dsl.processor.typesystem.*; public class NodeCodeGenerator extends CompilationUnitFactory { @@ -407,6 +407,9 @@ // Explicitly specified guards for (GuardData guard : guardedSpecialization.getGuards()) { builder.string(andOperator); + if (guard.isNegated()) { + builder.string("!"); + } builder.tree(createTemplateMethodCall(parent, null, valueSpecialization, guard, null)); andOperator = " && "; } @@ -437,7 +440,7 @@ continue; } - CodeTree cast = createCast(parent, field, valueParam, guardedParam); + CodeTree cast = createCast(parent, field, valueParam, guardedParam.getTypeSystemType()); if (cast == null) { continue; } @@ -476,7 +479,7 @@ valueParam = guardedParam; } - CodeTree implicitGuard = createImplicitGuard(builder, field, valueParam, guardedParam); + CodeTree implicitGuard = createTypeGuard(builder, field, valueParam, guardedParam.getTypeSystemType()); if (implicitGuard == null) { continue; } @@ -489,11 +492,11 @@ return builder.isEmpty() ? null : builder.getRoot(); } - private CodeTree createImplicitGuard(CodeTreeBuilder parent, NodeChildData field, ActualParameter source, ActualParameter target) { + private CodeTree createTypeGuard(CodeTreeBuilder parent, NodeChildData field, ActualParameter source, TypeData targetType) { NodeData node = field.getNodeData(); + CodeTreeBuilder builder = new CodeTreeBuilder(parent); - TypeData targetType = target.getTypeSystemType(); TypeData sourceType = source.getTypeSystemType(); if (!sourceType.needsCastTo(getContext(), targetType)) { @@ -503,14 +506,14 @@ builder.startGroup(); if (field.isShortCircuit()) { - ActualParameter shortCircuit = target.getPreviousParameter(); + ActualParameter shortCircuit = source.getPreviousParameter(); assert shortCircuit != null; builder.string("("); builder.string("!").string(valueName(shortCircuit)); builder.string(" || "); } - startCallTypeSystemMethod(getContext(), builder, node, TypeSystemCodeGenerator.isTypeMethodName(target.getTypeSystemType())); + startCallTypeSystemMethod(getContext(), builder, node, TypeSystemCodeGenerator.isTypeMethodName(targetType)); builder.string(valueName(source)); builder.end().end(); // call @@ -523,10 +526,9 @@ return builder.getRoot(); } - private CodeTree createCast(CodeTreeBuilder parent, NodeChildData field, ActualParameter source, ActualParameter target) { + private CodeTree createCast(CodeTreeBuilder parent, NodeChildData field, ActualParameter source, TypeData targetType) { NodeData node = field.getNodeData(); TypeData sourceType = source.getTypeSystemType(); - TypeData targetType = target.getTypeSystemType(); if (!sourceType.needsCastTo(getContext(), targetType)) { return null; @@ -534,14 +536,14 @@ CodeTree condition = null; if (field.isShortCircuit()) { - ActualParameter shortCircuit = target.getPreviousParameter(); + ActualParameter shortCircuit = source.getPreviousParameter(); assert shortCircuit != null; condition = CodeTreeBuilder.singleString(valueName(shortCircuit)); } - CodeTree value = createCallTypeSystemMethod(context, parent, node, TypeSystemCodeGenerator.asTypeMethodName(targetType), CodeTreeBuilder.singleString(valueName(target))); - - return createLazyAssignment(parent, castValueName(target), target.getType(), condition, value); + CodeTree value = createCallTypeSystemMethod(context, parent, node, TypeSystemCodeGenerator.asTypeMethodName(targetType), CodeTreeBuilder.singleString(valueName(source))); + + return createLazyAssignment(parent, castValueName(source), targetType.getPrimitiveType(), condition, value); } /** @@ -623,12 +625,22 @@ return false; } VariableElement var = element.getParameters().get(0); - TypeElement type = Utils.findNearestEnclosingType(var); - - if (!Utils.typeEquals(var.asType(), type.asType())) { - return false; + TypeElement enclosingType = Utils.findNearestEnclosingType(var); + if (Utils.typeEquals(var.asType(), enclosingType.asType())) { + return true; } - return true; + List types = Utils.getDirectSuperTypes(enclosingType); + for (TypeElement type : types) { + if (!(type instanceof CodeTypeElement)) { + // no copy constructors which are not generated types + return false; + } + + if (Utils.typeEquals(var.asType(), type.asType())) { + return true; + } + } + return false; } @Override @@ -686,7 +698,7 @@ createFactoryMethods(node, clazz, createVisibility); - if (node.getPolymorphicDepth() > 1) { + if (node.isPolymorphic()) { PolymorphicNodeFactory generic = new PolymorphicNodeFactory(getContext(), generatedNode, true); add(generic, node.getGenericPolymorphicSpecialization()); @@ -1063,6 +1075,20 @@ } } + for (NodeFieldData field : node.getFields()) { + if (!field.isGenerated()) { + continue; + } + + clazz.add(new CodeVariableElement(modifiers(PROTECTED, FINAL), field.getType(), field.getName())); + if (field.getGetter() != null && field.getGetter().getModifiers().contains(Modifier.ABSTRACT)) { + CodeExecutableElement method = CodeExecutableElement.clone(getContext().getEnvironment(), field.getGetter()); + method.getModifiers().remove(Modifier.ABSTRACT); + method.createBuilder().startReturn().string("this.").string(field.getName()).end(); + clazz.add(method); + } + } + for (String assumption : node.getAssumptions()) { clazz.add(createAssumptionField(assumption)); } @@ -1079,7 +1105,7 @@ if (node.needsRewrites(context)) { - if (node.getPolymorphicDepth() > 1) { + if (node.isPolymorphic()) { CodeVariableElement var = new CodeVariableElement(modifiers(PROTECTED), clazz.asType(), "next0"); var.getAnnotationMirrors().add(new CodeAnnotationMirror(getContext().getTruffleTypes().getChildAnnotation())); @@ -1093,8 +1119,6 @@ createIsCompatible(clazz, null); - clazz.add(createCreateSpecialization(node)); - CodeExecutableElement genericCachedExecute = createCachedExecute(node, node.getGenericPolymorphicSpecialization(), null); clazz.add(genericCachedExecute); for (SpecializationData polymorph : node.getPolymorphicSpecializations()) { @@ -1230,6 +1254,9 @@ ExecutableTypeData sourceExecutableType = node.findExecutableType(polymorph.getReturnType().getTypeSystemType(), 0); boolean sourceThrowsUnexpected = sourceExecutableType != null && sourceExecutableType.hasUnexpectedValue(getContext()); + if (sourceExecutableType.getType().equals(node.getGenericSpecialization().getReturnType().getTypeSystemType())) { + sourceThrowsUnexpected = false; + } if (sourceThrowsUnexpected) { cachedExecute.getThrownTypes().add(getContext().getType(UnexpectedResultException.class)); } @@ -1249,43 +1276,6 @@ } - private CodeExecutableElement createCreateSpecialization(NodeData node) { - CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE), getElement().asType(), "createSpezialization0"); - method.getParameters().add(new CodeVariableElement(context.getType(Class.class), "clazz")); - CodeTreeBuilder builder = method.createBuilder(); - - builder.startStatement().type(getElement().asType()).string(" node").end(); - - boolean elseIf = false; - for (SpecializationData specialization : node.getSpecializations()) { - if (specialization.isGeneric() || specialization.isUninitialized()) { - continue; - } - - elseIf = builder.startIf(elseIf); - builder.startGroup().string("clazz == ").string(nodeSpecializationClassName(specialization)).string(".class").end(); - builder.end(); - builder.startBlock(); - builder.startStatement(); - builder.string("node = "); - builder.startNew(nodeSpecializationClassName(specialization)).string("this").end(); - builder.end(); - builder.end(); - } - - builder.startElseBlock(); - builder.startThrow().startNew(context.getType(AssertionError.class)).end().end(); - builder.end(); - - builder.startStatement().startCall("node", "setNext0"); - builder.startNew(nodeSpecializationClassName(node.getUninitializedSpecialization())).string("this").end(); - builder.end().end(); - - builder.startReturn().string("node").end(); - - return method; - } - private void createConstructors(NodeData node, CodeTypeElement clazz) { List constructors = findUserConstructors(node.getNodeType()); if (constructors.isEmpty()) { @@ -1359,9 +1349,7 @@ private CodeExecutableElement createCopyConstructor(CodeTypeElement type, ExecutableElement superConstructor) { CodeExecutableElement method = new CodeExecutableElement(null, type.getSimpleName().toString()); CodeTreeBuilder builder = method.createBuilder(); - if (!(superConstructor == null && type.getFields().isEmpty())) { - method.getParameters().add(new CodeVariableElement(type.asType(), "copy")); - } + method.getParameters().add(new CodeVariableElement(type.asType(), "copy")); if (superConstructor != null) { builder.startStatement().startSuperCall().string("copy").end().end(); @@ -1398,7 +1386,7 @@ } builder.end(); } - if (getModel().getNode().getPolymorphicDepth() > 1) { + if (getModel().getNode().isPolymorphic()) { builder.statement("this.next0 = adoptChild(copy.next0)"); } @@ -1427,11 +1415,10 @@ return var; } - private CodeExecutableElement createGenericExecuteAndSpecialize(NodeData node) { - + private CodeExecutableElement createGenericExecuteAndSpecialize(final NodeData node) { TypeMirror genericReturnType = node.getGenericSpecialization().getReturnType().getType(); CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED), genericReturnType, EXECUTE_SPECIALIZE_NAME); - method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "minimumState")); + method.addParameter(new CodeVariableElement(getContext().getType(int.class), "minimumState")); addInternalValueParameters(method, node.getGenericSpecialization(), true, false); method.addParameter(new CodeVariableElement(getContext().getType(String.class), "reason")); @@ -1441,45 +1428,52 @@ builder.end(); emitSpecializationListeners(builder, node); - builder.defaultDeclaration(node.getGenericSpecialization().getReturnType().getTypeSystemType().getPrimitiveType(), "result"); - - builder.defaultDeclaration(getContext().getType(Class.class), "resultClass"); - - builder.startStatement().string("boolean allowed = (minimumState == ").string(nodeSpecializationClassName(node.getSpecializations().get(0))).string(".class)").end(); + + String currentNode = "this"; + for (SpecializationData specialization : node.getSpecializations()) { + if (!specialization.getExceptions().isEmpty()) { + currentNode = "current"; + builder.declaration(baseClassName(node), currentNode, "this"); + break; + } + } builder.startStatement().string("String message = ").startCall("createInfo0").string("reason"); addInternalValueParameterNames(builder, node.getGenericSpecialization(), node.getGenericSpecialization(), null, false, true); builder.end().end(); - String prefix = null; - List specializations = node.getSpecializations(); - - boolean firstUnreachable = true; - SpecializationData previous = null; + List filteredSpecializations = new ArrayList<>(); for (SpecializationData current : specializations) { - if (current.isUninitialized()) { + if (current.isUninitialized() || !current.isReachable()) { continue; } - - if (current.isReachable()) { - CodeTree execute = createGenericInvokeAndSpecialize(builder, node.getGenericSpecialization(), current); - - if (!current.isGeneric()) { - builder.startStatement().string("allowed = allowed || (minimumState == ").string(nodeSpecializationClassName(current)).string(".class)").end(); + filteredSpecializations.add(current); + } + + List groups = SpecializationGroup.create(filteredSpecializations); + + final String currentNodeVar = currentNode; + for (SpecializationGroup group : groups) { + builder.tree(createExecuteTree(builder, node.getGenericSpecialization(), group, true, new CodeBlock() { + + public CodeTree create(CodeTreeBuilder b, SpecializationData current) { + return createGenericInvokeAndSpecialize(b, node.getGenericSpecialization(), current, currentNodeVar); } - - builder.tree(createGuardAndCast(builder, prefix, current.getNode().getGenericSpecialization(), current, true, execute, null, true, false)); - } else { - if (firstUnreachable) { - if (previous != null && !previous.isGenericSpecialization(getContext()) && !previous.hasRewrite(getContext())) { - emitEncounteredSynthetic(builder, current); - } - firstUnreachable = false; - } - builder.string("// unreachable ").string(current.getId()).newLine(); + })); + } + + boolean firstUnreachable = true; + for (SpecializationData current : specializations) { + if (current.isUninitialized() || current.isReachable()) { + continue; } - previous = current; + if (firstUnreachable) { + emitEncounteredSynthetic(builder, current); + firstUnreachable = false; + } + + builder.string("// unreachable ").string(current.getId()).newLine(); } return method; @@ -1492,18 +1486,26 @@ method.getAnnotationMirrors().add(new CodeAnnotationMirror(getContext().getTruffleTypes().getSlowPath())); addInternalValueParameters(method, node.getGenericSpecialization(), node.needsFrame(), false); - CodeTreeBuilder builder = method.createBuilder(); - - String prefix = null; + final CodeTreeBuilder builder = method.createBuilder(); + List specializations = node.getSpecializations(); - + List filteredSpecializations = new ArrayList<>(); for (SpecializationData current : specializations) { if (current.isUninitialized() || !current.isReachable()) { continue; } - CodeTreeBuilder execute = new CodeTreeBuilder(builder); - execute.tree(createGenericInvoke(builder, node.getGenericSpecialization(), current)); - builder.tree(createGuardAndCast(builder, prefix, current.getNode().getGenericSpecialization(), current, true, execute.getRoot(), null, true, false)); + filteredSpecializations.add(current); + } + + List groups = SpecializationGroup.create(filteredSpecializations); + + for (SpecializationGroup group : groups) { + builder.tree(createExecuteTree(builder, node.getGenericSpecialization(), group, false, new CodeBlock() { + + public CodeTree create(CodeTreeBuilder b, SpecializationData current) { + return createGenericInvoke(builder, current.getNode().getGenericSpecialization(), current); + } + })); } for (SpecializationData current : specializations) { @@ -1516,6 +1518,209 @@ return method; } + private CodeTree createExecuteTree(CodeTreeBuilder outerParent, final SpecializationData source, final SpecializationGroup group, final boolean checkMinimumState, + final CodeBlock guardedblock) { + return guard(outerParent, source, group, checkMinimumState, new CodeBlock() { + + public CodeTree create(CodeTreeBuilder parent, Void value) { + CodeTreeBuilder builder = parent.create(); + + if (group.getSpecialization() != null) { + builder.tree(guardedblock.create(builder, group.getSpecialization())); + + assert group.getChildren().isEmpty() : "missed a specialization"; + } else { + for (SpecializationGroup childGroup : group.getChildren()) { + builder.tree(createExecuteTree(builder, source, childGroup, checkMinimumState, guardedblock)); + } + } + + return builder.getRoot(); + } + }); + } + + private CodeTree guard(CodeTreeBuilder parent, SpecializationData source, SpecializationGroup group, boolean checkMinimumState, CodeBlock bodyBlock) { + NodeData node = source.getNode(); + + CodeTreeBuilder guardsBuilder = parent.create(); + CodeTreeBuilder castBuilder = parent.create(); + CodeTreeBuilder guardsCastBuilder = parent.create(); + + String guardsAnd = ""; + String guardsCastAnd = ""; + + boolean minimumState = checkMinimumState; + if (minimumState) { + int groupMaxIndex = group.getMaxSpecializationIndex(); + + int genericIndex = node.getSpecializations().indexOf(node.getGenericSpecialization()); + if (groupMaxIndex >= genericIndex) { + // no minimum state check for an generic index + minimumState = false; + } + + if (minimumState) { + // no minimum state check if alread checked by parent group + int parentMaxIndex = -1; + if (group.getParent() != null) { + parentMaxIndex = group.getParent().getMaxSpecializationIndex(); + } + if (groupMaxIndex == parentMaxIndex) { + minimumState = false; + } + } + + if (minimumState) { + guardsBuilder.string(guardsAnd); + guardsBuilder.string("minimumState < " + groupMaxIndex); + guardsAnd = " && "; + } + } + + for (String assumption : group.getAssumptions()) { + guardsBuilder.string(guardsAnd); + guardsBuilder.string("this"); + guardsBuilder.string(".").string(assumption).string(".isValid()"); + guardsAnd = " && "; + } + + int argOffset = group.getTypeGuardOffset(); + int argIndex = argOffset; + for (TypeData typeData : group.getTypeGuards()) { + + ActualParameter valueParam = source.getSignatureParameter(argIndex); + + if (valueParam == null) { + /* + * If used inside a execute evaluated method then the value param may not exist. + * In that case we assume that the value is executed generic or of the current + * specialization. + */ + if (group.getSpecialization() != null) { + valueParam = group.getSpecialization().getSignatureParameter(argIndex); + } else { + valueParam = node.getGenericSpecialization().getSignatureParameter(argIndex); + } + } + + NodeChildData child = node.findChild(valueParam.getSpecification().getName()); + if (child == null) { + throw new IllegalStateException(); + } + + CodeTree implicitGuard = createTypeGuard(guardsBuilder, child, valueParam, typeData); + if (implicitGuard != null) { + guardsBuilder.string(guardsAnd); + guardsBuilder.tree(implicitGuard); + guardsAnd = " && "; + } + + CodeTree cast = createCast(castBuilder, child, valueParam, typeData); + if (cast != null) { + castBuilder.tree(cast); + } + + argIndex++; + } + CodeTreeBuilder builder = parent.create(); + + int ifCount = 0; + if (isElseConnectableGroup(group)) { + if (minimumState) { + builder.startElseIf().tree(guardsBuilder.getRoot()).end().startBlock(); + } else { + builder.startElseBlock(); + } + ifCount++; + + } else { + for (GuardData guard : group.getGuards()) { + if (needsTypeGuard(source, group, guard)) { + guardsCastBuilder.tree(createMethodGuard(parent, guardsCastAnd, source, guard)); + guardsCastAnd = " && "; + } else { + guardsBuilder.tree(createMethodGuard(parent, guardsAnd, source, guard)); + guardsAnd = " && "; + } + } + + if (!guardsBuilder.isEmpty()) { + builder.startIf().tree(guardsBuilder.getRoot()).end().startBlock(); + ifCount++; + } + builder.tree(castBuilder.getRoot()); + + if (!guardsCastBuilder.isEmpty()) { + builder.startIf().tree(guardsCastBuilder.getRoot()).end().startBlock(); + ifCount++; + } + } + + builder.tree(bodyBlock.create(builder, null)); + + builder.end(ifCount); + return builder.getRoot(); + } + + private boolean isElseConnectableGroup(SpecializationGroup group) { + if (!group.getTypeGuards().isEmpty() || !group.getAssumptions().isEmpty()) { + return false; + } + + SpecializationGroup previousGroup = group.getPreviousGroup(); + if (previousGroup != null && group.getGuards().size() == 1 && previousGroup.getGuards().size() == 1) { + GuardData guard = group.getGuards().get(0); + GuardData previousGuard = previousGroup.getGuards().get(0); + + if (guard.getMethod().equals(previousGuard.getMethod())) { + assert guard.isNegated() != previousGuard.isNegated(); + return true; + } + } + return false; + } + + private boolean needsTypeGuard(SpecializationData source, SpecializationGroup group, GuardData guard) { + int offset = group.getTypeGuardOffset(); + int argIndex = 0; + for (ActualParameter parameter : guard.getParameters()) { + if (!parameter.getSpecification().isSignature()) { + continue; + } + if (argIndex < offset) { + // type casted in parent group + continue; + } + + int guardIndex = argIndex - offset; + if (guardIndex < group.getTypeGuards().size()) { + TypeData requiredType = group.getTypeGuards().get(guardIndex); + + ActualParameter sourceParameter = source.findParameter(parameter.getLocalName()); + if (sourceParameter == null) { + sourceParameter = source.getNode().getGenericSpecialization().findParameter(parameter.getLocalName()); + } + + if (sourceParameter.getTypeSystemType().needsCastTo(getContext(), requiredType)) { + return true; + } + } + argIndex++; + } + return false; + } + + private CodeTree createMethodGuard(CodeTreeBuilder parent, String prefix, SpecializationData source, GuardData guard) { + CodeTreeBuilder builder = parent.create(); + builder.string(prefix); + if (guard.isNegated()) { + builder.string("!"); + } + builder.tree(createTemplateMethodCall(builder, null, source, guard, null)); + return builder.getRoot(); + } + protected CodeTree createGenericInvoke(CodeTreeBuilder parent, SpecializationData source, SpecializationData current) { CodeTreeBuilder builder = new CodeTreeBuilder(parent); @@ -1528,83 +1733,60 @@ return encloseThrowsWithFallThrough(current, builder.getRoot()); } - protected CodeTree createGenericInvokeAndSpecialize(CodeTreeBuilder parent, SpecializationData source, SpecializationData current) { - CodeTreeBuilder builder = new CodeTreeBuilder(parent); + protected CodeTree createGenericInvokeAndSpecialize(CodeTreeBuilder parent, SpecializationData source, SpecializationData current, String currentNodeVar) { + CodeTreeBuilder builder = parent.create(); + CodeTreeBuilder prefix = parent.create(); NodeData node = current.getNode(); - builder.startIf().string("resultClass == null").end().startBlock(); - if (current.getMethod() != null) { - CodeTree executeCall = createTemplateMethodCall(builder, null, source, current, null); - if (current.getReturnType().getTypeSystemType().isVoid()) { - builder.statement(executeCall); - } else { - builder.startStatement().string("result = ").tree(executeCall).end(); - } - builder.startStatement(); - builder.string("resultClass = ").string(nodeSpecializationClassName(current)).string(".class"); + if (current.isGeneric() && node.isPolymorphic()) { + builder.startIf().string(currentNodeVar).string(".next0 == null && minimumState > 0").end().startBlock(); + builder.tree(createRewritePolymorphic(builder, node, currentNodeVar)); + builder.end(); + builder.startElseBlock(); + builder.tree(createRewriteGeneric(builder, source, current, currentNodeVar)); builder.end(); } else { - emitEncounteredSynthetic(builder, current); + // simple rewrite + if (current.getExceptions().isEmpty()) { + builder.tree(createGenericInvoke(builder, source, current, createReplaceCall(builder, current, currentNodeVar, currentNodeVar, null))); + } else { + builder.startStatement().string(currentNodeVar).string(" = ").tree(createReplaceCall(builder, current, currentNodeVar, currentNodeVar, null)).end(); + builder.tree(createGenericInvoke(builder, source, current, CodeTreeBuilder.singleString(currentNodeVar))); + } + } + CodeTreeBuilder root = parent.create(); + root.tree(prefix.getRoot()); + root.tree(encloseThrowsWithFallThrough(current, builder.getRoot())); + return root.getRoot(); + } + + private CodeTree createRewriteGeneric(CodeTreeBuilder parent, SpecializationData source, SpecializationData current, String currentNode) { + NodeData node = current.getNode(); + + CodeTreeBuilder builder = parent.create(); + builder.declaration(getContext().getTruffleTypes().getNode(), "root", currentNode); + builder.startIf().string(currentNode).string(".next0 != null").end().startBlock(); + builder.tree(createFindRoot(builder, node, false)); + builder.end(); + builder.end(); + builder.tree(createGenericInvoke(builder, source, current, createReplaceCall(builder, current, "root", currentNode, null))); + return builder.getRoot(); + } + + protected CodeTree createFindRoot(CodeTreeBuilder parent, NodeData node, boolean countDepth) { + CodeTreeBuilder builder = parent.create(); + builder.startDoBlock(); + builder.startAssert().string("root != null").string(" : ").doubleQuote("No polymorphic parent node.").end(); + builder.startStatement().string("root = ").string("root.getParent()").end(); + if (countDepth) { + builder.statement("depth++"); } builder.end(); - - boolean ifAllowed = current.hasRewrite(getContext()); - if (ifAllowed) { - builder.startIf().string("allowed").end().startBlock(); - } - - if (!current.isGeneric() || node.getPolymorphicDepth() <= 1) { - // generic rewrite - builder.tree(createRewriteGeneric(builder, current)); - } else { - boolean rewriteableToGeneric = node.getGenericSpecialization().getMethod() != null && node.getGenericSpecialization().isReachable(); - if (rewriteableToGeneric) { - builder.startIf().string("resultClass == ").string(nodeSpecializationClassName(node.getGenericSpecialization())).string(".class").end(); - builder.startBlock(); - - boolean maybePolymorphic = node.getPolymorphicDepth() > 1; - if (maybePolymorphic) { - builder.startIf().string("next0 == null").end(); - builder.startBlock(); - } - builder.tree(createRewriteGeneric(builder, current)); - if (maybePolymorphic) { - builder.end().startElseBlock(); - builder.statement("Node searchNode = super.getParent()"); - builder.startWhile().string("searchNode != null").end(); - builder.startBlock(); - builder.statement("searchNode = searchNode.getParent()"); - builder.startIf().instanceOf("searchNode", nodePolymorphicClassName(node, node.getGenericPolymorphicSpecialization())).end(); - builder.startBlock().breakStatement().end(); - builder.end(); - builder.startStatement().startCall("searchNode", "replace"); - builder.startGroup().startNew(nodeSpecializationClassName(current)).startGroup().cast(baseClassName(node)).string("searchNode").end().end().end(); - builder.string("message"); - builder.end().end().end(); - } - - builder.end().startElseBlock(); - } - - // polymorphic rewrite - builder.tree(createRewritePolymorphic(builder, node)); - - if (rewriteableToGeneric) { - builder.end(); - } - } - - if (current.getReturnType().getTypeSystemType().isVoid()) { - builder.returnStatement(); - } else { - builder.startReturn().string("result").end(); - } - if (ifAllowed) { - builder.end(); - } - - return encloseThrowsWithFallThrough(current, builder.getRoot()); + builder.startDoWhile(); + builder.string("!").startParantheses().instanceOf("root", nodePolymorphicClassName(node, node.getGenericPolymorphicSpecialization())).end(); + builder.end(); + return builder.getRoot(); } private CodeTree encloseThrowsWithFallThrough(SpecializationData current, CodeTree tree) { @@ -1624,23 +1806,50 @@ return builder.getRoot(); } - private CodeTree createRewriteGeneric(CodeTreeBuilder parent, SpecializationData current) { + protected CodeTree createGenericInvoke(CodeTreeBuilder parent, SpecializationData source, SpecializationData current, CodeTree replaceCall) { CodeTreeBuilder builder = parent.create(); - builder.startStatement().startCall("super", "replace"); - builder.startGroup().startNew(nodeSpecializationClassName(current)).string("this").end().end(); - builder.string("message"); - builder.end().end(); + if (current.isGeneric()) { + builder.startReturn().tree(replaceCall).string(".").startCall(EXECUTE_GENERIC_NAME); + addInternalValueParameterNames(builder, source, current, null, current.getNode().needsFrame(), true); + builder.end().end(); + + } else if (current.getMethod() == null) { + builder.statement(replaceCall); + emitEncounteredSynthetic(builder, current); + } else if (!current.canBeAccessedByInstanceOf(getContext(), source.getNode().getNodeType())) { + builder.statement(replaceCall); + builder.startReturn().tree(createTemplateMethodCall(parent, null, source, current, null)).end(); + } else { + replaceCall.add(new CodeTree(CodeTreeKind.STRING, null, ".")); + builder.startReturn().tree(createTemplateMethodCall(parent, replaceCall, source, current, null)).end(); + } return builder.getRoot(); } - private CodeTree createRewritePolymorphic(CodeTreeBuilder parent, NodeData node) { - String className = nodePolymorphicClassName(node, node.getGenericPolymorphicSpecialization()); + protected CodeTree createReplaceCall(CodeTreeBuilder builder, SpecializationData current, String target, String source, String message) { + String className = nodeSpecializationClassName(current); + CodeTreeBuilder replaceCall = builder.create(); + if (target != null) { + replaceCall.startCall(target, "replace"); + } else { + replaceCall.startCall("replace"); + } + replaceCall.startGroup().startNew(className).string(source).end().end(); + if (message == null) { + replaceCall.string("message"); + } else { + replaceCall.doubleQuote(message); + } + replaceCall.end(); + return replaceCall.getRoot(); + } + + private CodeTree createRewritePolymorphic(CodeTreeBuilder parent, NodeData node, String currentNode) { + String polyClassName = nodePolymorphicClassName(node, node.getGenericPolymorphicSpecialization()); + String uninitializedName = nodeSpecializationClassName(node.getUninitializedSpecialization()); CodeTreeBuilder builder = parent.create(); - builder.startStatement(); - builder.string(className); - builder.string(" polymorphic = "); - builder.startNew(className).string("this").end(); - builder.end(); + + builder.declaration(polyClassName, "polymorphic", builder.create().startNew(polyClassName).string(currentNode).end()); for (ActualParameter param : node.getGenericSpecialization().getParameters()) { if (!param.getSpecification().isSignature()) { @@ -1648,22 +1857,23 @@ } NodeChildData child = node.findChild(param.getSpecification().getName()); if (child != null) { - builder.startStatement().string("this.").string(child.getName()); + builder.startStatement().string(currentNode).string(".").string(child.getName()); if (child.getCardinality().isMany()) { builder.string("[").string(String.valueOf(param.getIndex())).string("]"); } builder.string(" = null").end(); } } - builder.startStatement().startCall("super", "replace"); - builder.string("polymorphic"); - builder.string("message"); - builder.end().end(); - - builder.statement("polymorphic.setNext0(this)"); - builder.statement("setNext0(createSpezialization0(resultClass))"); - - builder.statement("polymorphic.optimizeTypes()"); + builder.startStatement().startCall(currentNode, "replace").string("polymorphic").string("message").end().end(); + builder.startStatement().startCall("polymorphic", "setNext0").string(currentNode).end().end(); + builder.startStatement().startCall(currentNode, "setNext0").startNew(uninitializedName).string(currentNode).end().end().end(); + + builder.startReturn(); + builder.startCall(currentNode + ".next0", executeCachedName(node.getGenericPolymorphicSpecialization())); + addInternalValueParameterNames(builder, node.getGenericSpecialization(), node.getGenericSpecialization(), null, true, true); + builder.end(); + builder.end(); + return builder.getRoot(); } @@ -1875,8 +2085,8 @@ if (specialization.isPolymorphic()) { builder.tree(createReturnOptimizeTypes(builder, currentExecutable, specialization, param)); } else { - builder.tree(createReturnExecuteAndSpecialize(builder, currentExecutable, specialization.findNextSpecialization(), param, "Expected " + param.getLocalName() + " instanceof " + - Utils.getSimpleName(param.getType()))); + builder.tree(createReturnExecuteAndSpecialize(builder, currentExecutable, specialization, param, + "Expected " + param.getLocalName() + " instanceof " + Utils.getSimpleName(param.getType()))); } builder.end(); // catch block } @@ -2028,19 +2238,20 @@ return builder.getRoot(); } - protected CodeTree createReturnExecuteAndSpecialize(CodeTreeBuilder parent, ExecutableTypeData executable, SpecializationData nextSpecialization, ActualParameter exceptionParam, String reason) { - SpecializationData generic = getModel().getNode().getGenericSpecialization(); + protected CodeTree createReturnExecuteAndSpecialize(CodeTreeBuilder parent, ExecutableTypeData executable, SpecializationData current, ActualParameter exceptionParam, String reason) { + NodeData node = current.getNode(); + SpecializationData generic = node.getGenericSpecialization(); CodeTreeBuilder specializeCall = new CodeTreeBuilder(parent); specializeCall.startCall(EXECUTE_SPECIALIZE_NAME); - specializeCall.string(nodeSpecializationClassName(nextSpecialization) + ".class"); - addInternalValueParameterNames(specializeCall, generic, nextSpecialization.getNode().getGenericSpecialization(), exceptionParam != null ? exceptionParam.getLocalName() : null, true, true); + specializeCall.string(String.valueOf(node.getSpecializations().indexOf(current))); + addInternalValueParameterNames(specializeCall, generic, node.getGenericSpecialization(), exceptionParam != null ? exceptionParam.getLocalName() : null, true, true); specializeCall.doubleQuote(reason); specializeCall.end().end(); CodeTreeBuilder builder = new CodeTreeBuilder(parent); builder.startReturn(); - builder.tree(createExpectExecutableType(nextSpecialization.getNode(), generic.getReturnType().getTypeSystemType(), executable, specializeCall.getRoot())); + builder.tree(createExpectExecutableType(node, generic.getReturnType().getTypeSystemType(), executable, specializeCall.getRoot())); builder.end(); return builder.getRoot(); @@ -2175,7 +2386,7 @@ NodeData node = specialization.getNode(); - if (node.needsRewrites(getContext()) && node.getPolymorphicDepth() > 1) { + if (node.needsRewrites(getContext()) && node.isPolymorphic()) { createIsCompatible(clazz, specialization); } @@ -2185,15 +2396,25 @@ protected void createConstructors(CodeTypeElement clazz) { TypeElement superTypeElement = Utils.fromTypeMirror(clazz.getSuperclass()); + SpecializationData specialization = getModel(); + NodeData node = specialization.getNode(); for (ExecutableElement constructor : ElementFilter.constructorsIn(superTypeElement.getEnclosedElements())) { - if (getModel().getNode().getUninitializedSpecialization() != null && !getModel().isUninitialized() && - (constructor.getParameters().size() != 1 || constructor.getParameters().get(0).getSimpleName().toString().equals(baseClassName(getModel().getNode())))) { - continue; + if (specialization.isUninitialized()) { + // ignore copy constructors for uninitialized if not polymorphic + if (isCopyConstructor(constructor) && !node.isPolymorphic()) { + continue; + } + } else if (node.getUninitializedSpecialization() != null) { + // ignore others than copy constructors for specialized nodes + if (!isCopyConstructor(constructor)) { + continue; + } } CodeExecutableElement superConstructor = createSuperConstructor(clazz, constructor); + if (superConstructor != null) { - if (getModel().isGeneric() && getModel().getNode().getPolymorphicDepth() > 1) { + if (getModel().isGeneric() && node.isPolymorphic()) { CodeTree body = superConstructor.getBodyTree(); CodeTreeBuilder builder = superConstructor.createBuilder(); builder.tree(body); @@ -2260,57 +2481,37 @@ private CodeTree createAppendPolymorphic(CodeTreeBuilder parent, SpecializationData specialization) { NodeData node = specialization.getNode(); - String genericClassName = nodePolymorphicClassName(node, node.getGenericPolymorphicSpecialization()); CodeTreeBuilder builder = new CodeTreeBuilder(parent); builder.startStatement().startStaticCall(getContext().getTruffleTypes().getCompilerDirectives(), "transferToInterpreter").end().end(); - builder.declaration(getContext().getTruffleTypes().getNode(), "searchNode", "super.getParent()"); + builder.declaration(getContext().getTruffleTypes().getNode(), "root", "this"); builder.declaration(getContext().getType(int.class), "depth", "0"); - builder.startWhile().string("searchNode != null").end(); + builder.tree(createFindRoot(builder, node, true)); + builder.newLine(); + + builder.startIf().string("depth > ").string(String.valueOf(node.getPolymorphicDepth())).end(); builder.startBlock(); - builder.statement("depth++"); - builder.statement("searchNode = searchNode.getParent()"); - - builder.startIf().instanceOf("searchNode", genericClassName).end(); - builder.startBlock().breakStatement().end(); - builder.end(); // if - builder.end(); // while - - builder.startAssert().instanceOf("searchNode", genericClassName).end(); - - builder.startStatement(); - builder.string(genericClassName).string(" ").string("polymorphic = ").string("(").string(genericClassName).string(") searchNode"); + String message = ("Polymorphic limit reached (" + node.getPolymorphicDepth() + ")"); + builder.tree(createGenericInvoke(builder, node.getGenericPolymorphicSpecialization(), node.getGenericSpecialization(), + createReplaceCall(builder, node.getGenericSpecialization(), "root", "this", message))); builder.end(); - builder.startIf().string("depth >= ").string(String.valueOf(node.getPolymorphicDepth())).end(); - builder.startBlock(); - builder.startStatement(); - builder.startCall("searchNode", "replace"); - builder.startNew(nodeSpecializationClassName(node.getGenericSpecialization())).string("this").end(); - builder.doubleQuote("Polymorphic limit reached (" + node.getPolymorphicDepth() + ")"); - builder.end(); - builder.end(); - - builder.startReturn().startCall("super", EXECUTE_GENERIC_NAME); - addInternalValueParameterNames(builder, specialization, node.getGenericSpecialization(), null, node.needsFrame(), true); - builder.end().end(); - - builder.end().startElseBlock(); - builder.startStatement().startCall("super", "setNext0"); + builder.startElseBlock(); + builder.startStatement().startCall("setNext0"); builder.startNew(nodeSpecializationClassName(node.getUninitializedSpecialization())).string("this").end(); builder.end().end(); CodeTreeBuilder specializeCall = new CodeTreeBuilder(builder); specializeCall.startCall(EXECUTE_SPECIALIZE_NAME); - specializeCall.string(nodeSpecializationClassName(node.getUninitializedSpecialization()) + ".class"); + specializeCall.string("0"); addInternalValueParameterNames(specializeCall, specialization, node.getGenericSpecialization(), null, true, true); specializeCall.startGroup().doubleQuote("Uninitialized polymorphic (").string(" + depth + ").doubleQuote("/" + node.getPolymorphicDepth() + ")").end(); specializeCall.end().end(); builder.declaration(node.getGenericSpecialization().getReturnType().getType(), "result", specializeCall.getRoot()); - builder.statement("polymorphic.optimizeTypes()"); + builder.startStatement().string("(").cast(nodePolymorphicClassName(node, node.getGenericPolymorphicSpecialization())).string("root).optimizeTypes()").end(); if (Utils.isVoid(builder.findMethod().getReturnType())) { builder.returnStatement(); @@ -2418,14 +2619,15 @@ CodeTree executeNode = createExecute(builder, executable, specialization); - SpecializationData next = specialization.findNextSpecialization(); CodeTree returnSpecialized = null; - if (next != null) { + + if (specialization.findNextSpecialization() != null) { CodeTreeBuilder returnBuilder = new CodeTreeBuilder(builder); returnBuilder.tree(createDeoptimize(builder)); - returnBuilder.tree(createReturnExecuteAndSpecialize(builder, executable, next, null, "One of guards " + specialization.getGuards() + " failed")); + returnBuilder.tree(createReturnExecuteAndSpecialize(builder, executable, specialization, null, "One of guards " + specialization.getGuardDefinitions() + " failed")); returnSpecialized = returnBuilder.getRoot(); } + builder.tree(createGuardAndCast(builder, null, specialization, specialization, true, executeNode, returnSpecialized, false, false)); return builder.getRoot(); @@ -2451,7 +2653,7 @@ returnBuilder.end(); } else if (specialization.isUninitialized()) { returnBuilder.startCall("super", EXECUTE_SPECIALIZE_NAME); - returnBuilder.startGroup().string(nodeSpecializationClassName(specialization)).string(".class").end(); + returnBuilder.string("0"); addInternalValueParameterNames(returnBuilder, specialization, specialization, null, true, true); returnBuilder.doubleQuote("Uninitialized monomorphic"); returnBuilder.end(); @@ -2505,13 +2707,13 @@ for (SpecializationThrowsData exception : specialization.getExceptions()) { builder.end().startCatchBlock(exception.getJavaClass(), "ex"); builder.tree(createDeoptimize(builder)); - builder.tree(createReturnExecuteAndSpecialize(parent, executable, exception.getTransitionTo(), null, "Thrown " + Utils.getSimpleName(exception.getJavaClass()))); + builder.tree(createReturnExecuteAndSpecialize(parent, executable, specialization, null, "Thrown " + Utils.getSimpleName(exception.getJavaClass()))); } builder.end(); } if (!specialization.getAssumptions().isEmpty()) { builder.end().startCatchBlock(getContext().getTruffleTypes().getInvalidAssumption(), "ex"); - builder.tree(createReturnExecuteAndSpecialize(parent, executable, specialization.findNextSpecialization(), null, "Assumption failed")); + builder.tree(createReturnExecuteAndSpecialize(parent, executable, specialization, null, "Assumption failed")); builder.end(); } @@ -2520,4 +2722,9 @@ } + private interface CodeBlock { + + CodeTree create(CodeTreeBuilder parent, T value); + + } } diff -r d0aeaf72c7bd -r 1e6d5dec4a4e graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeData.java Mon Aug 05 11:25:14 2013 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeData.java Mon Aug 05 13:20:06 2013 +0200 @@ -94,6 +94,10 @@ return polymorphicDepth; } + public boolean isPolymorphic() { + return polymorphicDepth > 1; + } + void setPolymorphicDepth(int polymorphicDepth) { this.polymorphicDepth = polymorphicDepth; } diff -r d0aeaf72c7bd -r 1e6d5dec4a4e graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeFieldData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeFieldData.java Mon Aug 05 11:25:14 2013 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeFieldData.java Mon Aug 05 13:20:06 2013 +0200 @@ -29,27 +29,49 @@ public class NodeFieldData extends MessageContainer { - private VariableElement variable; + private final Element messageElement; + private final AnnotationMirror messageAnnotation; + private final String name; + private final TypeMirror type; + private final boolean generated; + private ExecutableElement getter; - public NodeFieldData(VariableElement var) { - this.variable = var; + public NodeFieldData(Element messageElement, AnnotationMirror messageAnnotation, TypeMirror type, String name, boolean generated) { + this.messageElement = messageElement; + this.messageAnnotation = messageAnnotation; + this.name = name; + this.type = type; + this.generated = generated; + } + + void setGetter(ExecutableElement getter) { + this.getter = getter; } @Override public Element getMessageElement() { - return variable; + return messageElement; + } + + @Override + public AnnotationMirror getMessageAnnotation() { + return messageAnnotation; } public String getName() { - return variable.getSimpleName().toString(); + return name; } public TypeMirror getType() { - return variable.asType(); + return type; } - public VariableElement getVariable() { - return variable; + public boolean isGenerated() { + return generated; + } + + public ExecutableElement getGetter() { + return getter; } } diff -r d0aeaf72c7bd -r 1e6d5dec4a4e graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeMethodParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeMethodParser.java Mon Aug 05 11:25:14 2013 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeMethodParser.java Mon Aug 05 13:20:06 2013 +0200 @@ -79,7 +79,7 @@ addDefaultFrame(methodSpec); addDefaultImplicitThis(method, methodSpec); - addDefaultFieldMethodSpec(method, methodSpec); + addDefaultFieldMethodSpec(methodSpec); addDefaultChildren(shortCircuitsEnabled, shortCircuitName, methodSpec); return methodSpec; @@ -119,9 +119,9 @@ } } - protected void addDefaultFieldMethodSpec(ExecutableElement method, MethodSpec methodSpec) { + protected void addDefaultFieldMethodSpec(MethodSpec methodSpec) { for (NodeFieldData field : getNode().getFields()) { - if (!Utils.isFieldAccessible(method, field.getVariable())) { + if (getNode().isNodeContainer() || field.getGetter() == null) { ParameterSpec spec = new ParameterSpec(field.getName(), field.getType()); spec.setLocal(true); methodSpec.addOptional(spec); diff -r d0aeaf72c7bd -r 1e6d5dec4a4e 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 Aug 05 11:25:14 2013 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeParser.java Mon Aug 05 13:20:06 2013 +0200 @@ -214,7 +214,7 @@ } private void createPolymorphicSpecializations(NodeData node) { - if (!node.needsRewrites(context) || node.getPolymorphicDepth() <= 1) { + if (!node.needsRewrites(context) || !node.isPolymorphic()) { node.setPolymorphicSpecializations(Collections. emptyList()); return; } @@ -277,10 +277,10 @@ node.setPolymorphicSpecializations(specializations); } - private NodeData parseNodeData(TypeElement templateType, TypeMirror nodeType, List elements, List lookupTypes) { + private NodeData parseNodeData(TypeElement templateType, TypeMirror nodeType, List elements, List typeHierarchy) { NodeData nodeData = new NodeData(templateType, templateType.getSimpleName().toString()); - AnnotationMirror typeSystemMirror = findFirstAnnotation(lookupTypes, TypeSystemReference.class); + AnnotationMirror typeSystemMirror = findFirstAnnotation(typeHierarchy, TypeSystemReference.class); if (typeSystemMirror == null) { nodeData.addError("No @%s annotation found in type hierarchy of %s.", TypeSystemReference.class.getSimpleName(), Utils.getQualifiedName(nodeType)); return nodeData; @@ -293,7 +293,7 @@ return nodeData; } - AnnotationMirror polymorphicMirror = findFirstAnnotation(lookupTypes, PolymorphicLimit.class); + AnnotationMirror polymorphicMirror = findFirstAnnotation(typeHierarchy, PolymorphicLimit.class); if (polymorphicMirror != null) { AnnotationValue limitValue = Utils.getAnnotationValue(polymorphicMirror, "value"); int polymorphicLimit = Utils.getAnnotationValue(Integer.class, polymorphicMirror, "value"); @@ -304,8 +304,8 @@ } List assumptionsList = new ArrayList<>(); - for (int i = lookupTypes.size() - 1; i >= 0; i--) { - TypeElement type = lookupTypes.get(i); + for (int i = typeHierarchy.size() - 1; i >= 0; i--) { + TypeElement type = typeHierarchy.get(i); AnnotationMirror assumptions = Utils.findAnnotationMirror(context.getEnvironment(), type, NodeAssumptions.class); if (assumptions != null) { List assumptionStrings = Utils.getAnnotationValueList(String.class, assumptions, "value"); @@ -317,35 +317,66 @@ } } } - AnnotationMirror nodeInfoMirror = findFirstAnnotation(lookupTypes, NodeInfo.class); + AnnotationMirror nodeInfoMirror = findFirstAnnotation(typeHierarchy, NodeInfo.class); if (nodeInfoMirror != null) { nodeData.setShortName(Utils.getAnnotationValue(String.class, nodeInfoMirror, "shortName")); } nodeData.setAssumptions(new ArrayList<>(assumptionsList)); nodeData.setNodeType(nodeType); - AnnotationMirror nodeContainer = findFirstAnnotation(lookupTypes, NodeContainer.class); + AnnotationMirror nodeContainer = findFirstAnnotation(typeHierarchy, NodeContainer.class); nodeData.setNodeContainer(nodeContainer != null); nodeData.setTypeSystem(typeSystem); - nodeData.setFields(parseFields(elements)); + nodeData.setFields(parseFields(typeHierarchy, elements)); parsedNodes.put(Utils.getQualifiedName(templateType), nodeData); // parseChildren invokes cyclic parsing. - nodeData.setChildren(parseChildren(elements, lookupTypes)); + nodeData.setChildren(parseChildren(elements, typeHierarchy)); nodeData.setExecutableTypes(groupExecutableTypes(new ExecutableTypeMethodParser(context, nodeData).parse(elements))); return nodeData; } - private static List parseFields(List elements) { + private List parseFields(List typeHierarchy, List elements) { + Set names = new HashSet<>(); + List fields = new ArrayList<>(); for (VariableElement field : ElementFilter.fieldsIn(elements)) { if (field.getModifiers().contains(Modifier.STATIC)) { continue; } if (field.getModifiers().contains(Modifier.PUBLIC) || field.getModifiers().contains(Modifier.PROTECTED)) { - fields.add(new NodeFieldData(field)); + String name = field.getSimpleName().toString(); + fields.add(new NodeFieldData(field, null, field.asType(), name, false)); + names.add(name); } } + + List reversedTypeHierarchy = new ArrayList<>(typeHierarchy); + Collections.reverse(reversedTypeHierarchy); + for (TypeElement typeElement : reversedTypeHierarchy) { + AnnotationMirror nodeChildrenMirror = Utils.findAnnotationMirror(processingEnv, typeElement, NodeFields.class); + List children = Utils.collectAnnotations(context, nodeChildrenMirror, "value", typeElement, NodeField.class); + + for (AnnotationMirror mirror : children) { + String name = Utils.firstLetterLowerCase(Utils.getAnnotationValue(String.class, mirror, "name")); + TypeMirror type = Utils.getAnnotationValue(TypeMirror.class, mirror, "type"); + + NodeFieldData field = new NodeFieldData(typeElement, mirror, type, name, true); + if (name.isEmpty()) { + field.addError(Utils.getAnnotationValue(mirror, "name"), "Field name cannot be empty."); + } else if (names.contains(name)) { + field.addError(Utils.getAnnotationValue(mirror, "name"), "Duplicate field name '%s'.", name); + } + names.add(name); + + fields.add(field); + } + } + + for (NodeFieldData nodeFieldData : fields) { + nodeFieldData.setGetter(findGetter(elements, nodeFieldData.getName(), nodeFieldData.getType())); + } + return fields; } @@ -429,8 +460,8 @@ nodeChild.addError("Node type '%s' is invalid or not a valid Node.", Utils.getQualifiedName(childType)); } + index++; } - index++; } List filteredChildren = new ArrayList<>(); @@ -634,6 +665,7 @@ } // calculate reachability + SpecializationData prev = null; int specializationCount = 0; boolean reachable = true; for (SpecializationData specialization : specializations) { @@ -641,7 +673,9 @@ specialization.setReachable(true); continue; } - if (!reachable && specialization.getMethod() != null) { + if (prev != null && prev.equalsGuards(specialization) && prev.getExceptions().isEmpty()) { + specialization.addError("%s is not reachable.", specialization.isGeneric() ? "Generic" : "Specialization"); + } else if (!reachable && specialization.getMethod() != null) { specialization.addError("%s is not reachable.", specialization.isGeneric() ? "Generic" : "Specialization"); } specialization.setReachable(reachable); @@ -651,8 +685,10 @@ if (!specialization.isGeneric()) { specializationCount++; } + prev = specialization; } + // initialize polymorphic depth if (node.getPolymorphicDepth() < 0) { node.setPolymorphicDepth(specializationCount - 1); } @@ -974,6 +1010,12 @@ unusedElements.removeAll(nodeData.getExtensionElements()); } + for (NodeFieldData field : nodeData.getFields()) { + if (field.getGetter() != null) { + unusedElements.remove(field.getGetter()); + } + } + for (NodeChildData child : nodeData.getChildren()) { if (child.getAccessElement() != null) { unusedElements.remove(child.getAccessElement()); @@ -1141,7 +1183,7 @@ } } - private Element findGetter(List elements, String variableName, TypeMirror type) { + private ExecutableElement findGetter(List elements, String variableName, TypeMirror type) { if (type == null) { return null; } diff -r d0aeaf72c7bd -r 1e6d5dec4a4e 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 Aug 05 11:25:14 2013 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/SpecializationData.java Mon Aug 05 13:20:06 2013 +0200 @@ -259,4 +259,11 @@ getParameters().add(0, new ActualParameter(frameSpec, frameType, -1, false)); } } + + public boolean equalsGuards(SpecializationData specialization) { + if (assumptions.equals(specialization.getAssumptions()) && guards.equals(specialization.getGuards()) && getSignature().equalsParameters(specialization.getSignature())) { + return true; + } + return false; + } } diff -r d0aeaf72c7bd -r 1e6d5dec4a4e graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/SpecializationGroup.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/SpecializationGroup.java Mon Aug 05 13:20:06 2013 +0200 @@ -0,0 +1,241 @@ +/* + * 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.dsl.processor.node; + +import java.util.*; + +import com.oracle.truffle.dsl.processor.template.TemplateMethod.Signature; +import com.oracle.truffle.dsl.processor.typesystem.*; + +/** + * Class creates groups of specializations to optimize the layout of generated executeAndSpecialize + * and generic execute methods. + */ +public final class SpecializationGroup { + + private final List assumptions; + private final List typeGuards; + private final List guards; + + private final SpecializationData specialization; + private final List children = new ArrayList<>(); + + private SpecializationGroup parent; + + private SpecializationGroup(SpecializationData data) { + this.assumptions = new ArrayList<>(); + this.typeGuards = new ArrayList<>(); + this.guards = new ArrayList<>(); + this.specialization = data; + + this.assumptions.addAll(data.getAssumptions()); + Signature sig = data.getSignature(); + for (int i = 1; i < sig.size(); i++) { + typeGuards.add(sig.get(i)); + } + this.guards.addAll(data.getGuards()); + } + + public SpecializationGroup(List children, List assumptionMatches, List typeGuardsMatches, List guardMatches) { + this.assumptions = assumptionMatches; + this.typeGuards = typeGuardsMatches; + this.guards = guardMatches; + this.specialization = null; + updateChildren(children); + } + + private void updateChildren(List childs) { + if (!children.isEmpty()) { + children.clear(); + } + this.children.addAll(childs); + for (SpecializationGroup child : childs) { + child.parent = this; + } + } + + public int getTypeGuardOffset() { + return (parent != null ? parent.getTypeGuardOffsetRec() : 0); + } + + private int getTypeGuardOffsetRec() { + return typeGuards.size() + (parent != null ? parent.getTypeGuardOffsetRec() : 0); + } + + public SpecializationGroup getParent() { + return parent; + } + + public List getAssumptions() { + return assumptions; + } + + public List getTypeGuards() { + return typeGuards; + } + + public List getGuards() { + return guards; + } + + public List getChildren() { + return children; + } + + public SpecializationData getSpecialization() { + return specialization; + } + + private static SpecializationGroup combine(List groups) { + if (groups.isEmpty()) { + throw new IllegalArgumentException("empty combinations"); + } + if (groups.size() == 1) { + return null; + } + + List assumptionMatches = new ArrayList<>(); + List typeGuardsMatches = new ArrayList<>(); + List guardMatches = new ArrayList<>(); + + SpecializationGroup first = groups.get(0); + List others = groups.subList(1, groups.size()); + + outer: for (String assumption : first.assumptions) { + for (SpecializationGroup other : others) { + if (!other.assumptions.contains(assumption)) { + // assumptions can be combined unordered + continue outer; + } + } + assumptionMatches.add(assumption); + } + + int typeGuardIndex = 0; + outer: for (TypeData typeGuard : first.typeGuards) { + for (SpecializationGroup other : others) { + if (typeGuardIndex >= other.typeGuards.size()) { + break outer; + } + + if (!other.typeGuards.get(typeGuardIndex).equals(typeGuard)) { + break outer; + } + } + typeGuardsMatches.add(typeGuard); + typeGuardIndex++; + } + + outer: for (GuardData guard : first.guards) { + for (SpecializationGroup other : others) { + if (!other.guards.contains(guard)) { + // we must break here. One guard may depend on the other. + break outer; + } + } + guardMatches.add(guard); + } + + if (assumptionMatches.isEmpty() && typeGuardsMatches.isEmpty() && guardMatches.isEmpty()) { + return null; + } + + for (SpecializationGroup group : groups) { + group.assumptions.removeAll(assumptionMatches); + group.typeGuards.subList(0, typeGuardIndex).clear(); + group.guards.removeAll(guardMatches); + } + + List newChildren = new ArrayList<>(groups); + return new SpecializationGroup(newChildren, assumptionMatches, typeGuardsMatches, guardMatches); + } + + public static List create(List specializations) { + List groups = new ArrayList<>(); + for (SpecializationData specialization : specializations) { + groups.add(new SpecializationGroup(specialization)); + } + return createCombinationalGroups(groups); + } + + @Override + public String toString() { + return "SpecializationGroup [assumptions=" + assumptions + ", typeGuards=" + typeGuards + ", guards=" + guards + "]"; + } + + private static List createCombinationalGroups(List groups) { + if (groups.size() <= 1) { + return groups; + } + List newGroups = new ArrayList<>(); + + int i = 0; + for (i = 0; i < groups.size();) { + SpecializationGroup combined = null; + for (int j = groups.size(); j > i + 1; j--) { + combined = combine(groups.subList(i, j)); + if (combined != null) { + break; + } + } + SpecializationGroup newGroup; + if (combined == null) { + newGroup = groups.get(i); + i++; + } else { + newGroup = combined; + List originalGroups = new ArrayList<>(combined.children); + combined.updateChildren(createCombinationalGroups(originalGroups)); + i += originalGroups.size(); + } + + newGroups.add(newGroup); + + } + + return newGroups; + } + + public SpecializationGroup getPreviousGroup() { + if (parent == null || parent.children.isEmpty()) { + return null; + } + int index = parent.children.indexOf(this); + if (index <= 0) { + return null; + } + return parent.children.get(index - 1); + } + + public int getMaxSpecializationIndex() { + if (specialization != null) { + return specialization.getNode().getSpecializations().indexOf(specialization); + } else { + int max = Integer.MIN_VALUE; + for (SpecializationGroup childGroup : getChildren()) { + max = Math.max(max, childGroup.getMaxSpecializationIndex()); + } + return max; + } + } +} diff -r d0aeaf72c7bd -r 1e6d5dec4a4e 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 Aug 05 11:25:14 2013 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/TemplateMethod.java Mon Aug 05 13:20:06 2013 +0200 @@ -216,6 +216,20 @@ return signature; } + public ActualParameter getSignatureParameter(int searchIndex) { + int index = 0; + for (ActualParameter parameter : getParameters()) { + if (!parameter.getSpecification().isSignature()) { + continue; + } + if (index == searchIndex) { + return parameter; + } + index++; + } + return null; + } + public void updateSignature(Signature signature) { assert signature.size() >= 1; int signatureIndex = 0; @@ -366,6 +380,13 @@ return signature; } + public boolean equalsParameters(Signature other) { + if (size() != other.size()) { + return false; + } + return types.subList(1, types.size()).equals(other.types.subList(1, other.types.size())); + } + @Override public boolean equals(Object obj) { if (obj instanceof Signature) { diff -r d0aeaf72c7bd -r 1e6d5dec4a4e graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/GuardData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/GuardData.java Mon Aug 05 11:25:14 2013 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/GuardData.java Mon Aug 05 13:20:06 2013 +0200 @@ -28,12 +28,32 @@ public class GuardData extends TemplateMethod { private final SpecializationData specialization; + private final boolean negated; - public GuardData(TemplateMethod method, SpecializationData specialization) { + public GuardData(TemplateMethod method, SpecializationData specialization, boolean negated) { super(method); + this.negated = negated; this.specialization = specialization; } + public boolean isNegated() { + return negated; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof GuardData) { + GuardData other = (GuardData) obj; + return getMethod().equals(other.getMethod()) && negated == other.negated; + } + return false; + } + + @Override + public int hashCode() { + return getMethod().hashCode(); + } + public SpecializationData getSpecialization() { return specialization; } diff -r d0aeaf72c7bd -r 1e6d5dec4a4e graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/GuardParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/GuardParser.java Mon Aug 05 11:25:14 2013 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/GuardParser.java Mon Aug 05 13:20:06 2013 +0200 @@ -35,11 +35,18 @@ private final SpecializationData specialization; private final String guardName; + private final boolean negated; - public GuardParser(ProcessorContext context, SpecializationData specialization, String guardName) { + public GuardParser(ProcessorContext context, SpecializationData specialization, String guardDefinition) { super(context, specialization.getNode()); this.specialization = specialization; - this.guardName = guardName; + if (guardDefinition.startsWith("!")) { + this.guardName = guardDefinition.substring(1, guardDefinition.length()); + this.negated = true; + } else { + this.guardName = guardDefinition; + this.negated = false; + } setEmitErrors(false); setParseNullOnError(false); } @@ -71,7 +78,7 @@ @Override public GuardData create(TemplateMethod method) { - GuardData guard = new GuardData(method, specialization); + GuardData guard = new GuardData(method, specialization, negated); /* * Update parameters in way that parameter specifications match again the node field names * etc. diff -r d0aeaf72c7bd -r 1e6d5dec4a4e 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 Aug 05 11:25:14 2013 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/TypeSystemCodeGenerator.java Mon Aug 05 13:20:06 2013 +0200 @@ -77,7 +77,7 @@ @Override public CodeTypeElement create(TypeSystemData typeSystem) { String name = typeName(typeSystem); - CodeTypeElement clazz = createClass(typeSystem, modifiers(PUBLIC), name, typeSystem.getTemplateType().asType(), false); + CodeTypeElement clazz = createClass(typeSystem, modifiers(PUBLIC, FINAL), name, typeSystem.getTemplateType().asType(), false); clazz.add(createConstructorUsingFields(modifiers(PROTECTED), clazz)); CodeVariableElement singleton = createSingleton(clazz); @@ -141,6 +141,11 @@ CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), getContext().getType(boolean.class), TypeSystemCodeGenerator.isTypeMethodName(type)); method.addParameter(new CodeVariableElement(getContext().getType(Object.class), LOCAL_VALUE)); + DeclaredType suppressWarnings = (DeclaredType) getContext().getType(SuppressWarnings.class); + CodeAnnotationMirror annotationMirror = new CodeAnnotationMirror(suppressWarnings); + annotationMirror.setElementValue(annotationMirror.findExecutableElement("value"), new CodeAnnotationValue("static-method")); + method.getAnnotationMirrors().add(annotationMirror); + CodeTreeBuilder body = method.createBuilder(); body.startReturn().instanceOf(LOCAL_VALUE, type.getBoxedType()).end(); @@ -156,7 +161,8 @@ method.addParameter(new CodeVariableElement(getContext().getType(Object.class), LOCAL_VALUE)); CodeTreeBuilder body = method.createBuilder(); - body.startAssert().startCall(isTypeMethodName(type)).string(LOCAL_VALUE).end().end(); + String assertMessage = typeName(getModel()) + "." + asTypeMethodName(type) + ": " + Utils.getSimpleName(type.getBoxedType()) + " expected"; + body.startAssert().startCall(isTypeMethodName(type)).string(LOCAL_VALUE).end().string(" : ").doubleQuote(assertMessage).end(); body.startReturn().cast(type.getPrimitiveType(), body.create().string(LOCAL_VALUE).getTree()).end(); return method; diff -r d0aeaf72c7bd -r 1e6d5dec4a4e mxtool/mx.py --- a/mxtool/mx.py Mon Aug 05 11:25:14 2013 +0200 +++ b/mxtool/mx.py Mon Aug 05 13:20:06 2013 +0200 @@ -1549,9 +1549,7 @@ argfile.write('\n'.join(javafilelist)) argfile.close() - javacArgs = [] - if java().debug_port is not None: - javacArgs += ['-J-Xdebug', '-J-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(java().debug_port)] + processorArgs = [] ap = p.annotation_processors() if len(ap) > 0: @@ -1560,25 +1558,40 @@ if exists(genDir): shutil.rmtree(genDir) os.mkdir(genDir) - javacArgs += ['-processorpath', join(processorPath), '-s', genDir] + processorArgs += ['-processorpath', join(processorPath), '-s', genDir] else: - javacArgs += ['-proc:none'] + processorArgs += ['-proc:none'] toBeDeleted = [argfileName] try: compliance = str(p.javaCompliance) if p.javaCompliance is not None else args.compliance if jdtJar is None: log('Compiling Java sources for {0} with javac...'.format(p.name)) - javacCmd = [java().javac, '-g', '-J-Xmx1g', '-source', compliance, '-classpath', cp, '-d', outputDir] + javacArgs + ['@' + argfile.name] + + + javacCmd = [java().javac, '-g', '-J-Xmx1g', '-source', compliance, '-classpath', cp, '-d', outputDir] + if java().debug_port is not None: + javacCmd += ['-J-Xdebug', '-J-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(java().debug_port)] + javacCmd += processorArgs + javacCmd += ['@' + argfile.name] + if not args.warnAPI: javacCmd.append('-XDignore.symbol.file') run(javacCmd) else: log('Compiling Java sources for {0} with JDT...'.format(p.name)) - jdtArgs = [java().java, '-Xmx1g', '-jar', jdtJar, + + jdtArgs = [java().java, '-Xmx1g'] + if java().debug_port is not None: + jdtArgs += ['-Xdebug', '-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(java().debug_port)] + + jdtArgs += [ '-jar', jdtJar, '-' + compliance, '-cp', cp, '-g', '-enableJavadoc', - '-d', outputDir] + javacArgs + '-d', outputDir] + jdtArgs += processorArgs + + jdtProperties = join(p.dir, '.settings', 'org.eclipse.jdt.core.prefs') rootJdtProperties = join(p.suite.dir, 'mx', 'eclipse-settings', 'org.eclipse.jdt.core.prefs') if not exists(jdtProperties) or os.path.getmtime(jdtProperties) < os.path.getmtime(rootJdtProperties): @@ -1599,6 +1612,7 @@ else: jdtArgs += ['-properties', jdtProperties] jdtArgs.append('@' + argfile.name) + run(jdtArgs) finally: for n in toBeDeleted: