# HG changeset patch # User Christian Humer # Date 1419892734 -3600 # Node ID a665483c38819e43c71874f21f0d1f9cfe3d7899 # Parent 6fa3999631d8239a6774d08b86a0de4ddbd5f397 Truffle-DSL: new node layout implementation. diff -r 6fa3999631d8 -r a665483c3881 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ContainsTest.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ContainsTest.java Mon Dec 29 23:38:50 2014 +0100 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ContainsTest.java Mon Dec 29 23:38:54 2014 +0100 @@ -54,8 +54,12 @@ new ExecutionListener() { public void afterExecution(TestRootNode node, int index, Object value, Object expectedResult, Object actualResult, boolean last) { if (value instanceof String) { - // assert that the final specialization is always Object - Assert.assertEquals(Object.class, ((DSLNode) node.getNode()).getMetadata0().getSpecializedTypes()[0]); + if (node.getNode() instanceof DSLNode) { + // assert that the final specialization is always Object + Assert.assertEquals(Object.class, ((DSLNode) node.getNode()).getMetadata0().getSpecializedTypes()[0]); + } else { + Assert.assertTrue(((SpecializedNode) node.getNode()).getSpecializationNode().toString().startsWith("ObjectNode")); + } } } }); diff -r 6fa3999631d8 -r a665483c3881 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteEvaluatedTest.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteEvaluatedTest.java Mon Dec 29 23:38:50 2014 +0100 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteEvaluatedTest.java Mon Dec 29 23:38:54 2014 +0100 @@ -161,10 +161,10 @@ Assert.assertEquals(42, root.getNode().execute1(null, 42)); } - @Test(expected = AssertionError.class) + @Test(expected = Throwable.class) public void test1VarArgs2() { TestRootNode root = TestHelper.createRoot(TestEvaluatedVarArgs2Factory.getInstance()); - Assert.assertEquals(-1, root.getNode().execute1(null)); + root.getNode().execute1(null); } abstract static class TestEvaluatedVarArgs1 extends ChildrenNode { @@ -183,16 +183,16 @@ Assert.assertEquals(42, root.getNode().execute1(null, 21, 21)); } - @Test(expected = AssertionError.class) + @Test(expected = Throwable.class) public void test2VarArgs2() { TestRootNode root = TestHelper.createRoot(TestEvaluatedVarArgs2Factory.getInstance()); - Assert.assertEquals(-1, root.getNode().execute1(null, 42)); + root.getNode().execute1(null, 42); } - @Test(expected = AssertionError.class) + @Test(expected = Throwable.class) public void test2VarArgs3() { TestRootNode root = TestHelper.createRoot(TestEvaluatedVarArgs2Factory.getInstance()); - Assert.assertEquals(-1, root.getNode().execute1(null)); + root.getNode().execute1(null); } abstract static class TestEvaluatedVarArgs2 extends ChildrenNode { diff -r 6fa3999631d8 -r a665483c3881 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/LazyClassLoadingTest.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/LazyClassLoadingTest.java Mon Dec 29 23:38:50 2014 +0100 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/LazyClassLoadingTest.java Mon Dec 29 23:38:54 2014 +0100 @@ -28,28 +28,45 @@ import com.oracle.truffle.api.dsl.*; import com.oracle.truffle.api.dsl.test.LazyClassLoadingTestFactory.TestNodeFactory; -import com.oracle.truffle.api.dsl.test.TypeSystemTest.ValueNode; +import com.oracle.truffle.api.dsl.test.TypeSystemTest.*; public class LazyClassLoadingTest { @Test public void test() { - String testClassName = getClass().getName(); - String factoryClassName = testClassName + "Factory"; - String nodeFactoryClassName = factoryClassName + "$TestNodeFactory"; - - Assert.assertFalse(isLoaded(factoryClassName + "$TestNode")); - Assert.assertFalse(isLoaded(nodeFactoryClassName)); + String factoryName = TestNodeFactory.class.getName(); + String nodeName = factoryName + "$" + TestNode.class.getSimpleName() + "Gen"; + Assert.assertTrue(isLoaded(factoryName)); + Assert.assertFalse(isLoaded(nodeName)); NodeFactory factory = TestNodeFactory.getInstance(); + Assert.assertTrue(isLoaded(factoryName)); + Assert.assertTrue(isLoaded(nodeName)); - Assert.assertTrue(isLoaded(nodeFactoryClassName)); - Assert.assertFalse(isLoaded(nodeFactoryClassName + "$TestBaseNode")); + Assert.assertFalse(isLoaded(nodeName + "$UninitializedNode")); + Assert.assertFalse(isLoaded(nodeName + "$BaseNode")); + Assert.assertFalse(isLoaded(nodeName + "$IntNode")); + Assert.assertFalse(isLoaded(nodeName + "$BooleanNode")); + Assert.assertFalse(isLoaded(nodeName + "$PolymorphicNode")); + + TestRootNode root = TestHelper.createRoot(factory); - TestHelper.createRoot(factory); + Assert.assertTrue(isLoaded(nodeName + "$BaseNode")); + Assert.assertTrue(isLoaded(nodeName + "$UninitializedNode")); + Assert.assertFalse(isLoaded(nodeName + "$IntNode")); + Assert.assertFalse(isLoaded(nodeName + "$BooleanNode")); + Assert.assertFalse(isLoaded(nodeName + "$PolymorphicNode")); + + Assert.assertEquals(42, TestHelper.executeWith(root, 42)); - Assert.assertTrue(isLoaded(nodeFactoryClassName + "$TestBaseNode")); - Assert.assertTrue(isLoaded(nodeFactoryClassName + "$TestUninitializedNode")); - Assert.assertFalse(isLoaded(nodeFactoryClassName + "$TestGenericNode")); + Assert.assertTrue(isLoaded(nodeName + "$IntNode")); + Assert.assertFalse(isLoaded(nodeName + "$BooleanNode")); + Assert.assertFalse(isLoaded(nodeName + "$PolymorphicNode")); + + Assert.assertEquals(true, TestHelper.executeWith(root, true)); + + Assert.assertTrue(isLoaded(nodeName + "$IntNode")); + Assert.assertTrue(isLoaded(nodeName + "$BooleanNode")); + Assert.assertTrue(isLoaded(nodeName + "$PolymorphicNode")); } private boolean isLoaded(String className) { @@ -64,22 +81,18 @@ } } - @SuppressWarnings("unused") - @NodeChildren({@NodeChild("left"), @NodeChild("right")}) + @NodeChild("a") abstract static class TestNode extends ValueNode { - @Specialization(order = 1) - int add(int left, int right) { - return 42; + + @Specialization + int s(int a) { + return a; } - @Specialization(order = 2) - int add(boolean left, boolean right) { - return 21; + @Specialization + boolean s(boolean a) { + return a; } - @Specialization(order = 4) - String add(boolean left, int right) { - return "(boolean,int)"; - } } } diff -r 6fa3999631d8 -r a665483c3881 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/PolymorphicTest2.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/PolymorphicTest2.java Mon Dec 29 23:38:50 2014 +0100 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/PolymorphicTest2.java Mon Dec 29 23:38:54 2014 +0100 @@ -48,17 +48,17 @@ @SuppressWarnings("unused") abstract static class Polymorphic1 extends BinaryNode { - @Specialization(order = 1) + @Specialization int add(int left, int right) { return 42; } - @Specialization(order = 2) + @Specialization int add(boolean left, boolean right) { return 21; } - @Specialization(order = 4) + @Specialization String add(boolean left, int right) { return "(boolean,int)"; } diff -r 6fa3999631d8 -r a665483c3881 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/SourceSectionTest.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/SourceSectionTest.java Mon Dec 29 23:38:50 2014 +0100 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/SourceSectionTest.java Mon Dec 29 23:38:54 2014 +0100 @@ -31,6 +31,7 @@ import org.junit.runner.*; import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.dsl.internal.*; import com.oracle.truffle.api.dsl.test.SourceSectionTestFactory.SourceSection0Factory; import com.oracle.truffle.api.dsl.test.SourceSectionTestFactory.SourceSection1Factory; import com.oracle.truffle.api.dsl.test.TypeSystemTest.ArgumentNode; @@ -61,7 +62,7 @@ private static void expectSourceSection(Node root, SourceSection section) { assertThat(root.getSourceSection(), is(sameInstance(section))); for (Node child : root.getChildren()) { - if (child instanceof ArgumentNode) { + if (child instanceof ArgumentNode || child instanceof SpecializationNode) { continue; } if (child != null) { diff -r 6fa3999631d8 -r a665483c3881 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/SpecializationGroupingTest.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/SpecializationGroupingTest.java Mon Dec 29 23:38:50 2014 +0100 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/SpecializationGroupingTest.java Mon Dec 29 23:38:54 2014 +0100 @@ -45,10 +45,9 @@ @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); + TestRootNode root = TestHelper.createRoot(TestGroupingFactory.getInstance(), a1, a3); SimpleTypes.intCast = 0; SimpleTypes.intCheck = 0; @@ -64,10 +63,9 @@ Assert.assertEquals(4, TestGrouping.true2); Assert.assertEquals(5, TestGrouping.false2); Assert.assertEquals(5, TestGrouping.true3); - Assert.assertEquals(8, SimpleTypes.intCheck); + Assert.assertEquals(10, SimpleTypes.intCheck); Assert.assertEquals(8, SimpleTypes.intCast); Assert.assertEquals(4, a1.checked); - Assert.assertEquals(0, a2.checked); Assert.assertEquals(4, a3.checked); Assert.assertEquals(42, TestHelper.executeWith(root, 21, 21)); @@ -78,16 +76,15 @@ Assert.assertEquals(6, TestGrouping.true3); Assert.assertEquals(5, a1.checked); - Assert.assertEquals(0, a2.checked); Assert.assertEquals(5, a3.checked); - Assert.assertEquals(8, SimpleTypes.intCheck); + Assert.assertEquals(10, SimpleTypes.intCheck); Assert.assertEquals(8, SimpleTypes.intCast); } @SuppressWarnings("unused") @NodeChildren({@NodeChild, @NodeChild}) - @NodeAssumptions({"a1", "a2", "a3"}) + @NodeAssumptions({"a1", "a3"}) public abstract static class TestGrouping extends ValueNode { private static int true1; diff -r 6fa3999631d8 -r a665483c3881 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TestSerialization.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/TestSerialization.java Mon Dec 29 23:38:54 2014 +0100 @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2014, 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.TestSerializationFactory.SerializedNodeFactory; +import com.oracle.truffle.api.dsl.test.TypeSystemTest.TestRootNode; +import com.oracle.truffle.api.dsl.test.TypeSystemTest.ValueNode; +import com.oracle.truffle.api.nodes.*; + +public class TestSerialization { + + @Test + public void testUpdateRoot() { + /* Tests the unexpected polymorphic case. */ + TestRootNode node = TestHelper.createRoot(SerializedNodeFactory.getInstance()); + assertEquals(true, executeWith(node, true)); + assertEquals(21, executeWith(node, 21)); + assertEquals("s", executeWith(node, "s")); + assertEquals(3, node.getNode().invocations); + assertEquals(NodeCost.POLYMORPHIC, node.getNode().getCost()); + + @SuppressWarnings("unchecked") + TestRootNode copiedNode = (TestRootNode) node.deepCopy(); + copiedNode.adoptChildren(); + assertTrue(copiedNode != node); + assertEquals(true, executeWith(copiedNode, true)); + assertEquals(21, executeWith(copiedNode, 21)); + assertEquals("s", executeWith(copiedNode, "s")); + assertEquals(6, copiedNode.getNode().invocations); + } + + @NodeChild + abstract static class SerializedNode extends ValueNode { + + int invocations; + + @Specialization + int add(int left) { + invocations++; + return left; + } + + @Specialization + boolean add(boolean left) { + invocations++; + return left; + } + + @Specialization + String add(String left) { + invocations++; + return left; + } + + } + +} diff -r 6fa3999631d8 -r a665483c3881 graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/GeneratedBy.java --- a/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/GeneratedBy.java Mon Dec 29 23:38:50 2014 +0100 +++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/GeneratedBy.java Mon Dec 29 23:38:54 2014 +0100 @@ -27,7 +27,7 @@ import java.lang.annotation.*; /** - * Marks a type as being generated based on another class or method. + * Marks a type as being generated based on another class or method of a class. */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) diff -r 6fa3999631d8 -r a665483c3881 graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/internal/DSLOptions.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/internal/DSLOptions.java Mon Dec 29 23:38:54 2014 +0100 @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.dsl.internal; + +import java.lang.annotation.*; + +/** + * Internal DSL options to tune the generated code. These are expert options and not intended to be + * changed used for guest language implementations. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +public @interface DSLOptions { + + /** Enable the new DSL generation layout. */ + boolean useNewLayout() default false; + + /** + * Lazy class loading ensures that all generated specialization classes are loaded lazily. + * Disabling this feature will eagerly load all classes but will also reduce the generated code + * size. + */ + boolean useLazyClassLoading() default true; + + /** + * Sets the optimization strategy for implicit casts. + */ + ImplicitCastOptimization implicitCastOptimization() default ImplicitCastOptimization.DUPLICATE_TAIL; + + /** Not yet implemented. */ + boolean useDisjunctiveMethodGuardOptimization() default true; + + public enum ImplicitCastOptimization { + + /** Perform no informed optimization for implicit casts. */ + NONE, + + /** Duplicate specializations for each used implicit cast combination */ + DUPLICATE_TAIL, + + /** + * Use the same specialization for multiple combinations of implicit casts and specialize + * them independently. Not yet fully implemented. + */ + MERGE_CASTS; + + public boolean isNone() { + return this == NONE; + } + + public boolean isDuplicateTail() { + return this == DUPLICATE_TAIL; + } + + public boolean isMergeCasts() { + return this == MERGE_CASTS; + } + } + + public enum TypeBoxingOptimization { + /** Perform the optimization for all types. */ + ALWAYS, + /** Perform the optimization just for primitive types. */ + PRIMITIVE, + /** Perform the optimization for no types. */ + NONE; + } + + /** + * Defines the range of the generation of type specialized execute methods for return types and + * for specialized parameter types. A type specialized execute method is generated as soon as + * one declared type is either returned or used a specialized parameter. + */ + TypeBoxingOptimization monomorphicTypeBoxingOptimization() default TypeBoxingOptimization.PRIMITIVE; + + /** + * Defines the range of types for which type specialized execute methods should be used for + * polymorphic operations. + */ + TypeBoxingOptimization polymorphicTypeBoxingElimination() default TypeBoxingOptimization.PRIMITIVE; + + /** + * Defines the range of types for which type specialized execute methods for implicit cast + * optimizations are used. This option only has an effect if + * {@link ImplicitCastOptimization#DUPLICATE_TAIL} or + * {@link ImplicitCastOptimization#MERGE_CASTS} is set in {@link #implicitCastOptimization()}. + */ + TypeBoxingOptimization implicitTypeBoxingOptimization() default TypeBoxingOptimization.PRIMITIVE; + + /** + * Defines range of specialization return types in which the void boxing optimization is used. + * Void boxing generates an extra execute method with {@link Void} return type in order to avoid + * boxing and type checking of the return type in case the return type is not needed. For this + * to work the operation class needs to provide an overridable execute method returning + * {@link Void}. + */ + TypeBoxingOptimization voidBoxingOptimization() default TypeBoxingOptimization.PRIMITIVE; + + public enum FallbackOptimization { + /** Always generate an optimized fallback specialization. */ + ALWAYS, + + /** + * Only generate an optimized fallback specialization if a method annotated with @Fallback + * is used in the operation. + */ + DECLARED, + + /** + * Never generate an optimized fallback specialization. Please be aware that triggering a @Fallback + * case without optimization will also invalidate your compiled code. + */ + NEVER; + } + + /** Defines the optimization strategy that is used to optimize @Fallback annotated methods. */ + FallbackOptimization optimizeFallback() default FallbackOptimization.DECLARED; + +} diff -r 6fa3999631d8 -r a665483c3881 graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/internal/RewriteEvent.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/internal/RewriteEvent.java Mon Dec 29 23:38:54 2014 +0100 @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.dsl.internal; + +import com.oracle.truffle.api.nodes.*; + +/** + * Lazy rewrite event that implements {@link CharSequence} to be provided as message in + * {@link Node#replace(Node, CharSequence)}. + */ +abstract class RewriteEvent implements CharSequence { + + private final Node source; + private final String reason; + private String message; + + private RewriteEvent(Node source, String reason) { + this.source = source; + this.reason = reason; + } + + public int length() { + return getMessage().length(); + } + + public char charAt(int index) { + return getMessage().charAt(index); + } + + public CharSequence subSequence(int start, int end) { + return getMessage().subSequence(start, end); + } + + @Override + public String toString() { + return getMessage(); + } + + private String getMessage() { + if (message == null) { + message = createMessage(); + } + return message; + } + + private String createMessage() { + StringBuilder builder = new StringBuilder(); + builder.append(source); + builder.append(" "); + builder.append(reason); + Object[] values = getValues(); + if (values.length > 0) { + builder.append(" with parameters ("); + String sep = ""; + for (Object value : values) { + builder.append(sep); + if (value == null) { + builder.append("null"); + } else { + builder.append(value).append(" (").append(value.getClass().getSimpleName()).append(")"); + } + + sep = ", "; + } + builder.append(")"); + } + return builder.toString(); + } + + public abstract Object[] getValues(); + + static final class RewriteEvent0 extends RewriteEvent { + + private static final Object[] EMPTY = new Object[0]; + + public RewriteEvent0(Node source, String reason) { + super(source, reason); + } + + @Override + public Object[] getValues() { + return EMPTY; + } + + } + + static final class RewriteEvent1 extends RewriteEvent { + + private final Object o1; + + public RewriteEvent1(Node source, String reason, Object o1) { + super(source, reason); + this.o1 = o1; + } + + @Override + public Object[] getValues() { + return new Object[]{o1}; + } + + } + + static final class RewriteEvent2 extends RewriteEvent { + + private final Object o1; + private final Object o2; + + public RewriteEvent2(Node source, String reason, Object o1, Object o2) { + super(source, reason); + this.o1 = o1; + this.o2 = o2; + } + + @Override + public Object[] getValues() { + return new Object[]{o1, o2}; + } + + } + + static final class RewriteEvent3 extends RewriteEvent { + + private final Object o1; + private final Object o2; + private final Object o3; + + public RewriteEvent3(Node source, String reason, Object o1, Object o2, Object o3) { + super(source, reason); + this.o1 = o1; + this.o2 = o2; + this.o3 = o3; + } + + @Override + public Object[] getValues() { + return new Object[]{o1, o2, o3}; + } + + } + + static final class RewriteEvent4 extends RewriteEvent { + + private final Object o1; + private final Object o2; + private final Object o3; + private final Object o4; + + public RewriteEvent4(Node source, String reason, Object o1, Object o2, Object o3, Object o4) { + super(source, reason); + this.o1 = o1; + this.o2 = o2; + this.o3 = o3; + this.o4 = o4; + } + + @Override + public Object[] getValues() { + return new Object[]{o1, o2, o3, o4}; + } + + } + + static final class RewriteEventN extends RewriteEvent { + + private final Object[] args; + + public RewriteEventN(Node source, String reason, Object[] args) { + super(source, reason); + this.args = args; + } + + @Override + public Object[] getValues() { + return args; + } + + } +} diff -r 6fa3999631d8 -r a665483c3881 graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/internal/SpecializationNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/internal/SpecializationNode.java Mon Dec 29 23:38:54 2014 +0100 @@ -0,0 +1,445 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.dsl.internal; + +import java.lang.reflect.*; +import java.util.concurrent.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.dsl.internal.RewriteEvent.RewriteEvent0; +import com.oracle.truffle.api.dsl.internal.RewriteEvent.RewriteEvent1; +import com.oracle.truffle.api.dsl.internal.RewriteEvent.RewriteEvent2; +import com.oracle.truffle.api.dsl.internal.RewriteEvent.RewriteEvent3; +import com.oracle.truffle.api.dsl.internal.RewriteEvent.RewriteEvent4; +import com.oracle.truffle.api.dsl.internal.RewriteEvent.RewriteEventN; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.api.nodes.NodeUtil.NodeClass; +import com.oracle.truffle.api.nodes.NodeUtil.NodeField; + +/** + * Internal implementation dependent base class for generated specialized nodes. + */ +@SuppressWarnings("unused") +@NodeInfo(cost = NodeCost.NONE) +public abstract class SpecializationNode extends Node { + + @Child protected SpecializationNode next; + + private final int index; + + public SpecializationNode() { + this(-1); + } + + public SpecializationNode(int index) { + this.index = index; + } + + @Override + public final NodeCost getCost() { + return NodeCost.NONE; + } + + public static Node updateRoot(Node node) { + updateRootImpl(((SpecializedNode) node).getSpecializationNode(), node); + return node; + } + + private static void updateRootImpl(SpecializationNode start, Node node) { + NodeField[] fields = NodeClass.get(start.getClass()).getFields(); + for (int i = fields.length - 1; i >= 0; i--) { + NodeField f = fields[i]; + if (f.getName().equals("root")) { + f.putObject(start, node); + break; + } + } + if (start.next != null) { + updateRootImpl(start.next, node); + } + } + + protected final SpecializationNode polymorphicMerge(SpecializationNode newNode) { + SpecializationNode merged = next.merge(newNode); + if (merged == newNode && !isSame(newNode) && count() <= 2) { + return removeSame(new RewriteEvent0(findParentNode(), "merged polymorphic to monomorphic")); + } + return merged; + } + + public final NodeCost getNodeCost() { + switch (count()) { + case 0: + case 1: + return NodeCost.UNINITIALIZED; + case 2: + return NodeCost.MONOMORPHIC; + default: + return NodeCost.POLYMORPHIC; + } + } + + protected abstract Node[] getSuppliedChildren(); + + protected SpecializationNode merge(SpecializationNode newNode) { + if (this.isSame(newNode)) { + return this; + } + return next != null ? next.merge(newNode) : newNode; + } + + @Override + public final boolean equals(Object obj) { + if (obj instanceof SpecializationNode) { + return ((SpecializationNode) obj).isSame(this); + } + return super.equals(obj); + } + + @Override + public final int hashCode() { + return index; + } + + protected boolean isSame(SpecializationNode other) { + return getClass() == other.getClass(); + } + + private final int count() { + return next != null ? next.count() + 1 : 1; + } + + protected final SpecializationNode removeSame(final CharSequence reason) { + return atomic(new Callable() { + public SpecializationNode call() throws Exception { + return removeImpl(SpecializationNode.this, reason); + } + }); + } + + /** Find the topmost of the specialization chain. */ + private final SpecializationNode findStart() { + SpecializationNode node = this; + Node parent = this.getParent(); + while (parent instanceof SpecializationNode) { + SpecializationNode parentCast = ((SpecializationNode) parent); + if (parentCast.next != node) { + break; + } + node = parentCast; + parent = node.getParent(); + } + return node; + } + + private final Node findParentNode() { + return findStart().getParent(); + } + + private SpecializationNode removeImpl(SpecializationNode toRemove, CharSequence reason) { + SpecializationNode start = findStart(); + SpecializationNode current = start; + while (current != null) { + if (current.isSame(toRemove)) { + current.replace(current.next, reason); + if (current == start) { + start = start.next; + } + } + current = current.next; + } + return start; + } + + public Object acceptAndExecute(VirtualFrame frame) { + throw new UnsupportedOperationException(); + } + + public Object acceptAndExecute(VirtualFrame frame, Object o1) { + throw new UnsupportedOperationException(); + } + + public Object acceptAndExecute(VirtualFrame frame, Object o1, Object o2) { + throw new UnsupportedOperationException(); + } + + public Object acceptAndExecute(VirtualFrame frame, Object o1, Object o2, Object o3) { + throw new UnsupportedOperationException(); + } + + public Object acceptAndExecute(VirtualFrame frame, Object o1, Object o2, Object o3, Object o4) { + throw new UnsupportedOperationException(); + } + + public Object acceptAndExecute(VirtualFrame frame, Object... args) { + throw new UnsupportedOperationException(); + } + + protected SpecializationNode createFallback() { + return null; + } + + protected SpecializationNode createPolymorphic() { + return null; + } + + protected SpecializationNode createNext(VirtualFrame frame) { + throw new UnsupportedOperationException(); + } + + protected SpecializationNode createNext(VirtualFrame frame, Object o1) { + throw new UnsupportedOperationException(); + } + + protected SpecializationNode createNext(VirtualFrame frame, Object o1, Object o2) { + throw new UnsupportedOperationException(); + } + + protected SpecializationNode createNext(VirtualFrame frame, Object o1, Object o2, Object o3) { + throw new UnsupportedOperationException(); + } + + protected SpecializationNode createNext(VirtualFrame frame, Object o1, Object o2, Object o3, Object o4) { + throw new UnsupportedOperationException(); + } + + protected SpecializationNode createNext(VirtualFrame frame, Object... args) { + throw new UnsupportedOperationException(); + } + + protected final Object uninitialized(VirtualFrame frame) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + SpecializationNode nextSpecialization = createNext(frame); + if (nextSpecialization == null) { + nextSpecialization = createFallback(); + } + if (nextSpecialization == null) { + return unsupported(frame); + } + return insertSpecialization(nextSpecialization, new RewriteEvent0(findParentNode(), "inserted new specialization")).acceptAndExecute(frame); + } + + protected final Object uninitialized(VirtualFrame frame, Object o1) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + SpecializationNode nextSpecialization = createNext(frame, o1); + if (nextSpecialization == null) { + nextSpecialization = createFallback(); + } + if (nextSpecialization == null) { + return unsupported(frame, o1); + } + return insertSpecialization(nextSpecialization, new RewriteEvent1(findParentNode(), "inserted new specialization", o1)).acceptAndExecute(frame, o1); + } + + protected final Object uninitialized(VirtualFrame frame, Object o1, Object o2) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + SpecializationNode nextSpecialization = createNext(frame, o1, o2); + if (nextSpecialization == null) { + nextSpecialization = createFallback(); + } + if (nextSpecialization == null) { + return unsupported(frame, o1, o2); + } + return insertSpecialization(nextSpecialization, new RewriteEvent2(findParentNode(), "inserted new specialization", o1, o2)).acceptAndExecute(frame, o1, o2); + } + + protected final Object uninitialized(VirtualFrame frame, Object o1, Object o2, Object o3) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + SpecializationNode nextSpecialization = createNext(frame, o1, o2, o3); + if (nextSpecialization == null) { + nextSpecialization = createFallback(); + } + if (nextSpecialization == null) { + return unsupported(frame, o1, o2, o3); + } + return insertSpecialization(nextSpecialization, new RewriteEvent3(findParentNode(), "inserted new specialization", o1, o2, o3)).acceptAndExecute(frame, o1, o2, o3); + } + + protected final Object uninitialized(VirtualFrame frame, Object o1, Object o2, Object o3, Object o4) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + SpecializationNode nextSpecialization = createNext(frame, o1, o2, o3, o4); + if (nextSpecialization == null) { + nextSpecialization = createFallback(); + } + if (nextSpecialization == null) { + return unsupported(frame, o1, o2, o3, o4); + } + return insertSpecialization(nextSpecialization, new RewriteEvent4(findParentNode(), "inserts new specialization", o1, o2, o3, o4)).acceptAndExecute(frame, o1, o2, o3, o4); + } + + protected final Object uninitialized(VirtualFrame frame, Object... args) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + SpecializationNode nextSpecialization = createNext(frame, args); + if (nextSpecialization == null) { + nextSpecialization = createFallback(); + } + if (nextSpecialization == null) { + unsupported(frame, args); + } + return insertSpecialization(nextSpecialization, new RewriteEventN(findParentNode(), "inserts new specialization", args)).acceptAndExecute(frame, args); + } + + private boolean needsPolymorphic() { + return findStart().count() == 2; + } + + protected final Object remove(String reason, VirtualFrame frame) { + return removeSame(new RewriteEvent0(findParentNode(), reason)).acceptAndExecute(frame); + } + + protected final Object remove(String reason, VirtualFrame frame, Object o1) { + return removeSame(new RewriteEvent1(findParentNode(), reason, o1)).acceptAndExecute(frame, o1); + } + + protected final Object remove(String reason, VirtualFrame frame, Object o1, Object o2) { + return removeSame(new RewriteEvent2(findParentNode(), reason, o1, o2)).acceptAndExecute(frame, o1, o2); + } + + protected final Object remove(String reason, VirtualFrame frame, Object o1, Object o2, Object o3) { + return removeSame(new RewriteEvent3(findParentNode(), reason, o1, o2, o3)).acceptAndExecute(frame, o1, o2, o3); + } + + protected final Object remove(String reason, VirtualFrame frame, Object o1, Object o2, Object o3, Object o4) { + return removeSame(new RewriteEvent4(findParentNode(), reason, o1, o2, o3, o4)).acceptAndExecute(frame, o1, o2, o3, o4); + } + + protected final Object remove(String reason, VirtualFrame frame, Object... args) { + return removeSame(new RewriteEventN(findParentNode(), reason, args)).acceptAndExecute(frame, args); + } + + protected Object unsupported(VirtualFrame frame) { + throw new UnsupportedSpecializationException(findParentNode(), getSuppliedChildren()); + } + + protected Object unsupported(VirtualFrame frame, Object o1) { + throw new UnsupportedSpecializationException(findParentNode(), getSuppliedChildren(), o1); + } + + protected Object unsupported(VirtualFrame frame, Object o1, Object o2) { + throw new UnsupportedSpecializationException(findParentNode(), getSuppliedChildren(), o1, o2); + } + + protected Object unsupported(VirtualFrame frame, Object o1, Object o2, Object o3) { + throw new UnsupportedSpecializationException(findParentNode(), getSuppliedChildren(), o1, o2, o3); + } + + protected Object unsupported(VirtualFrame frame, Object o1, Object o2, Object o3, Object o4) { + throw new UnsupportedSpecializationException(findParentNode(), getSuppliedChildren(), o1, o2, o3, o4); + } + + protected Object unsupported(VirtualFrame frame, Object... args) { + throw new UnsupportedSpecializationException(findParentNode(), getSuppliedChildren(), args); + } + + private SpecializationNode insertSpecialization(final SpecializationNode generated, final CharSequence message) { + return atomic(new Callable() { + public SpecializationNode call() { + return insert(generated, message); + } + }); + } + + private final SpecializationNode insert(final SpecializationNode generated, CharSequence message) { + SpecializationNode start = findStart(); + if (start == this) { + // fast path for first insert + return insertBefore(this, generated, message); + } else { + return slowSortedInsert(start, generated, message); + } + } + + private static SpecializationNode slowSortedInsert(SpecializationNode start, final SpecializationNode generated, final CharSequence message) { + final SpecializationNode merged = start.merge(generated); + if (merged == generated) { + // new node + if (start.count() == 2) { + insertBefore(start, start.createPolymorphic(), "insert polymorphic"); + } + SpecializationNode insertBefore = findInsertBeforeNode(generated.index, start); + return insertBefore(insertBefore, generated, message); + } else { + // existing node + merged.replace(merged, new RewriteEvent0(merged.findParentNode(), "merged specialization")); + return merged; + } + } + + private static SpecializationNode findInsertBeforeNode(int generatedIndex, SpecializationNode start) { + SpecializationNode current = start; + while (current != null && current.index < generatedIndex) { + current = current.next; + } + return current; + } + + private static SpecializationNode insertBefore(SpecializationNode node, SpecializationNode insertBefore, CharSequence message) { + insertBefore.next = node; + return node.replace(insertBefore, message); + } + + @Override + public final String toString() { + Class clazz = getClass(); + StringBuilder b = new StringBuilder(); + b.append(clazz.getSimpleName()); + + appendFields(b, clazz); + if (next != null) { + b.append(" -> ").append(next.toString()); + } + return b.toString(); + } + + private void appendFields(StringBuilder b, Class clazz) { + Field[] fields = clazz.getDeclaredFields(); + if (fields.length == 0) { + return; + } + b.append("("); + for (Field field : fields) { + if (Modifier.isStatic(field.getModifiers())) { + continue; + } + String name = field.getName(); + if (name.equals("root")) { + continue; + } + b.append(field.getName()); + try { + field.setAccessible(true); + b.append(field.get(this)); + } catch (IllegalArgumentException e) { + b.append(e.toString()); + } catch (IllegalAccessException e) { + b.append(e.toString()); + } + } + b.append(")"); + } + +} diff -r 6fa3999631d8 -r a665483c3881 graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/internal/SpecializedNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/internal/SpecializedNode.java Mon Dec 29 23:38:54 2014 +0100 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.dsl.internal; + +import com.oracle.truffle.api.nodes.*; + +/** + * Implemented by DSL generated operation classes. This is internal implementation dependent API. + */ +public interface SpecializedNode extends NodeInterface { + + /** Returns the root {@link SpecializationNode} of the DSL operation. */ + SpecializationNode getSpecializationNode(); + +} diff -r 6fa3999631d8 -r a665483c3881 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ProcessorContext.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ProcessorContext.java Mon Dec 29 23:38:50 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ProcessorContext.java Mon Dec 29 23:38:54 2014 +0100 @@ -83,6 +83,10 @@ return model; } + public DeclaredType getDeclaredType(Class element) { + return (DeclaredType) ElementUtils.getType(environment, element); + } + public TypeMirror getType(Class element) { return ElementUtils.getType(environment, element); } diff -r 6fa3999631d8 -r a665483c3881 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/TruffleProcessor.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/TruffleProcessor.java Mon Dec 29 23:38:50 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/TruffleProcessor.java Mon Dec 29 23:38:54 2014 +0100 @@ -93,7 +93,7 @@ } private static void handleThrowable(AnnotationProcessor generator, Throwable t, Element e) { - String message = "Uncaught error in " + generator.getClass().getSimpleName() + " while processing " + e; + String message = "Uncaught error in " + generator.getClass().getSimpleName() + " while processing " + e + " "; ProcessorContext.getInstance().getEnvironment().getMessager().printMessage(Kind.ERROR, message + ": " + ElementUtils.printException(t), e); } diff -r 6fa3999631d8 -r a665483c3881 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/GeneratorUtils.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/GeneratorUtils.java Mon Dec 29 23:38:50 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/GeneratorUtils.java Mon Dec 29 23:38:54 2014 +0100 @@ -31,18 +31,31 @@ import javax.lang.model.type.*; import javax.lang.model.util.*; +import com.oracle.truffle.api.*; import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.dsl.internal.DSLOptions.*; import com.oracle.truffle.dsl.processor.*; import com.oracle.truffle.dsl.processor.java.model.*; import com.oracle.truffle.dsl.processor.model.*; public class GeneratorUtils { - public static CodeExecutableElement createConstructorUsingFields(ProcessorContext context, Set modifiers, CodeTypeElement clazz) { + public static CodeTree createTransferToInterpreterAndInvalidate() { + ProcessorContext context = ProcessorContext.getInstance(); + CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); + builder.startStatement().startStaticCall(context.getType(CompilerDirectives.class), "transferToInterpreterAndInvalidate").end().end(); + return builder.build(); + } + + public static CodeExecutableElement createConstructorUsingFields(Set modifiers, CodeTypeElement clazz) { + TypeElement superClass = fromTypeMirror(clazz.getSuperclass()); + ExecutableElement constructor = findConstructor(superClass); + return createConstructorUsingFields(modifiers, clazz, constructor); + } + + public static CodeExecutableElement createConstructorUsingFields(Set modifiers, CodeTypeElement clazz, ExecutableElement constructor) { CodeExecutableElement method = new CodeExecutableElement(modifiers, null, clazz.getSimpleName().toString()); CodeTreeBuilder builder = method.createBuilder(); - TypeElement superClass = fromTypeMirror(clazz.getSuperclass()); - ExecutableElement constructor = findConstructor(superClass); if (constructor != null && constructor.getParameters().size() > 0) { builder.startStatement(); builder.startSuperCall(); @@ -64,17 +77,26 @@ builder.string("this."); builder.string(fieldName); builder.string(" = "); - if (isAssignable(field.asType(), context.getTruffleTypes().getNode())) { - builder.string("adoptChild(").string(fieldName).string(")"); - } else { - builder.string(fieldName); - } + builder.string(fieldName); builder.end(); // statement } return method; } + public static boolean isTypeBoxingOptimized(TypeBoxingOptimization boxing, TypeData type) { + switch (boxing) { + case NONE: + return false; + case ALWAYS: + return !type.isGeneric() && !type.isVoid(); + case PRIMITIVE: + return type.isPrimitive(); + default: + throw new AssertionError(); + } + } + private static ExecutableElement findConstructor(TypeElement clazz) { List constructors = ElementFilter.constructorsIn(clazz.getEnclosedElements()); if (constructors.isEmpty()) { @@ -103,13 +125,13 @@ return executable; } - public static CodeTypeElement createClass(Template model, Set modifiers, String simpleName, TypeMirror superType, boolean enumType) { - TypeElement templateType = model.getTemplateType(); + public static CodeTypeElement createClass(Template sourceModel, TemplateMethod sourceMethod, Set modifiers, String simpleName, TypeMirror superType) { + TypeElement templateType = sourceModel.getTemplateType(); ProcessorContext context = ProcessorContext.getInstance(); PackageElement pack = context.getEnvironment().getElementUtils().getPackageOf(templateType); - CodeTypeElement clazz = new CodeTypeElement(modifiers, enumType ? ElementKind.ENUM : ElementKind.CLASS, pack, simpleName); + CodeTypeElement clazz = new CodeTypeElement(modifiers, ElementKind.CLASS, pack, simpleName); TypeMirror resolvedSuperType = superType; if (resolvedSuperType == null) { resolvedSuperType = context.getType(Object.class); @@ -118,8 +140,8 @@ CodeAnnotationMirror generatedByAnnotation = new CodeAnnotationMirror((DeclaredType) context.getType(GeneratedBy.class)); generatedByAnnotation.setElementValue(generatedByAnnotation.findExecutableElement("value"), new CodeAnnotationValue(templateType.asType())); - if (model.getTemplateMethodName() != null) { - generatedByAnnotation.setElementValue(generatedByAnnotation.findExecutableElement("methodName"), new CodeAnnotationValue(model.getTemplateMethodName())); + if (sourceMethod != null && sourceMethod.getMethod() != null) { + generatedByAnnotation.setElementValue(generatedByAnnotation.findExecutableElement("methodName"), new CodeAnnotationValue(sourceMethod.createReferenceName())); } clazz.addAnnotationMirror(generatedByAnnotation); diff -r 6fa3999631d8 -r a665483c3881 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/ImplicitCastNodeFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/ImplicitCastNodeFactory.java Mon Dec 29 23:38:54 2014 +0100 @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2014, 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.generator; + +import static com.oracle.truffle.dsl.processor.java.ElementUtils.*; +import static javax.lang.model.element.Modifier.*; + +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.CompilerDirectives.*; +import com.oracle.truffle.api.dsl.internal.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.dsl.processor.*; +import com.oracle.truffle.dsl.processor.java.*; +import com.oracle.truffle.dsl.processor.java.model.*; +import com.oracle.truffle.dsl.processor.model.*; + +import static com.oracle.truffle.dsl.processor.generator.GeneratorUtils.*; + +public class ImplicitCastNodeFactory { + + private final ProcessorContext context; + private final TypeData forType; + private final TypeSystemData typeSystem; + private final DSLOptions options; + private final List sourceTypes; + + public ImplicitCastNodeFactory(ProcessorContext context, TypeData forType) { + this.context = context; + this.forType = forType; + this.typeSystem = forType.getTypeSystem(); + this.options = typeSystem.getOptions(); + this.sourceTypes = typeSystem.lookupSourceTypes(forType); + } + + public static String typeName(TypeData type) { + return "Implicit" + getTypeId(type.getBoxedType()) + "Cast"; + } + + public static TypeMirror type(TypeData type) { + TypeSystemData typeSystem = type.getTypeSystem(); + String typeSystemName = TypeSystemCodeGenerator.typeName(typeSystem); + return new GeneratedTypeMirror(ElementUtils.getPackageName(typeSystem.getTemplateType()) + "." + typeSystemName, typeName(type)); + } + + public static CodeTree create(TypeData type, CodeTree value) { + return CodeTreeBuilder.createBuilder().startStaticCall(type(type), "create").tree(value).end().build(); + } + + public static CodeTree cast(String nodeName, CodeTree value) { + return CodeTreeBuilder.createBuilder().startCall(nodeName, "cast").tree(value).end().build(); + } + + public static CodeTree check(String nodeName, CodeTree value) { + return CodeTreeBuilder.createBuilder().startCall(nodeName, "check").tree(value).end().build(); + } + + private static String seenFieldName(TypeData type) { + return "seen" + getTypeId(type.getBoxedType()); + } + + public CodeTypeElement create() { + String typeName = typeName(forType); + TypeMirror baseType = context.getType(Object.class); + CodeTypeElement clazz = GeneratorUtils.createClass(typeSystem, null, modifiers(PUBLIC, FINAL, STATIC), typeName, baseType); + + for (TypeData sourceType : sourceTypes) { + CodeVariableElement hasSeen = new CodeVariableElement(modifiers(PUBLIC), context.getType(boolean.class), seenFieldName(sourceType)); + hasSeen.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(CompilationFinal.class))); + clazz.add(hasSeen); + } + + clazz.add(createConstructor(clazz)); + if (isTypeBoxingOptimized(options.monomorphicTypeBoxingOptimization(), forType)) { + clazz.add(createIsMonomorphic()); + } + clazz.add(createCast(false)); + clazz.add(createCast(true)); + clazz.add(createCheck()); + clazz.add(createMerge(clazz)); + clazz.add(createCreate(clazz)); + + return clazz; + } + + private Element createIsMonomorphic() { + String methodName = "isMonomorphic"; + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), context.getType(boolean.class), methodName); + CodeTreeBuilder builder = method.createBuilder(); + builder.startReturn(); + String operator = ""; + for (TypeData sourceType : sourceTypes) { + builder.string(operator); + builder.string(seenFieldName(sourceType)); + operator = " ^ "; + } + builder.end(); + return method; + } + + private static Element createConstructor(CodeTypeElement clazz) { + return new CodeExecutableElement(modifiers(PRIVATE), null, clazz.getSimpleName().toString()); + } + + private Element createCreate(CodeTypeElement clazz) { + String methodName = "create"; + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), clazz.asType(), methodName); + method.addParameter(new CodeVariableElement(typeSystem.getGenericType(), "value")); + CodeTreeBuilder builder = method.createBuilder(); + + builder.declaration(clazz.asType(), "newCast", builder.create().startNew(clazz.asType()).end()); + + for (TypeData sourceType : sourceTypes) { + String seenField = seenFieldName(sourceType); + builder.startStatement(); + builder.string("newCast.").string(seenField).string(" = ").tree(TypeSystemCodeGenerator.check(sourceType, "value")); + builder.end(); + } + builder.startReturn().string("newCast").end(); + return method; + } + + private Element createMerge(CodeTypeElement clazz) { + String methodName = "merge"; + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), context.getType(void.class), methodName); + method.addParameter(new CodeVariableElement(clazz.asType(), "otherCast")); + CodeTreeBuilder builder = method.createBuilder(); + + for (TypeData sourceType : sourceTypes) { + String seenField = seenFieldName(sourceType); + builder.startStatement(); + builder.string("this.").string(seenField).string(" |= ").string("otherCast.").string(seenField); + builder.end(); + } + return method; + } + + private Element createCheck() { + String methodName = "check"; + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), context.getType(boolean.class), methodName); + method.addParameter(new CodeVariableElement(typeSystem.getGenericType(), "value")); + CodeTreeBuilder builder = method.createBuilder(); + + boolean elseIf = false; + for (TypeData sourceType : sourceTypes) { + elseIf = builder.startIf(elseIf); + builder.string(seenFieldName(sourceType)).string(" && ").tree(TypeSystemCodeGenerator.check(sourceType, "value")); + builder.end(); + builder.startBlock().returnTrue().end(); + } + builder.returnFalse(); + return method; + } + + private Element createCast(boolean expect) { + String methodName = expect ? "expect" : "cast"; + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), forType.getPrimitiveType(), methodName); + method.addParameter(new CodeVariableElement(typeSystem.getGenericType(), "value")); + if (expect) { + method.getThrownTypes().add(context.getType(UnexpectedResultException.class)); + } + + CodeTreeBuilder builder = method.createBuilder(); + + boolean elseIf = false; + for (TypeData sourceType : sourceTypes) { + elseIf = builder.startIf(elseIf); + builder.string(seenFieldName(sourceType)).string(" && ").tree(TypeSystemCodeGenerator.check(sourceType, "value")); + builder.end(); + builder.startBlock(); + builder.startReturn(); + CodeTree castTree = TypeSystemCodeGenerator.cast(sourceType, "value"); + ImplicitCastData cast = typeSystem.lookupCast(sourceType, forType); + if (cast != null) { + builder.tree(TypeSystemCodeGenerator.invokeImplicitCast(cast, castTree)); + } else { + builder.tree(castTree); + } + builder.end(); + builder.end(); + } + if (expect) { + builder.startThrow().startNew(context.getType(UnexpectedResultException.class)).string("value").end().end(); + } else { + builder.startStatement().startStaticCall(context.getType(CompilerDirectives.class), "transferToInterpreter").end().end(); + builder.startThrow().startNew(context.getType(AssertionError.class)).end().end(); + } + return method; + } + +} diff -r 6fa3999631d8 -r a665483c3881 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeBaseFactory.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeBaseFactory.java Mon Dec 29 23:38:50 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeBaseFactory.java Mon Dec 29 23:38:54 2014 +0100 @@ -71,7 +71,7 @@ } public CodeTypeElement create() { - CodeTypeElement clazz = GeneratorUtils.createClass(node, modifiers(PRIVATE, ABSTRACT), baseClassName(node), node.getNodeType(), false); + CodeTypeElement clazz = GeneratorUtils.createClass(node, null, modifiers(PRIVATE, ABSTRACT), baseClassName(node), node.getNodeType()); clazz.getImplements().add(context.getTruffleTypes().getDslNode()); for (NodeChildData child : node.getChildren()) { @@ -321,7 +321,7 @@ private CodeTree truffleBooleanOption(CodeTreeBuilder parent, String name) { CodeTreeBuilder builder = parent.create(); builder.staticReference(context.getTruffleTypes().getTruffleOptions(), name); - return builder.getRoot(); + return builder.build(); } private final void addInternalValueParameters(CodeExecutableElement executableMethod, TemplateMethod method, boolean forceFrame, boolean disableFrame, boolean evaluated) { @@ -507,7 +507,7 @@ final String varName = var.getSimpleName().toString(); final TypeMirror varType = var.asType(); if (ElementUtils.isAssignable(varType, context.getTruffleTypes().getNodeArray())) { - CodeTree size = builder.create().string("copy.", varName, ".length").getRoot(); + CodeTree size = builder.create().string("copy.", varName, ".length").build(); builder.startStatement().string("this.").string(varName).string(" = ").startNewArray((ArrayType) varType, size).end().end(); } else { builder.startStatement().string("this.", varName, " = copy.", varName).end(); @@ -598,7 +598,7 @@ builder.startCall(CREATE_INFO).string(reason); addInternalValueParameterNames(builder, specialization, specialization, null, false, false, null); builder.end(); - return builder.getRoot(); + return builder.build(); } private CodeExecutableElement createMonomorphicRewrite() { @@ -633,7 +633,7 @@ builder.end(); builder.declaration(baseClassName, "returnNode", - builder.create().startStaticCall(context.getTruffleTypes().getDslShare(), DSLSHARE_REWRITE).string("this").string("newNode").string("message").end().getRoot()); + builder.create().startStaticCall(context.getTruffleTypes().getDslShare(), DSLSHARE_REWRITE).string("this").string("newNode").string("message").end().build()); builder.startIf().string("returnNode == null").end().startBlock(); builder.tree(createRewritePolymorphic(builder, "this")); builder.end(); @@ -654,15 +654,15 @@ builder.startStatement().string("returnNode = "); builder.startStaticCall(context.getTruffleTypes().getDslShare(), DSLSHARE_REWRITE_TO_POLYMORHPIC); builder.string("this"); - builder.tree(builder.create().startNew(nodeSpecializationClassName(node.getUninitializedSpecialization())).string(currentNode).end().getRoot()); - builder.tree(builder.create().startNew(polyClassName).string(currentNode).end().getRoot()); + builder.tree(builder.create().startNew(nodeSpecializationClassName(node.getUninitializedSpecialization())).string(currentNode).end().build()); + builder.tree(builder.create().startNew(polyClassName).string(currentNode).end().build()); builder.startGroup().cast(baseClassName(node)).startCall("copy").end().end(); builder.string("newNode"); builder.string("message"); builder.end(); builder.end(); - return builder.getRoot(); + return builder.build(); } private CodeExecutableElement createCreateSpecializationMethod(SpecializationGroup group) { @@ -691,7 +691,7 @@ private CodeTree createCreateSpecializationMethodBody0(CodeTreeBuilder parent, SpecializationData current, boolean useDeoptimize) { CodeTreeBuilder builder = new CodeTreeBuilder(parent); - if (current.isGeneric()) { + if (current.isFallback()) { builder.startReturn().nullLiteral().end(); } else { String className = nodeSpecializationClassName(current); @@ -721,7 +721,7 @@ builder.end(); } } - return builder.getRoot(); + return builder.build(); } @@ -752,7 +752,7 @@ } } - return builder.getRoot(); + return builder.build(); } }, elseBlock, forceElse, emitAssumptions, typedCasts, castForGuardsOnly); } @@ -775,7 +775,7 @@ } } - return builder.getRoot(); + return builder.build(); } private static boolean isReachableGroup(SpecializationGroup group, int ifCount) { @@ -877,22 +877,22 @@ } } - int ifCount = startGuardIf(builder, guardsBuilder, 0, elseGuards); - builder.tree(castBuilder.getRoot()); - ifCount = startGuardIf(builder, guardsCastBuilder, ifCount, elseGuards); + int ifCount = startGuardIf(builder, guardsBuilder.build(), 0, elseGuards); + builder.tree(castBuilder.build()); + ifCount = startGuardIf(builder, guardsCastBuilder.build(), ifCount, elseGuards); return ifCount; } - private static int startGuardIf(CodeTreeBuilder builder, CodeTreeBuilder conditionBuilder, int ifCount, List elseGuard) { + private static int startGuardIf(CodeTreeBuilder builder, CodeTree condition, int ifCount, List elseGuard) { int newIfCount = ifCount; - if (!conditionBuilder.isEmpty()) { + if (!condition.isEmpty()) { if (ifCount == 0 && !elseGuard.isEmpty()) { builder.startElseIf(); } else { builder.startIf(); } - builder.tree(conditionBuilder.getRoot()); + builder.tree(condition); builder.end().startBlock(); newIfCount++; } else if (ifCount == 0 && !elseGuard.isEmpty()) { @@ -957,13 +957,13 @@ } CodeTree check; if (castTypeName == null) { - check = TypeSystemCodeGenerator.implicitCheck(targetType, valueName(source), null); + check = TypeSystemCodeGenerator.implicitCheck(targetType, CodeTreeBuilder.singleString(valueName(source)), null); } else { - check = TypeSystemCodeGenerator.implicitCheck(targetType, valueName(source), castTypeName); + check = TypeSystemCodeGenerator.implicitCheck(targetType, CodeTreeBuilder.singleString(valueName(source)), castTypeName); } builder.tree(check); } else { - builder.tree(TypeSystemCodeGenerator.check(targetType, valueName(source))); + builder.tree(TypeSystemCodeGenerator.check(targetType, CodeTreeBuilder.singleString(valueName(source)))); } if (execution.isShortCircuit()) { @@ -972,7 +972,7 @@ builder.end(); // group - return builder.getRoot(); + return builder.build(); } // TODO merge redundancies with #createTypeGuard @@ -997,7 +997,7 @@ if (typedCasts) { castTypeName = implicitTypeName(source); } - cast = TypeSystemCodeGenerator.implicitCast(targetType, valueName(source), castTypeName); + cast = TypeSystemCodeGenerator.implicitCast(targetType, CodeTreeBuilder.singleString(valueName(source)), castTypeName); } else { cast = TypeSystemCodeGenerator.cast(targetType, valueName(source)); } @@ -1005,7 +1005,7 @@ CodeTreeBuilder builder = parent.create(); builder.tree(createLazyAssignment(parent, castValueName(source), targetType.getPrimitiveType(), condition, cast)); - return builder.getRoot(); + return builder.build(); } private CodeTree createGetImplicitType(CodeTreeBuilder parent, NodeExecutionData execution, Parameter source, TypeData targetType) { @@ -1019,10 +1019,10 @@ CodeTreeBuilder builder = parent.create(); List types = getSpecialization().getNode().getTypeSystem().lookupSourceTypes(targetType); if (types.size() > 1) { - CodeTree castType = TypeSystemCodeGenerator.implicitType(targetType, valueName(source)); + CodeTree castType = TypeSystemCodeGenerator.implicitType(targetType, CodeTreeBuilder.singleString(valueName(source))); builder.tree(createLazyAssignment(builder, implicitTypeName(source), context.getType(Class.class), condition, castType)); } - return builder.getRoot(); + return builder.build(); } private static CodeTree createMethodGuard(CodeTreeBuilder parent, String prefix, SpecializationData source, GuardExpression guard) { @@ -1032,7 +1032,7 @@ builder.string("!"); } builder.tree(createTemplateMethodCall(builder, null, source, guard.getResolvedGuard(), null)); - return builder.getRoot(); + return builder.build(); } protected CodeTree createGenericInvoke(CodeTreeBuilder parent, SpecializationData source, SpecializationData current) { @@ -1044,7 +1044,7 @@ builder.startReturn().tree(createTemplateMethodCall(builder, null, source, current, null)).end(); } - return encloseThrowsWithFallThrough(parent, current, builder.getRoot()); + return encloseThrowsWithFallThrough(parent, current, builder.build()); } private CodeTree encloseThrowsWithFallThrough(CodeTreeBuilder parent, SpecializationData current, CodeTree tree) { @@ -1063,7 +1063,7 @@ } builder.end(); - return builder.getRoot(); + return builder.build(); } protected CodeTree createCastingExecute(CodeTreeBuilder parent, ExecutableTypeData executable, ExecutableTypeData castExecutable) { @@ -1134,7 +1134,7 @@ } } - return builder.getRoot(); + return builder.build(); } private static CodeTree createExpectExecutableType(TypeData sourceType, boolean hasUnexpected, TypeData exepctedType, CodeTree value) { @@ -1166,7 +1166,7 @@ } } - return builder.getRoot(); + return builder.build(); } private ExecutableTypeData resolveExecutableType(NodeExecutionData execution, TypeData type) { @@ -1204,7 +1204,7 @@ builder.startStatement().tree(createExecuteChildImplicit(parent, execution, sourceExecutable, targetParameter, unexpectedParameter)).end(); builder.end(); - return builder.getRoot(); + return builder.build(); } } return createExecuteChildImplicit(parent, execution, sourceExecutable, targetParameter, unexpectedParameter); @@ -1270,7 +1270,7 @@ builder.tree(createExecuteChildExpression(parent, execution, expectType, param, unexpectedParameter, null)); } } - return builder.getRoot(); + return builder.build(); } private static String createExecuteChildMethodName(Parameter param, boolean expect) { @@ -1359,7 +1359,7 @@ builder.end(); index++; } - return builder.getRoot(); + return builder.build(); } private CodeTree createExecuteChildExpression(CodeTreeBuilder parent, NodeExecutionData execution, TypeData sourceParameterType, Parameter targetParameter, Parameter unexpectedParameter, @@ -1393,7 +1393,7 @@ builder.string(valueName(targetParameter)); builder.string(" = "); builder.tree(expression); - return builder.getRoot(); + return builder.build(); } private static CodeTree createImplicitCast(ImplicitCastData cast, CodeTree expression) { @@ -1503,7 +1503,7 @@ } builder.end(); // catch block - return builder.getRoot(); + return builder.build(); } private CodeTree createReturnOptimizeTypes(CodeTreeBuilder parent, ExecutableTypeData currentExecutable, SpecializationData currentSpecialization, Parameter param) { @@ -1521,10 +1521,10 @@ TypeData sourceType = polymorphic.getReturnType().getTypeSystemType(); - builder.tree(createExpectExecutableType(sourceType, currentExecutable.hasUnexpectedValue(context), currentExecutable.getType(), execute.getRoot())); + builder.tree(createExpectExecutableType(sourceType, currentExecutable.hasUnexpectedValue(context), currentExecutable.getType(), execute.build())); builder.end(); - return builder.getRoot(); + return builder.build(); } private CodeTree createExecuteChildExpression(CodeTreeBuilder parent, NodeExecutionData targetExecution, ExecutableTypeData targetExecutable, Parameter unexpectedParameter) { @@ -1581,7 +1581,7 @@ builder.end(); - return builder.getRoot(); + return builder.build(); } private CodeTree createShortCircuitTree(CodeTreeBuilder parent, CodeTree body, SpecializationData currentSpecialization, Parameter parameter, Parameter exceptionParam) { @@ -1604,7 +1604,7 @@ } builder.end(); - return builder.getRoot(); + return builder.build(); } private static CodeTree createShortCircuitValue(CodeTreeBuilder parent, SpecializationData specialization, NodeExecutionData execution, Parameter shortCircuitParam, Parameter exceptionParam) { @@ -1624,7 +1624,7 @@ builder.tree(createTemplateMethodCall(builder, null, specialization, shortCircuitData, exceptionParam != null ? exceptionParam.getLocalName() : null)); builder.end(); // statement - return builder.getRoot(); + return builder.build(); } protected CodeTree createCallRewriteMonomorphic(CodeTreeBuilder parent, boolean hasUnexpected, TypeData returnType, Parameter exceptionParam, String reason) { @@ -1638,10 +1638,10 @@ CodeTreeBuilder builder = new CodeTreeBuilder(parent); builder.startReturn(); - builder.tree(createExpectExecutableType(generic.getReturnType().getTypeSystemType(), hasUnexpected, returnType, specializeCall.getRoot())); + builder.tree(createExpectExecutableType(generic.getReturnType().getTypeSystemType(), hasUnexpected, returnType, specializeCall.build())); builder.end(); - return builder.getRoot(); + return builder.build(); } static String valueNameEvaluated(Parameter targetParameter) { @@ -1677,7 +1677,7 @@ if (targetExecution.isIndexed()) { builder.string("[" + targetExecution.getIndex() + "]"); } - return builder.getRoot(); + return builder.build(); } private static String castValueName(Parameter parameter) { @@ -1825,7 +1825,7 @@ builder.end().end(); - return builder.getRoot(); + return builder.build(); } public static String baseClassName(NodeData node) { @@ -1855,7 +1855,7 @@ if (condition == null) { builder.declaration(type, name, value); } else { - builder.declaration(type, name, new CodeTreeBuilder(parent).defaultValue(type).getRoot()); + builder.declaration(type, name, new CodeTreeBuilder(parent).defaultValue(type).build()); builder.startIf().tree(condition).end(); builder.startBlock(); @@ -1866,7 +1866,7 @@ builder.end(); // statement builder.end(); // block } - return builder.getRoot(); + return builder.build(); } void emitEncounteredSynthetic(CodeTreeBuilder builder, NodeData model, TemplateMethod current) { @@ -1895,10 +1895,10 @@ builder.startThrow().startNew(context.getType(UnsupportedSpecializationException.class)); builder.string("rootNode"); builder.startNewArray(context.getTruffleTypes().getNodeArray(), null); - builder.tree(nodes.getRoot()); + builder.tree(nodes.build()); builder.end(); if (!empty) { - builder.tree(arguments.getRoot()); + builder.tree(arguments.build()); } builder.end().end(); } @@ -1959,7 +1959,7 @@ builder.startStatement(); builder.startStaticCall(ProcessorContext.getInstance().getTruffleTypes().getCompilerDirectives(), "transferToInterpreterAndInvalidate").end(); builder.end(); - return builder.getRoot(); + return builder.build(); } private TypeMirror getUnexpectedValueException() { diff -r 6fa3999631d8 -r a665483c3881 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeCodeGenerator.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeCodeGenerator.java Mon Dec 29 23:38:50 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeCodeGenerator.java Mon Dec 29 23:38:54 2014 +0100 @@ -95,19 +95,21 @@ } else { // wrap all types into the first node CodeTypeElement first = generatedNodes.get(0); - CodeTypeElement last = generatedNodes.get(1); - - for (CodeTypeElement generatedNode : generatedNodes) { - if (first != generatedNode) { - first.add(makeInnerClass(generatedNode)); + CodeTypeElement second = first; + if (generatedNodes.size() > 1) { + second = generatedNodes.get(1); + for (CodeTypeElement generatedNode : generatedNodes) { + if (first != generatedNode) { + first.add(makeInnerClass(generatedNode)); + } } } + new NodeFactoryFactory(context, node, second).createFactoryMethods(first, ElementUtils.getVisibility(node.getTemplateType().getModifiers())); ElementUtils.setVisibility(first.getModifiers(), ElementUtils.getVisibility(node.getTemplateType().getModifiers())); for (ExecutableElement constructor : ElementFilter.constructorsIn(first.getEnclosedElements())) { ElementUtils.setVisibility(((CodeExecutableElement) constructor).getModifiers(), Modifier.PRIVATE); } - NodeFactoryFactory.createFactoryMethods(context, node, first, last, ElementUtils.getVisibility(node.getTemplateType().getModifiers())); return first; } } @@ -116,7 +118,7 @@ CodeTypeElement container; Modifier visibility = ElementUtils.getVisibility(node.getTemplateType().getModifiers()); String containerName = NodeFactoryFactory.factoryClassName(node); - container = GeneratorUtils.createClass(node, modifiers(), containerName, null, false); + container = GeneratorUtils.createClass(node, null, modifiers(), containerName, null); if (visibility != null) { container.getModifiers().add(visibility); } @@ -133,13 +135,21 @@ if (!node.needsFactory()) { return Collections.emptyList(); } + if (node.getTypeSystem().getOptions().useNewLayout()) { + return Arrays.asList(new NodeGenFactory(context, node).create()); + } else { + return generateNodesOld(context, node); + } + } + + private static List generateNodesOld(ProcessorContext context, NodeData node) { List nodeTypes = new ArrayList<>(); SpecializationData generic = node.getGenericSpecialization() == null ? node.getSpecializations().get(0) : node.getGenericSpecialization(); CodeTypeElement baseNode = new NodeBaseFactory(context, node, generic).create(); nodeTypes.add(baseNode); for (SpecializationData specialization : node.getSpecializations()) { - if (!specialization.isReachable() || specialization.isGeneric()) { + if (!specialization.isReachable() || specialization.isFallback()) { continue; } if (specialization.isPolymorphic() && node.isPolymorphic(context)) { diff -r 6fa3999631d8 -r a665483c3881 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeFactoryFactory.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeFactoryFactory.java Mon Dec 29 23:38:50 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeFactoryFactory.java Mon Dec 29 23:38:54 2014 +0100 @@ -31,6 +31,7 @@ import javax.lang.model.type.*; import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.dsl.internal.*; import com.oracle.truffle.dsl.processor.*; import com.oracle.truffle.dsl.processor.java.*; import com.oracle.truffle.dsl.processor.java.model.*; @@ -43,12 +44,16 @@ private final ProcessorContext context; private final NodeData node; + private final TypeSystemData typeSystem; + private final DSLOptions options; private final CodeTypeElement createdFactoryElement; public NodeFactoryFactory(ProcessorContext context, NodeData node, CodeTypeElement createdClass) { this.context = context; this.node = node; this.createdFactoryElement = createdClass; + this.typeSystem = node.getTypeSystem(); + this.options = typeSystem.getOptions(); } public static String factoryClassName(NodeData node) { @@ -59,14 +64,14 @@ Modifier visibility = ElementUtils.getVisibility(node.getTemplateType().getModifiers()); TypeMirror nodeFactory = ElementUtils.getDeclaredType(ElementUtils.fromTypeMirror(context.getTruffleTypes().getNodeFactoryBase()), node.getNodeType()); - CodeTypeElement clazz = GeneratorUtils.createClass(node, modifiers(), factoryClassName(node), null, false); + CodeTypeElement clazz = GeneratorUtils.createClass(node, null, modifiers(), factoryClassName(node), null); if (visibility != null) { clazz.getModifiers().add(visibility); } clazz.getModifiers().add(Modifier.FINAL); if (createdFactoryElement != null) { - createFactoryMethods(context, node, clazz, createdFactoryElement, visibility); + createFactoryMethods(clazz, visibility); clazz.setSuperClass(nodeFactory); clazz.add(createNodeFactoryConstructor()); clazz.add(createCreateNodeMethod()); @@ -224,14 +229,14 @@ return var; } - public static void createFactoryMethods(ProcessorContext context, NodeData node, CodeTypeElement clazz, CodeTypeElement createdFactoryElement, Modifier createVisibility) { + public void createFactoryMethods(CodeTypeElement clazz, Modifier createVisibility) { List constructors = NodeBaseFactory.findUserConstructors(createdFactoryElement.asType()); for (ExecutableElement constructor : constructors) { - clazz.add(createCreateMethod(context, node, createVisibility, constructor)); + clazz.add(createCreateMethod(createVisibility, constructor)); } } - private static CodeExecutableElement createCreateMethod(ProcessorContext context, NodeData node, Modifier visibility, ExecutableElement constructor) { + private CodeExecutableElement createCreateMethod(Modifier visibility, ExecutableElement constructor) { CodeExecutableElement method = CodeExecutableElement.clone(context.getEnvironment(), constructor); method.setSimpleName(CodeNames.of("create")); method.getModifiers().clear(); @@ -246,14 +251,18 @@ if (node.getSpecializations().isEmpty()) { body.nullLiteral(); } else { - body.startCall(NodeBaseFactory.nodeSpecializationClassName(node.getSpecializations().get(0)), FACTORY_METHOD_NAME); + if (options.useNewLayout()) { + body.startNew(NodeGenFactory.nodeType(node)); + } else { + body.startCall(NodeBaseFactory.nodeSpecializationClassName(node.getSpecializations().get(0)), FACTORY_METHOD_NAME); + } for (VariableElement var : method.getParameters()) { body.string(var.getSimpleName().toString()); } body.end(); + } body.end(); return method; } - } \ No newline at end of file diff -r 6fa3999631d8 -r a665483c3881 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java Mon Dec 29 23:38:54 2014 +0100 @@ -0,0 +1,2230 @@ +/* + * Copyright (c) 2014, 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.generator; + +import static com.oracle.truffle.dsl.processor.generator.GeneratorUtils.*; +import static com.oracle.truffle.dsl.processor.java.ElementUtils.*; +import static javax.lang.model.element.Modifier.*; + +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; +import javax.lang.model.util.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.dsl.internal.*; +import com.oracle.truffle.api.dsl.internal.DSLOptions.ImplicitCastOptimization; +import com.oracle.truffle.api.dsl.internal.DSLOptions.TypeBoxingOptimization; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.api.nodes.Node.Child; +import com.oracle.truffle.dsl.processor.*; +import com.oracle.truffle.dsl.processor.java.*; +import com.oracle.truffle.dsl.processor.java.model.*; +import com.oracle.truffle.dsl.processor.model.*; +import com.oracle.truffle.dsl.processor.parser.*; +import com.oracle.truffle.dsl.processor.parser.SpecializationGroup.TypeGuard; + +public class NodeGenFactory { + + private static final String FRAME_VALUE = "frameValue"; + + private final ProcessorContext context; + private final NodeData node; + private final TypeSystemData typeSystem; + private final TypeData genericType; + private final DSLOptions options; + + public NodeGenFactory(ProcessorContext context, NodeData node) { + this.context = context; + this.node = node; + this.typeSystem = node.getTypeSystem(); + this.genericType = typeSystem.getGenericTypeData(); + this.options = typeSystem.getOptions(); + } + + public static String nodeTypeName(NodeData node) { + return resolveNodeId(node) + "NodeGen"; + } + + private static String resolveNodeId(NodeData node) { + String nodeid = node.getNodeId(); + if (nodeid.endsWith("Node") && !nodeid.equals("Node")) { + nodeid = nodeid.substring(0, nodeid.length() - 4); + } + return nodeid; + } + + public static TypeMirror nodeType(NodeData node) { + return new GeneratedTypeMirror(ElementUtils.getPackageName(node.getTemplateType()), nodeTypeName(node)); + } + + private static String specializationTypeName(SpecializationData specialization) { + return specialization.getId() + "Node"; + } + + private static TypeMirror specializationType(SpecializationData specialization) { + return new GeneratedTypeMirror(ElementUtils.getPackageName(specialization.getNode().getTemplateType()) + "." + nodeTypeName(specialization.getNode()), specializationTypeName(specialization)); + } + + private static String polymorphicTypeProfileFieldName(NodeExecutionData execution) { + return execution.getName() + "Type_"; + } + + private static String nodeFieldName(NodeExecutionData execution) { + return execution.getName() + "_"; + } + + private static String specializationStartFieldName() { + return "specialization_"; + } + + private static String excludedFieldName(SpecializationData specialization) { + return "exclude" + specialization.getId() + "_"; + } + + private static String executeChildMethodName(NodeExecutionData execution, TypeData type) { + return "execute" + ElementUtils.firstLetterUpperCase(execution.getName()) + (type.isGeneric() ? "" : getTypeId(type.getBoxedType())) + "_"; + } + + private static CodeTree accessParent(String name) { + if (name == null) { + return CodeTreeBuilder.singleString("root"); + } else { + return CodeTreeBuilder.createBuilder().string("root.").string(name).build(); + } + } + + private static String assumptionName(String assumption) { + return assumption + "_"; + } + + public CodeTypeElement create() { + String typeName = nodeTypeName(node); + TypeMirror baseType = node.getTemplateType().asType(); + CodeTypeElement clazz = GeneratorUtils.createClass(node, null, modifiers(PUBLIC, FINAL), typeName, baseType); + + clazz.getImplements().add(getType(SpecializedNode.class)); + + for (String assumption : node.getAssumptions()) { + clazz.add(new CodeVariableElement(modifiers(PRIVATE, FINAL), getType(Assumption.class), assumptionName(assumption))); + } + + for (NodeChildData child : node.getChildren()) { + clazz.addOptional(createAccessChildMethod(child)); + } + + for (NodeFieldData field : node.getFields()) { + if (!field.isGenerated()) { + continue; + } + + clazz.add(new CodeVariableElement(modifiers(PRIVATE, FINAL), field.getType(), field.getName())); + if (field.getGetter() != null && field.getGetter().getModifiers().contains(Modifier.ABSTRACT)) { + CodeExecutableElement method = CodeExecutableElement.clone(context.getEnvironment(), field.getGetter()); + method.getModifiers().remove(Modifier.ABSTRACT); + method.createBuilder().startReturn().string("this.").string(field.getName()).end(); + clazz.add(method); + } + } + + List superConstructors = ElementFilter.constructorsIn(node.getTemplateType().getEnclosedElements()); + for (ExecutableElement superConstructor : superConstructors) { + if (getVisibility(superConstructor.getModifiers()) == PRIVATE) { + continue; + } + if (superConstructors.size() > 1 && superConstructor.getParameters().size() > 0 && + ElementUtils.typeEquals(superConstructor.getEnclosingElement().asType(), superConstructor.getParameters().get(0).asType())) { + // constructor is copy constructor + continue; + } + clazz.add(createNodeConstructor(clazz, superConstructor)); + } + + for (NodeExecutionData execution : node.getChildExecutions()) { + clazz.add(createNodeField(PRIVATE, execution.getNodeType(), nodeFieldName(execution), Child.class)); + } + + for (NodeExecutionData execution : node.getChildExecutions()) { + if (findSpecializedExecutables(execution, node.findSpecializedTypes(execution), options.polymorphicTypeBoxingElimination()).isEmpty()) { + continue; + } + clazz.add(createNodeField(PRIVATE, getType(Class.class), polymorphicTypeProfileFieldName(execution), CompilationFinal.class)); + } + + for (SpecializationData specialization : node.getSpecializations()) { + if (mayBeExcluded(specialization)) { + clazz.add(createNodeField(PRIVATE, getType(boolean.class), excludedFieldName(specialization), CompilationFinal.class)); + } + } + + clazz.add(createNodeField(PRIVATE, TypeSystemNodeFactory.nodeType(node.getTypeSystem()), specializationStartFieldName(), Child.class)); + clazz.add(createMethodGetSpecializationNode()); + clazz.add(createDeepCopyMethod()); + clazz.add(createGetCostMethod()); + + Collection specializedTypes = node.findSpecializedReturnTypes(); + for (ExecutableTypeData execType : node.getExecutableTypes()) { + if (shouldImplementExecutableType(specializedTypes, execType)) { + clazz.add(createExecutableTypeOverride(execType)); + } + } + + SpecializationData initialSpecialization = createSpecializations(clazz); + + for (ExecutableElement constructor : ElementFilter.constructorsIn(clazz.getEnclosedElements())) { + CodeTreeBuilder builder = ((CodeExecutableElement) constructor).appendBuilder(); + builder.startStatement(); + builder.string("this.").string(specializationStartFieldName()); + builder.string(" = ").tree(createCallCreateMethod(initialSpecialization, "this", null)); + builder.end(); + } + + return clazz; + } + + private CodeExecutableElement createNodeConstructor(CodeTypeElement clazz, ExecutableElement superConstructor) { + CodeExecutableElement constructor = GeneratorUtils.createConstructorUsingFields(modifiers(PUBLIC), clazz, superConstructor); + + List childParameters = new ArrayList<>(); + for (NodeChildData child : node.getChildren()) { + childParameters.add(new CodeVariableElement(child.getOriginalType(), child.getName())); + } + constructor.getParameters().addAll(superConstructor.getParameters().size(), childParameters); + + CodeTreeBuilder builder = constructor.appendBuilder(); + List childValues = new ArrayList<>(node.getChildren().size()); + for (NodeChildData child : node.getChildren()) { + String name = child.getName(); + if (child.getCardinality().isMany()) { + CreateCastData createCast = node.findCast(child.getName()); + if (createCast != null) { + CodeTree nameTree = CodeTreeBuilder.singleString(name); + CodeTreeBuilder callBuilder = builder.create(); + callBuilder.string(name).string(" != null ? "); + callBuilder.tree(callTemplateMethod(builder, null, createCast, nameTree)); + callBuilder.string(" : null"); + name += "_"; + builder.declaration(child.getNodeType(), name, callBuilder.build()); + } + } + childValues.add(name); + } + + for (NodeExecutionData execution : node.getChildExecutions()) { + CreateCastData createCast = node.findCast(execution.getChild().getName()); + + builder.startStatement(); + builder.string("this.").string(nodeFieldName(execution)).string(" = "); + + String name = childValues.get(node.getChildren().indexOf(execution.getChild())); + CodeTreeBuilder accessorBuilder = builder.create(); + accessorBuilder.string(name); + + if (execution.isIndexed()) { + accessorBuilder.string("[").string(String.valueOf(execution.getIndex())).string("]"); + } + + CodeTree accessor = accessorBuilder.build(); + + if (createCast != null && execution.getChild().getCardinality().isOne()) { + accessor = callTemplateMethod(builder, null, createCast, accessor); + } + + if (execution.isIndexed()) { + CodeTreeBuilder nullCheck = builder.create(); + nullCheck.string(name).string(" != null ? "); + nullCheck.tree(accessor); + nullCheck.string(" : null"); + accessor = nullCheck.build(); + } + + builder.tree(accessor); + + builder.end(); + } + + return constructor; + } + + private static boolean mayBeExcluded(SpecializationData specialization) { + return !specialization.getExceptions().isEmpty() || !specialization.getExcludedBy().isEmpty(); + } + + private SpecializationData createSpecializations(CodeTypeElement clazz) { + List reachableSpecializations = getReachableSpecializations(); + + if (isSingleSpecializable(reachableSpecializations)) { + SpecializationData single = reachableSpecializations.get(0); + clazz.add(createSingleSpecialization(single)); + return single; + } else { + CodeTypeElement baseSpecialization = clazz.add(createBaseSpecialization(clazz)); + TypeMirror baseSpecializationType = baseSpecialization.asType(); + + Map generated = new LinkedHashMap<>(); + + List generateSpecializations = new ArrayList<>(); + generateSpecializations.add(node.getUninitializedSpecialization()); + if (needsPolymorphic(reachableSpecializations)) { + generateSpecializations.add(node.getPolymorphicSpecialization()); + } + generateSpecializations.addAll(reachableSpecializations); + + for (SpecializationData specialization : generateSpecializations) { + generated.put(specialization, clazz.add(createSpecialization(specialization, baseSpecializationType))); + } + + baseSpecialization.addOptional(createCreateNext(generated)); + baseSpecialization.addOptional(createCreateFallback(generated)); + baseSpecialization.addOptional(createCreatePolymorphic(generated)); + + return node.getUninitializedSpecialization(); + } + } + + // create specialization + + private CodeTypeElement createBaseSpecialization(CodeTypeElement parentClass) { + CodeTypeElement clazz = createClass(node, null, modifiers(PRIVATE, STATIC, ABSTRACT), "BaseNode", TypeSystemNodeFactory.nodeType(typeSystem)); + + clazz.addOptional(createSpecializationConstructor(clazz, null, null)); + clazz.add(new CodeVariableElement(modifiers(PROTECTED, FINAL), nodeType(node), "root")); + + clazz.addOptional(createUnsupported()); + clazz.add(createGetSuppliedChildren()); + + int signatureSize = node.getSignatureSize(); + Set evaluatedCount = getEvaluatedCounts(); + for (int evaluated : evaluatedCount) { + if (signatureSize != evaluated || signatureSize == 0) { + clazz.add(createFastPathExecuteMethod(null, evaluated > 0 ? null : genericType, evaluated)); + } + } + + for (NodeExecutionData execution : node.getChildExecutions()) { + Collection specializedTypes = node.findSpecializedTypes(execution); + specializedTypes.add(genericType); + for (TypeData specializedType : specializedTypes) { + if (isExecuteChildShared(execution, specializedType)) { + if (specializedType.isGeneric()) { + parentClass.add(createExecuteChildMethod(execution, specializedType)); + } else { + clazz.add(createExecuteChildMethod(execution, specializedType)); + } + } + } + } + + return clazz; + } + + private CodeTypeElement createSingleSpecialization(SpecializationData specialization) { + CodeTypeElement clazz = createClass(node, specialization, modifiers(PRIVATE, STATIC, FINAL), specializationTypeName(specialization), TypeSystemNodeFactory.nodeType(typeSystem)); + CodeExecutableElement constructor = clazz.addOptional(createSpecializationConstructor(clazz, null, "0")); + clazz.add(new CodeVariableElement(modifiers(PROTECTED, FINAL), nodeType(node), "root")); + TypeData returnType = specialization.getReturnType().getTypeSystemType(); + Set evaluatedCount = getEvaluatedCounts(); + for (int evaluated : evaluatedCount) { + clazz.add(createFastPathExecuteMethod(specialization, null, evaluated)); + } + if (isTypeBoxingEliminated(specialization)) { + clazz.add(createFastPathExecuteMethod(specialization, returnType, 0)); + } + clazz.add(createFastPathWrapExecuteMethod(genericType, null)); + + clazz.addOptional(createUnsupported()); + clazz.addOptional(createSpecializationCreateMethod(specialization, constructor)); + clazz.add(createGetSuppliedChildren()); + + return clazz; + } + + private CodeTypeElement createSpecialization(SpecializationData specialization, TypeMirror baseType) { + CodeTypeElement clazz = createClass(node, specialization, modifiers(PRIVATE, STATIC, FINAL), specializationTypeName(specialization), baseType); + + CodeExecutableElement constructor = clazz.addOptional(createSpecializationConstructor(clazz, specialization, null)); + + for (Parameter p : specialization.getSignatureParameters()) { + TypeData targetType = p.getTypeSystemType(); + if (targetType.hasImplicitSourceTypes()) { + NodeExecutionData execution = p.getSpecification().getExecution(); + CodeVariableElement implicitProfile = createImplicitProfileParameter(execution, p.getTypeSystemType()); + if (implicitProfile != null) { + implicitProfile.getModifiers().add(PRIVATE); + implicitProfile.getModifiers().add(FINAL); + clazz.add(implicitProfile); + } + } + } + + if (specialization.isFallback()) { + clazz.add(createFallbackGuardMethod()); + } + + clazz.addOptional(createSpecializationCreateMethod(specialization, constructor)); + clazz.addOptional(createMergeMethod(specialization)); + clazz.addOptional(createIsSameMethod(specialization)); + + TypeData returnType = specialization.getReturnType().getTypeSystemType(); + int signatureSize = specialization.getSignatureSize(); + + clazz.add(createFastPathExecuteMethod(specialization, null, signatureSize)); + + if (isTypeBoxingEliminated(specialization)) { + clazz.add(createFastPathExecuteMethod(specialization, returnType, 0)); + + if (signatureSize > 0 && !returnType.isGeneric()) { + clazz.add(createFastPathWrapExecuteMethod(genericType, returnType)); + } + + ExecutableTypeData voidExecutableType = node.findExecutableType(typeSystem.getVoidType(), 0); + if (voidExecutableType != null && isTypeBoxingOptimized(options.voidBoxingOptimization(), returnType)) { + clazz.add(createFastPathWrapVoidMethod(returnType)); + } + } + + return clazz; + } + + private Element createDeepCopyMethod() { + CodeExecutableElement executable = new CodeExecutableElement(modifiers(PUBLIC), getType(Node.class), "deepCopy"); + executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); + CodeTreeBuilder builder = executable.createBuilder(); + builder.startReturn().startStaticCall(getType(SpecializationNode.class), "updateRoot").string("super.deepCopy()").end().end(); + return executable; + } + + private Element createGetCostMethod() { + TypeMirror returnType = getType(NodeCost.class); + CodeExecutableElement executable = new CodeExecutableElement(modifiers(PUBLIC), returnType, "getCost"); + executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); + CodeTreeBuilder builder = executable.createBuilder(); + builder.startReturn().startCall(specializationStartFieldName(), "getNodeCost").end().end(); + return executable; + } + + private CodeExecutableElement createIsSameMethod(SpecializationData specialization) { + if (!specialization.isSpecialized() || !options.implicitCastOptimization().isDuplicateTail()) { + return null; + } + + List profiles = new ArrayList<>(); + for (Parameter parameter : specialization.getSignatureParameters()) { + NodeExecutionData execution = parameter.getSpecification().getExecution(); + if (execution == null) { + continue; + } + CodeVariableElement var = createImplicitProfileParameter(execution, parameter.getTypeSystemType()); + if (var != null) { + profiles.add(var); + } + } + + if (profiles.isEmpty()) { + return null; + } + + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), getType(boolean.class), "isSame"); + method.addParameter(new CodeVariableElement(getType(SpecializationNode.class), "other")); + method.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); + CodeTreeBuilder builder = method.createBuilder(); + + builder.startReturn(); + builder.string("super.isSame(other)"); + + for (CodeVariableElement profile : profiles) { + builder.string(" && "); + builder.string("this.").string(profile.getName()).string(" == ").string("(").cast(specializationType(specialization)).string("other).").string(profile.getName()); + } + + builder.end(); + return method; + } + + private Element createMergeMethod(SpecializationData specialization) { + if (specialization.getExcludedBy().isEmpty() && !specialization.isPolymorphic()) { + return null; + } + TypeMirror specializationNodeType = getType(SpecializationNode.class); + CodeExecutableElement executable = new CodeExecutableElement(modifiers(PUBLIC), specializationNodeType, "merge"); + executable.addParameter(new CodeVariableElement(specializationNodeType, "newNode")); + executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); + CodeTreeBuilder builder = executable.createBuilder(); + + if (specialization.isPolymorphic()) { + builder.statement("return polymorphicMerge(newNode)"); + } else { + boolean elseIf = false; + for (SpecializationData containedSpecialization : specialization.getExcludedBy()) { + elseIf = builder.startIf(elseIf); + builder.string("newNode.getClass() == ").typeLiteral(specializationType(containedSpecialization)); + builder.end(); + builder.startBlock(); + builder.statement("removeSame(\"Contained by " + containedSpecialization.createReferenceName() + "\")"); + builder.end(); + } + builder.statement("return super.merge(newNode)"); + } + + return executable; + } + + private Element createFastPathWrapVoidMethod(TypeData wrap) { + CodeExecutableElement executable = new CodeExecutableElement(modifiers(PUBLIC), typeSystem.getVoidType().getPrimitiveType(), TypeSystemNodeFactory.executeName(typeSystem.getVoidType())); + executable.addParameter(new CodeVariableElement(getType(VirtualFrame.class), FRAME_VALUE)); + executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); + CodeTreeBuilder builder = executable.createBuilder(); + builder.startStatement(); + builder.startCall(TypeSystemNodeFactory.voidBoxingExecuteName(wrap)); + builder.string(FRAME_VALUE); + builder.end(); + builder.end(); + + return executable; + } + + private Element createFastPathWrapExecuteMethod(TypeData override, TypeData wrap) { + CodeExecutableElement executable = new CodeExecutableElement(modifiers(PUBLIC), override.getPrimitiveType(), TypeSystemNodeFactory.executeName(override)); + executable.addParameter(new CodeVariableElement(getType(VirtualFrame.class), FRAME_VALUE)); + executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); + CodeTreeBuilder builder = executable.createBuilder(); + if (wrap != null) { + builder.startTryBlock(); + } + builder.startReturn(); + builder.startCall(TypeSystemNodeFactory.executeName(wrap)); + builder.string(FRAME_VALUE); + builder.end(); + builder.end(); + if (wrap != null) { + builder.end().startCatchBlock(getType(UnexpectedResultException.class), "ex"); + builder.statement("return ex.getResult()"); + builder.end(); + } + + return executable; + } + + private boolean needsPolymorphic(List reachableSpecializations) { + if (reachableSpecializations.size() > 1) { + return true; + } + if (options.implicitCastOptimization().isDuplicateTail()) { + SpecializationData specialization = reachableSpecializations.get(0); + for (Parameter parameter : specialization.getSignatureParameters()) { + if (parameter.getTypeSystemType().hasImplicitSourceTypes()) { + return true; + } + } + } + return false; + } + + private Element createCreateFallback(Map generatedSpecializationClasses) { + SpecializationData fallback = node.getGenericSpecialization(); + if (fallback == null) { + return null; + } + CodeTypeElement generatedType = generatedSpecializationClasses.get(fallback); + if (generatedType == null) { + return null; + } + + TypeMirror returnType = getType(SpecializationNode.class); + CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, FINAL), returnType, "createFallback"); + method.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); + method.createBuilder().startReturn().tree(createCallCreateMethod(fallback, null, null)).end(); + return method; + } + + private Element createCreatePolymorphic(Map generatedSpecializationClasses) { + SpecializationData polymorphic = node.getPolymorphicSpecialization(); + CodeTypeElement generatedPolymorphic = generatedSpecializationClasses.get(polymorphic); + if (generatedPolymorphic == null) { + return null; + } + TypeMirror returnType = getType(SpecializationNode.class); + CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, FINAL), returnType, "createPolymorphic"); + method.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); + method.createBuilder().startReturn().tree(createCallCreateMethod(polymorphic, null, null)).end(); + return method; + } + + private CodeExecutableElement createCreateNext(final Map specializationClasses) { + final LocalContext locals = LocalContext.load(this); + + CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), getType(SpecializationNode.class), "createNext", FRAME_VALUE); + method.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); + + CodeTreeBuilder builder = method.createBuilder(); + SpecializationGroup group = createSpecializationGroups(); + CodeTree execution = createGuardAndCast(group, genericType, locals, new SpecializationExecution() { + public CodeTree createExecute(SpecializationData specialization, LocalContext values) { + CodeTypeElement generatedType = specializationClasses.get(specialization); + if (generatedType == null) { + throw new AssertionError("No generated type for " + specialization); + } + return createSlowPathExecute(specialization, locals); + } + + public boolean isFastPath() { + return false; + } + }); + + builder.tree(execution); + + if (hasFallthrough(group, genericType, locals, false)) { + builder.returnNull(); + } + return method; + } + + private CodeExecutableElement createFallbackGuardMethod() { + boolean frameUsed = node.isFrameUsedByAnyGuard(context); + LocalContext locals = LocalContext.load(this); + + if (!frameUsed) { + locals.removeValue(FRAME_VALUE); + } + + CodeExecutableElement boundaryMethod = locals.createMethod(modifiers(PRIVATE), getType(boolean.class), "guardFallback", FRAME_VALUE); + if (!frameUsed) { + boundaryMethod.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(TruffleBoundary.class))); + } + + CodeTreeBuilder builder = boundaryMethod.createBuilder(); + builder.startReturn(); + builder.startCall("createNext"); + locals.addReferencesTo(builder, FRAME_VALUE); + builder.end(); + builder.string(" == null"); + builder.end(); + return boundaryMethod; + } + + private ExecutableElement createAccessChildMethod(NodeChildData child) { + if (child.getAccessElement() != null && child.getAccessElement().getModifiers().contains(Modifier.ABSTRACT)) { + ExecutableElement getter = (ExecutableElement) child.getAccessElement(); + CodeExecutableElement method = CodeExecutableElement.clone(context.getEnvironment(), getter); + method.getModifiers().remove(Modifier.ABSTRACT); + + List executions = new ArrayList<>(); + for (NodeExecutionData execution : node.getChildExecutions()) { + if (execution.getChild() == child) { + executions.add(execution); + } + } + + CodeTreeBuilder builder = method.createBuilder(); + if (child.getCardinality().isMany()) { + builder.startReturn().startNewArray((ArrayType) child.getOriginalType(), null); + for (NodeExecutionData execution : executions) { + builder.string(nodeFieldName(execution)); + } + builder.end().end(); + } else { + for (NodeExecutionData execution : executions) { + builder.startReturn().string("this.").string(nodeFieldName(execution)).end(); + break; + } + } + return method; + } + return null; + } + + private boolean isTypeBoxingEliminated(SpecializationData specialization) { + if (specialization.getMethod() == null) { + return false; + } + + TypeBoxingOptimization optimization = options.monomorphicTypeBoxingOptimization(); + if (isTypeBoxingOptimized(optimization, specialization.getReturnType().getTypeSystemType())) { + return true; + } + for (Parameter p : specialization.getSignatureParameters()) { + if (isTypeBoxingOptimized(optimization, p.getTypeSystemType())) { + return true; + } + } + return false; + + } + + private Set getEvaluatedCounts() { + Set evaluatedCount = new TreeSet<>(); + Collection returnSpecializedTypes = node.findSpecializedReturnTypes(); + for (ExecutableTypeData execType : node.getExecutableTypes()) { + if (shouldImplementExecutableType(returnSpecializedTypes, execType)) { + evaluatedCount.add(execType.getEvaluatedCount()); + } + } + return evaluatedCount; + } + + // create specialization + + private Element createUnsupported() { + SpecializationData fallback = node.getGenericSpecialization(); + if (fallback == null || optimizeFallback(fallback) || fallback.getMethod() == null) { + return null; + } + LocalContext locals = LocalContext.load(this); + + CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), genericType.getPrimitiveType(), "unsupported", FRAME_VALUE); + method.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); + + CodeTreeBuilder builder = method.createBuilder(); + builder.startReturn(); + builder.tree(callTemplateMethod(builder, accessParent(null), fallback, locals)); + builder.end(); + + return method; + } + + private boolean isSingleSpecializable(List reachableSpecializations) { + if (reachableSpecializations.size() != 1) { + return false; + } + return !reachableSpecializations.get(0).hasRewrite(context); + } + + private List getReachableSpecializations() { + List specializations = new ArrayList<>(); + for (SpecializationData specialization : node.getSpecializations()) { + if (specialization.isReachable() && // + (specialization.isSpecialized() // + || (specialization.isFallback() && optimizeFallback(specialization)))) { + specializations.add(specialization); + } + } + return specializations; + } + + private boolean optimizeFallback(SpecializationData specialization) { + switch (options.optimizeFallback()) { + case NEVER: + return false; + case DECLARED: + return specialization.getMethod() != null; + case ALWAYS: + return true; + default: + throw new AssertionError(); + } + } + + private CodeExecutableElement createExecutableTypeOverride(ExecutableTypeData execType) { + final String varArgsName = "args"; + final TypeData returnType = execType.getType(); + final TypeData executedType = execType.getEvaluatedCount() > 0 ? null : returnType; + + CodeExecutableElement method = cloneExecutableTypeOverride(execType, varArgsName); + + LocalContext locals = LocalContext.load(this, execType.getSignatureSize()); + + // rename varargs parameter + int signatureIndex = 0; + for (Parameter parameter : execType.getSignatureParameters()) { + if (parameter.isTypeVarArgs()) { + String newName = varArgsName + "[" + parameter.getTypeVarArgsIndex() + "]"; + NodeExecutionData execution = node.getChildExecutions().get(signatureIndex); + locals.setValue(execution, locals.getValue(execution).accessWith(CodeTreeBuilder.singleString(newName))); + } + signatureIndex++; + } + + CodeTreeBuilder builder = method.createBuilder(); + + // create acceptAndExecute + CodeTreeBuilder executeBuilder = builder.create(); + executeBuilder.startCall(specializationStartFieldName(), TypeSystemNodeFactory.executeName(executedType)); + Parameter frame = execType.getFrame(); + if (frame == null) { + executeBuilder.nullLiteral(); + } else { + executeBuilder.string(frame.getLocalName()); + } + locals.addReferencesTo(executeBuilder); + executeBuilder.end(); + + CodeTreeBuilder contentBuilder = builder.create(); + contentBuilder.startReturn(); + contentBuilder.tree(TypeSystemCodeGenerator.expect(executedType, returnType, executeBuilder.build())); + contentBuilder.end(); + + // try catch assert if unexpected value is not expected + if (!execType.hasUnexpectedValue(context) && !returnType.isGeneric() && !returnType.isVoid()) { + builder.startTryBlock(); + builder.tree(contentBuilder.build()); + builder.end().startCatchBlock(getType(UnexpectedResultException.class), "ex"); + builder.startThrow().startNew(getType(AssertionError.class)).end().end(); + builder.end(); + } else { + builder.tree(contentBuilder.build()); + } + + return method; + } + + private CodeExecutableElement cloneExecutableTypeOverride(ExecutableTypeData execType, final String varArgsName) throws AssertionError { + CodeExecutableElement method = CodeExecutableElement.clone(context.getEnvironment(), execType.getMethod()); + + method.getAnnotationMirrors().clear(); + method.getModifiers().remove(Modifier.ABSTRACT); + + if (!execType.getMethod().isVarArgs() && execType.getParameters().size() != method.getParameters().size()) { + throw new AssertionError("Should be verified in the parser"); + } + + // align argument names + int index = 0; + for (Parameter parameter : execType.getParameters()) { + CodeVariableElement var = (CodeVariableElement) method.getParameters().get(index); + if (parameter.isTypeVarArgs()) { + var.getAnnotationMirrors().clear(); + var.setName(varArgsName); + break; + } + var.setName(LocalVariable.fromParameter(parameter).createParameter().getName()); + var.getAnnotationMirrors().clear(); + index++; + } + return method; + } + + private boolean shouldImplementExecutableType(Collection specializedTypes, ExecutableTypeData execType) { + TypeData type = execType.getType(); + Set modifiers = execType.getMethod().getModifiers(); + if (modifiers.contains(FINAL) || modifiers.contains(STATIC) || modifiers.contains(PRIVATE)) { + return false; + } else if (execType.isAbstract()) { + return true; + } else if (type.isGeneric()) { + return true; + } else if (type.isVoid()) { + for (TypeData specializedType : specializedTypes) { + if (isTypeBoxingOptimized(options.voidBoxingOptimization(), specializedType)) { + return true; + } + } + return false; + } else if (!specializedTypes.contains(type)) { + return false; + } else if (!isTypeBoxingOptimized(options.monomorphicTypeBoxingOptimization(), type)) { + return false; + } + return true; + } + + private Element createMethodGetSpecializationNode() { + TypeMirror returntype = getType(SpecializationNode.class); + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), returntype, "getSpecializationNode"); + method.createBuilder().startReturn().string(specializationStartFieldName()).end(); + return method; + } + + private TypeMirror getType(Class clazz) { + return context.getType(clazz); + } + + private CodeVariableElement createNodeField(Modifier visibility, TypeMirror type, String name, Class annotationType) { + CodeVariableElement childField = new CodeVariableElement(modifiers(), type, name); + childField.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(annotationType))); + setVisibility(childField.getModifiers(), visibility); + return childField; + } + + private static List findSpecializedExecutables(NodeExecutionData execution, Collection types, TypeBoxingOptimization optimization) { + if (optimization == TypeBoxingOptimization.NONE) { + return Collections.emptyList(); + } + + List executables = new ArrayList<>(); + for (TypeData type : types) { + if (!isTypeBoxingOptimized(optimization, type)) { + continue; + } + ExecutableTypeData foundType = execution.getChild().getNodeData().findExecutableType(type, execution.getChild().getExecuteWith().size()); + if (foundType != null) { + executables.add(foundType); + } + } + return executables; + } + + private static CodeTree callTemplateMethod(CodeTreeBuilder parent, CodeTree receiver, TemplateMethod method, CodeTree... boundValues) { + CodeTreeBuilder builder = parent.create(); + if (method.getMethod().getModifiers().contains(STATIC)) { + builder.startStaticCall(method.getMethod().getEnclosingElement().asType(), method.getMethodName()); + } else { + builder.startCall(receiver, method.getMethodName()); + } + int index = -1; + for (Parameter parameter : method.getParameters()) { + index++; + if (index < boundValues.length) { + CodeTree tree = boundValues[index]; + if (tree != null) { + builder.tree(tree); + continue; + } + } + builder.string(parameter.getLocalName()); + } + builder.end(); + return builder.build(); + } + + private static CodeTree callTemplateMethod(CodeTreeBuilder parent, CodeTree receiver, TemplateMethod method, LocalContext currentValues) { + CodeTree[] bindings = new CodeTree[method.getParameters().size()]; + + int signatureIndex = 0; + for (int i = 0; i < bindings.length; i++) { + Parameter parameter = method.getParameters().get(i); + LocalVariable var = currentValues.get(parameter, signatureIndex); + if (var != null) { + CodeTree valueReference = bindings[i] = var.createReference(); + if (parameter.getTypeSystemType() != null && var.getType() != null && var.getType().needsCastTo(parameter.getTypeSystemType())) { + valueReference = TypeSystemCodeGenerator.cast(parameter.getTypeSystemType(), valueReference); + } + bindings[i] = valueReference; + } + if (parameter.getSpecification().isSignature()) { + signatureIndex++; + } + } + return callTemplateMethod(parent, receiver, method, bindings); + } + + private SpecializationGroup createSpecializationGroups() { + return SpecializationGroup.create(getReachableSpecializations()); + } + + private CodeTree createSlowPathExecute(SpecializationData specialization, LocalContext currentValues) { + CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); + if (specialization.isFallback()) { + return builder.returnNull().build(); + } + if (node.isFrameUsedByAnyGuard(context)) { + builder.tree(createTransferToInterpreterAndInvalidate()); + } + for (SpecializationData otherSpeciailzation : node.getSpecializations()) { + if (otherSpeciailzation == specialization) { + continue; + } + if (otherSpeciailzation.getExcludedBy().contains(specialization)) { + builder.startStatement(); + builder.tree(accessParent(excludedFieldName(otherSpeciailzation))); + builder.string(" = true"); + builder.end(); + } + } + + builder.startReturn().tree(createCallCreateMethod(specialization, null, currentValues)).end(); + + if (mayBeExcluded(specialization)) { + CodeTreeBuilder checkHasSeenBuilder = builder.create(); + checkHasSeenBuilder.startIf().string("!").tree(accessParent(excludedFieldName(specialization))).end().startBlock(); + checkHasSeenBuilder.tree(builder.build()); + checkHasSeenBuilder.end(); + return checkHasSeenBuilder.build(); + } + return builder.build(); + } + + private static boolean hasFallthrough(SpecializationGroup group, TypeData forType, LocalContext currentValues, boolean fastPath) { + for (TypeGuard guard : group.getTypeGuards()) { + if (currentValues.getValue(guard.getSignatureIndex()) == null) { + // not evaluated + return true; + } + LocalVariable value = currentValues.getValue(guard.getSignatureIndex()); + if (value.getType().needsCastTo(guard.getType())) { + return true; + } + } + + List expressions = new ArrayList<>(group.getGuards()); + expressions.removeAll(group.findElseConnectableGuards()); + if (!expressions.isEmpty()) { + return true; + } + + if ((!fastPath || forType.isGeneric()) && !group.getAssumptions().isEmpty()) { + return true; + } + + if (!fastPath && group.getSpecialization() != null && !group.getSpecialization().getExceptions().isEmpty()) { + return true; + } + + if (!group.getChildren().isEmpty()) { + return hasFallthrough(group.getChildren().get(group.getChildren().size() - 1), forType, currentValues, fastPath); + } + + return false; + } + + private Element createGetSuppliedChildren() { + ArrayType nodeArray = context.getEnvironment().getTypeUtils().getArrayType(getType(Node.class)); + + CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, FINAL), nodeArray, "getSuppliedChildren"); + method.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); + + CodeTreeBuilder builder = method.createBuilder(); + + builder.startReturn().startNewArray(nodeArray, null); + for (int i = 0; i < node.getChildExecutions().size(); i++) { + NodeExecutionData execution = node.getChildExecutions().get(i); + if (execution.isShortCircuit()) { + builder.nullLiteral(); + } + builder.tree(accessParent(nodeFieldName(execution))); + } + builder.end().end(); + + return method; + } + + // create specialization + + private CodeTree createCallCreateMethod(SpecializationData specialization, String rootName, LocalContext currentValues) { + CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); + + TypeMirror specializationType = specializationType(specialization); + if (options.useLazyClassLoading()) { + builder.startStaticCall(specializationType(specialization), "create"); + } else { + builder.startNew(specializationType); + } + if (rootName != null) { + builder.string(rootName); + } else { + builder.string("root"); + } + if (currentValues != null) { + for (Parameter p : specialization.getSignatureParameters()) { + LocalVariable local = currentValues.get(p.getLocalName()); + CodeVariableElement var = createImplicitProfileParameter(p.getSpecification().getExecution(), p.getTypeSystemType()); + if (var != null) { + builder.tree(local.createReference()); + } + } + } + builder.end(); + + return builder.build(); + } + + private Element createSpecializationCreateMethod(SpecializationData specialization, CodeExecutableElement constructor) { + if (!options.useLazyClassLoading()) { + return null; + } + + CodeExecutableElement executable = CodeExecutableElement.clone(context.getEnvironment(), constructor); + + TypeMirror specializationType = specializationType(specialization); + + executable.setReturnType(TypeSystemNodeFactory.nodeType(typeSystem)); + executable.setSimpleName(CodeNames.of("create")); + executable.getModifiers().add(STATIC); + + CodeTreeBuilder builder = executable.createBuilder(); + builder.startReturn().startNew(specializationType); + for (VariableElement parameter : executable.getParameters()) { + builder.string(parameter.getSimpleName().toString()); + } + builder.end().end(); + return executable; + } + + private static String implicitClassFieldName(NodeExecutionData execution) { + return execution.getName() + "ImplicitType"; + } + + private static String implicitNodeFieldName(NodeExecutionData execution) { + return execution.getName() + "Cast"; + } + + private CodeExecutableElement createSpecializationConstructor(CodeTypeElement clazz, SpecializationData specialization, String constantIndex) { + CodeExecutableElement constructor = new CodeExecutableElement(modifiers(), null, clazz.getSimpleName().toString()); + + constructor.addParameter(new CodeVariableElement(nodeType(node), "root")); + CodeTreeBuilder builder = constructor.createBuilder(); + + if (specialization == null) { + if (constantIndex == null) { + builder.statement("super(index)"); + constructor.addParameter(new CodeVariableElement(getType(int.class), "index")); + } else { + builder.startStatement().startSuperCall().string(constantIndex).end().end(); + } + builder.statement("this.root = root"); + } else { + int index = resolveSpecializationIndex(specialization); + builder.startStatement().startSuperCall().string("root").string(String.valueOf(index)).end().end(); + + for (Parameter p : specialization.getSignatureParameters()) { + NodeExecutionData execution = p.getSpecification().getExecution(); + + CodeVariableElement implicitProfile = createImplicitProfileParameter(execution, p.getTypeSystemType()); + if (implicitProfile != null) { + LocalVariable var = LocalVariable.fromParameter(p).makeGeneric(); + + String implicitFieldName = implicitProfile.getName(); + if (options.implicitCastOptimization().isDuplicateTail()) { + constructor.addParameter(var.createParameter()); + CodeTree implicitType = TypeSystemCodeGenerator.implicitType(p.getTypeSystemType(), var.createReference()); + builder.startStatement().string("this.").string(implicitFieldName).string(" = ").tree(implicitType).end(); + } else if (options.implicitCastOptimization().isMergeCasts()) { + // use node that supports polymorphism + constructor.addParameter(var.createParameter()); + builder.startStatement().string("this.").string(implicitFieldName).string(" = ").tree(ImplicitCastNodeFactory.create(p.getTypeSystemType(), var.createReference())).end(); + } else { + throw new AssertionError(); + } + } + } + } + + if (constructor.getParameters().isEmpty()) { + // do not generate default constructor + return null; + } + return constructor; + } + + // TODO this logic can be inlined to the parser as soon as the old NodeGen layout is gone + private static int resolveSpecializationIndex(SpecializationData specialization) { + if (specialization.isFallback()) { + return Integer.MAX_VALUE - 1; + } else if (specialization.isUninitialized()) { + return Integer.MAX_VALUE; + } else if (specialization.isPolymorphic()) { + return 0; + } else { + return specialization.getIndex(); + } + } + + private CodeTree createCallNext(TypeData forType, LocalContext currentValues) { + CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); + builder.startCall("next", TypeSystemNodeFactory.executeName(null)); + currentValues.addReferencesTo(builder, FRAME_VALUE); + builder.end(); + return TypeSystemCodeGenerator.expect(genericType, forType, builder.build()); + } + + private static CodeTree createCallDelegate(String methodName, String reason, TypeData forType, LocalContext currentValues) { + CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); + builder.startCall(methodName); + if (reason != null) { + builder.doubleQuote(reason); + } + currentValues.addReferencesTo(builder, FRAME_VALUE); + builder.end(); + + TypeData executedType = forType.getTypeSystem().getGenericTypeData(); + return TypeSystemCodeGenerator.expect(executedType, forType, builder.build()); + } + + private static ExecutableTypeData findSpecializedExecutableType(NodeExecutionData execution, TypeData type) { + NodeChildData child = execution.getChild(); + int executeWithCount = child.getExecuteWith().size(); + return child.getNodeData().findExecutableType(type, executeWithCount); + } + + private boolean hasUnexpectedResult(NodeExecutionData execution, TypeData type) { + if (type.isGeneric() || type.isVoid()) { + return false; + } + List executableTypes = new ArrayList<>(); + executableTypes.add(findSpecializedExecutableType(execution, type)); + + if (!options.implicitCastOptimization().isNone()) { + executableTypes.addAll(findSpecializedExecutables(execution, type.getImplicitSourceTypes(), options.implicitTypeBoxingOptimization())); + } + + for (ExecutableTypeData executableType : executableTypes) { + if (executableType != null && executableType.hasUnexpectedValue(context)) { + return true; + } + } + return false; + } + + private Element createFastPathExecuteMethod(SpecializationData specialization, final TypeData forType, int evaluatedArguments) { + TypeData type = forType == null ? genericType : forType; + LocalContext currentLocals = LocalContext.load(this, evaluatedArguments); + + CodeExecutableElement executable = currentLocals.createMethod(modifiers(PUBLIC), type.getPrimitiveType(), TypeSystemNodeFactory.executeName(forType), FRAME_VALUE); + executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); + + if (!type.isGeneric()) { + executable.getThrownTypes().add(getType(UnexpectedResultException.class)); + } + + CodeTreeBuilder builder = executable.createBuilder(); + + for (NodeExecutionData execution : node.getChildExecutions()) { + LocalVariable var = currentLocals.getValue(execution); + if (var == null) { + TypeData targetType; + if (specialization == null) { + targetType = genericType; + } else { + targetType = specialization.findParameterOrDie(execution).getTypeSystemType(); + } + LocalVariable shortCircuit = resolveShortCircuit(specialization, execution, currentLocals); + LocalVariable value = currentLocals.createValue(execution, targetType).nextName(); + builder.tree(createAssignExecuteChild(execution, type, value, shortCircuit, currentLocals)); + currentLocals.setValue(execution, value); + } + } + + LocalContext originalValues = currentLocals.copy(); + if (specialization == null) { + builder.startReturn().tree(createCallDelegate("acceptAndExecute", null, type, currentLocals)).end(); + } else if (specialization.isPolymorphic()) { + builder.startReturn().tree(createCallNext(type, currentLocals)).end(); + } else if (specialization.isUninitialized()) { + builder.startReturn().tree(createCallDelegate("uninitialized", null, type, currentLocals)).end(); + } else { + final TypeData type_ = type; + SpecializationGroup group = SpecializationGroup.create(specialization); + SpecializationExecution executionFactory = new SpecializationExecution() { + public CodeTree createExecute(SpecializationData s, LocalContext values) { + return createFastPathExecute(type_, s, values); + } + + public boolean isFastPath() { + return true; + } + }; + builder.tree(createGuardAndCast(group, type, currentLocals, executionFactory)); + if (hasFallthrough(group, type, originalValues, true) || group.getSpecialization().isFallback()) { + builder.startReturn().tree(createCallNext(type, originalValues)).end(); + } + } + + return executable; + } + + private LocalVariable resolveShortCircuit(SpecializationData specialization, NodeExecutionData execution, LocalContext currentLocals) { + LocalVariable shortCircuit = null; + SpecializationData resolvedSpecialization = specialization; + if (specialization == null) { + resolvedSpecialization = node.getGenericSpecialization(); + } + + if (execution.isShortCircuit()) { + ShortCircuitData shortCircuitData = resolvedSpecialization.getShortCircuits().get(calculateShortCircuitIndex(execution)); + CodeTree access = callTemplateMethod(CodeTreeBuilder.createBuilder(), accessParent(null), shortCircuitData, currentLocals); + shortCircuit = currentLocals.createShortCircuitValue(execution).accessWith(access); + } + return shortCircuit; + } + + private int calculateShortCircuitIndex(NodeExecutionData execution) { + int shortCircuitIndex = 0; + for (NodeExecutionData otherExectuion : node.getChildExecutions()) { + if (otherExectuion.isShortCircuit()) { + if (otherExectuion == execution) { + break; + } + shortCircuitIndex++; + } + } + return shortCircuitIndex; + } + + private CodeTree createFastPathExecute(final TypeData forType, SpecializationData specialization, LocalContext currentValues) { + CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); + int ifCount = 0; + if (specialization.isFallback()) { + builder.startIf().startCall("guardFallback"); + if (node.isFrameUsedByAnyGuard(context)) { + builder.string(FRAME_VALUE); + } + currentValues.addReferencesTo(builder); + + builder.end(); + builder.end(); + builder.startBlock(); + ifCount++; + } + CodeTreeBuilder execute = builder.create(); + execute.startReturn(); + if (specialization.getMethod() == null) { + execute.startCall("unsupported"); + currentValues.addReferencesTo(execute, FRAME_VALUE); + execute.end(); + } else { + execute.tree(callTemplateMethod(execute, accessParent(null), specialization, currentValues)); + } + execute.end(); + builder.tree(createFastPathTryCatchRewriteException(specialization, forType, currentValues, execute.build())); + + builder.end(ifCount); + return builder.build(); + } + + private CodeTree createGuardAndCast(SpecializationGroup group, TypeData forType, LocalContext currentValues, SpecializationExecution execution) { + CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); + + Set castGuards; + if (execution.isFastPath()) { + castGuards = null; // cast all + } else { + castGuards = new HashSet<>(); + for (TypeGuard castGuard : group.getTypeGuards()) { + if (isTypeGuardUsedInAnyGuardBelow(group, currentValues, castGuard)) { + castGuards.add(castGuard); + } + } + } + CodeTree[] checkAndCast = createTypeCheckAndCast(group.getTypeGuards(), castGuards, currentValues, execution); + CodeTree check = checkAndCast[0]; + CodeTree cast = checkAndCast[1]; + + List elseGuardExpressions = group.findElseConnectableGuards(); + List guardExpressions = new ArrayList<>(group.getGuards()); + guardExpressions.removeAll(elseGuardExpressions); + CodeTree methodGuards = createMethodGuardCheck(guardExpressions, currentValues); + + if (!group.getAssumptions().isEmpty()) { + if (execution.isFastPath() && !forType.isGeneric()) { + cast = appendAssumptionFastPath(cast, group.getAssumptions(), forType, currentValues); + } else { + methodGuards = appendAssumptionSlowPath(methodGuards, group.getAssumptions()); + } + } + + int ifCount = 0; + if (!check.isEmpty()) { + builder.startIf(); + builder.tree(check).end(); + builder.startBlock(); + ifCount++; + } + if (!cast.isEmpty()) { + builder.tree(cast); + } + boolean elseIf = !elseGuardExpressions.isEmpty(); + if (!methodGuards.isEmpty()) { + builder.startIf(elseIf); + builder.tree(methodGuards).end(); + builder.startBlock(); + ifCount++; + } else if (elseIf) { + builder.startElseBlock(); + ifCount++; + } + + boolean reachable = isReachableGroup(group, ifCount); + if (reachable) { + for (SpecializationGroup child : group.getChildren()) { + builder.tree(createGuardAndCast(child, forType, currentValues.copy(), execution)); + } + SpecializationData specialization = group.getSpecialization(); + if (specialization != null) { + builder.tree(execution.createExecute(specialization, currentValues)); + } + } + builder.end(ifCount); + + return builder.build(); + } + + private static CodeTree appendAssumptionSlowPath(CodeTree methodGuards, List assumptions) { + CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); + + builder.tree(methodGuards); + String connect = methodGuards.isEmpty() ? "" : " && "; + for (String assumption : assumptions) { + builder.string(connect); + builder.startCall(accessParent(assumptionName(assumption)), "isValid").end(); + connect = " && "; + } + + return builder.build(); + } + + private CodeTree appendAssumptionFastPath(CodeTree casts, List assumptions, TypeData forType, LocalContext currentValues) { + CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); + builder.tree(casts); + builder.startTryBlock(); + for (String assumption : assumptions) { + builder.startStatement().startCall(accessParent(assumptionName(assumption)), "check").end().end(); + } + builder.end().startCatchBlock(getType(InvalidAssumptionException.class), "ae"); + builder.startReturn().tree(createCallNext(forType, currentValues)).end(); + builder.end(); + return builder.build(); + } + + private static boolean isReachableGroup(SpecializationGroup group, int ifCount) { + if (ifCount != 0) { + return true; + } + SpecializationGroup previous = group.getPreviousGroup(); + if (previous == null || previous.findElseConnectableGuards().isEmpty()) { + return true; + } + + /* + * Hacky else case. In this case the specialization is not reachable due to previous else + * branch. This is only true if the minimum state is not checked. + */ + if (previous.getGuards().size() == 1 && previous.getTypeGuards().isEmpty() && previous.getAssumptions().isEmpty() && + (previous.getParent() == null || previous.getMaxSpecializationIndex() != previous.getParent().getMaxSpecializationIndex())) { + return false; + } + + return true; + } + + private boolean isTypeGuardUsedInAnyGuardBelow(SpecializationGroup group, LocalContext currentValues, TypeGuard typeGuard) { + NodeExecutionData execution = node.getChildExecutions().get(typeGuard.getSignatureIndex()); + + for (GuardExpression guard : group.getGuards()) { + List guardParameters = guard.getResolvedGuard().findByExecutionData(execution); + TypeData sourceType = currentValues.getValue(typeGuard.getSignatureIndex()).getType(); + + for (Parameter guardParameter : guardParameters) { + if (sourceType.needsCastTo(guardParameter.getType())) { + return true; + } + } + } + + for (SpecializationGroup child : group.getChildren()) { + if (isTypeGuardUsedInAnyGuardBelow(child, currentValues, typeGuard)) { + return true; + } + } + + return false; + } + + private CodeExecutableElement createExecuteChildMethod(NodeExecutionData execution, TypeData targetType) { + LocalContext locals = LocalContext.load(this, 0); + + CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), targetType.getPrimitiveType(), executeChildMethodName(execution, targetType), FRAME_VALUE); + if (hasUnexpectedResult(execution, targetType)) { + method.getThrownTypes().add(getType(UnexpectedResultException.class)); + } + + CodeVariableElement implicitProfile = createImplicitProfileParameter(execution, targetType); + if (implicitProfile != null) { + method.addParameter(implicitProfile); + } + + for (int i = 0; i < execution.getChild().getExecuteWith().size(); i++) { + NodeExecutionData executeWith = node.getChildExecutions().get(i); + LocalVariable var = locals.createValue(executeWith, genericType); + method.addParameter(var.createParameter()); + locals.setValue(executeWith, var); + } + + CodeTreeBuilder builder = method.createBuilder(); + CodeTree executeChild = createExecuteChild(execution, targetType, locals.createValue(execution, targetType), locals, true); + if (executeChild.isSingleLine()) { + builder.statement(executeChild); + } else { + builder.tree(executeChild); + } + return method; + } + + private CodeVariableElement createImplicitProfileParameter(NodeExecutionData execution, TypeData targetType) { + if (targetType.hasImplicitSourceTypes()) { + switch (options.implicitCastOptimization()) { + case NONE: + return null; + case DUPLICATE_TAIL: + return new CodeVariableElement(getType(Class.class), implicitClassFieldName(execution)); + case MERGE_CASTS: + return new CodeVariableElement(ImplicitCastNodeFactory.type(targetType), implicitNodeFieldName(execution)); + } + } + return null; + } + + private boolean isExecuteChildShared(NodeExecutionData execution, TypeData targetType) { + if (targetType.isVoid()) { + return false; + } else if (targetType.isGeneric()) { + if (isSingleSpecializable(getReachableSpecializations())) { + return false; + } + return findSpecializedExecutables(execution, node.findSpecializedTypes(execution), options.polymorphicTypeBoxingElimination()).size() >= 1; + } else { + if (!isTypeBoxingOptimized(options.monomorphicTypeBoxingOptimization(), targetType)) { + return false; + } + if (!targetType.hasImplicitSourceTypes()) { + return false; + } + + int uses = 0; + for (SpecializationData specialization : node.getSpecializations()) { + List parameters = specialization.findByExecutionData(execution); + for (Parameter parameter : parameters) { + if (targetType.equals(parameter.getTypeSystemType())) { + uses++; + } + } + } + if (uses > 1) { + return findSpecializedExecutables(execution, targetType.getImplicitSourceTypes(), options.implicitTypeBoxingOptimization()).size() > 1; + } else { + return false; + } + } + } + + private CodeTree createAssignExecuteChild(NodeExecutionData execution, TypeData returnType, LocalVariable targetValue, LocalVariable shortCircuit, LocalContext currentValues) { + CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); + boolean hasUnexpected = hasUnexpectedResult(execution, targetValue.getType()); + + CodeTree executeChild; + if (isExecuteChildShared(execution, targetValue.getType())) { + executeChild = createCallSharedExecuteChild(execution, targetValue, currentValues); + } else { + executeChild = createExecuteChild(execution, targetValue.getType(), targetValue, currentValues, false); + } + + builder.tree(createTryExecuteChild(targetValue, executeChild, shortCircuit == null, hasUnexpected)); + builder.end(); + if (hasUnexpected) { + builder.startCatchBlock(getType(UnexpectedResultException.class), "ex"); + + LocalContext slowPathValues = currentValues.copy(); + slowPathValues.setValue(execution, targetValue.makeGeneric().accessWith(CodeTreeBuilder.singleString("ex.getResult()"))); + boolean found = false; + for (NodeExecutionData otherExecution : node.getChildExecutions()) { + if (found) { + LocalVariable childEvaluatedValue = slowPathValues.createValue(otherExecution, genericType); + LocalVariable genericShortCircuit = resolveShortCircuit(null, otherExecution, slowPathValues); + builder.tree(createAssignExecuteChild(otherExecution, genericType, childEvaluatedValue, genericShortCircuit, slowPathValues)); + slowPathValues.setValue(otherExecution, childEvaluatedValue); + } else { + // skip forward already evaluated + found = execution == otherExecution; + } + } + builder.startReturn().tree(createCallNext(returnType, slowPathValues)).end(); + builder.end(); + } + + if (shortCircuit != null) { + currentValues.setShortCircuitValue(execution, shortCircuit.accessWith(null)); + } + return createShortCircuit(targetValue, shortCircuit, builder.build()); + } + + private static CodeTree createShortCircuit(LocalVariable targetValue, LocalVariable shortCircuitValue, CodeTree tryExecute) { + if (shortCircuitValue == null) { + return tryExecute; + } + + CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); + + builder.tree(shortCircuitValue.createDeclaration(shortCircuitValue.createReference())); + builder.tree(targetValue.createDeclaration(builder.create().defaultValue(targetValue.getTypeMirror()).build())); + + builder.startIf().string(shortCircuitValue.getName()).end().startBlock(); + builder.tree(tryExecute); + builder.end(); + + return builder.build(); + } + + private static CodeTree createTryExecuteChild(LocalVariable value, CodeTree executeChild, boolean needDeclaration, boolean hasTry) { + CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); + boolean hasDeclaration = false; + if ((hasTry || !executeChild.isSingleLine()) && needDeclaration) { + builder.tree(value.createDeclaration(null)); + hasDeclaration = true; + } + + if (hasTry) { + builder.startTryBlock(); + } else { + builder.startGroup(); + } + + if (executeChild.isSingleLine()) { + builder.startStatement(); + if (hasDeclaration || !needDeclaration) { + builder.tree(executeChild); + } else { + builder.type(value.getTypeMirror()).string(" ").tree(executeChild); + } + builder.end(); + } else { + builder.tree(executeChild); + } + + builder.end(); + + return builder.build(); + } + + private CodeTree createCallSharedExecuteChild(NodeExecutionData execution, LocalVariable targetValue, LocalContext currentValues) { + if (!isExecuteChildShared(execution, targetValue.getType())) { + throw new AssertionError("Execute child not shared with method but called."); + } + + CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); + builder.tree(targetValue.createReference()).string(" = "); + if (targetValue.getType().isGeneric()) { + builder.startCall("root", executeChildMethodName(execution, targetValue.getType())); + } else { + builder.startCall(executeChildMethodName(execution, targetValue.getType())); + } + builder.string(FRAME_VALUE); + + CodeVariableElement implicitProfile = createImplicitProfileParameter(execution, targetValue.getType()); + if (implicitProfile != null) { + builder.string(implicitProfile.getName()); + } + for (int i = 0; i < execution.getChild().getExecuteWith().size(); i++) { + builder.tree(currentValues.getValue(i).createReference()); + } + builder.end(); + return builder.build(); + } + + private CodeTree createExecuteChild(NodeExecutionData execution, TypeData returnType, LocalVariable target, LocalContext currentValues, boolean shared) { + final CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); + final ExecutableTypeData executableType = findSpecializedExecutableType(execution, target.getType()); + + CodeTree assignment = createAssignmentStart(target, shared, false); + + if (executableType == null) { + if (target.getType().isGeneric()) { + throw new AssertionError("Should be caught by the parser."); + } + CodeTree genericExecute = createExecuteChild(execution, returnType, target.makeGeneric(), currentValues, shared); + builder.tree(genericExecute); + } else { + if (target.getType().isGeneric() && executableType.getEvaluatedCount() == 0) { + return createPolymorphicExecuteChild(execution, target, currentValues, shared); + } else if (target.getType().hasImplicitSourceTypes()) { + if (options.implicitCastOptimization().isNone()) { + CodeTree execute = createCallSharedExecuteChild(execution, target.makeGeneric(), currentValues); + return TypeSystemCodeGenerator.implicitExpect(target.getType(), execute, null); + } else if (options.implicitCastOptimization().isDuplicateTail()) { + builder.tree(createExecuteChildDuplicateTail(builder, execution, assignment, target, currentValues)); + } else if (options.implicitCastOptimization().isMergeCasts()) { + // TODO + } else { + throw new AssertionError(); + } + } else { + builder.tree(assignment); + + CodeTree accessChild; + if (shared && target.getType().isGeneric()) { + accessChild = CodeTreeBuilder.singleString(nodeFieldName(execution)); + } else { + accessChild = accessParent(nodeFieldName(execution)); + } + + CodeTree execute = callTemplateMethod(builder, accessChild, executableType, currentValues); + CodeTree expect = TypeSystemCodeGenerator.expect(executableType.getType(), returnType, execute); + builder.tree(expect); + } + } + return builder.build(); + } + + private CodeTree createPolymorphicExecuteChild(NodeExecutionData execution, LocalVariable target, LocalContext currentValues, boolean shared) throws AssertionError { + ExecutableTypeData genericExecutableType = execution.getChild().getNodeData().findAnyGenericExecutableType(context, execution.getChild().getExecuteWith().size()); + if (genericExecutableType == null) { + throw new AssertionError("error should be caught by the parser"); + } + + CodeTree assignment = createAssignmentStart(target, shared, true); + + CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); + CodeTreeBuilder polyChainBuilder = builder.create(); + boolean hasUnexpectedResult = false; + + Set specializedTypes = new HashSet<>(); + for (TypeData type : node.findSpecializedTypes(execution)) { + specializedTypes.addAll(type.getImplicitSourceTypes()); + } + + List specializedExecutables = findSpecializedExecutables(execution, specializedTypes, options.polymorphicTypeBoxingElimination()); + + Collections.sort(specializedExecutables, new Comparator() { + public int compare(ExecutableTypeData o1, ExecutableTypeData o2) { + return o1.getType().compareTo(o2.getType()); + } + }); + + if (isSingleSpecializable(getReachableSpecializations())) { + specializedExecutables = Collections.emptyList(); + } + + boolean hasSpecializedTypes = false; + for (ExecutableTypeData executableType : specializedExecutables) { + hasSpecializedTypes = polyChainBuilder.startIf(hasSpecializedTypes); + polyChainBuilder.tree(createAccessPolymorphicField(execution, shared)); + polyChainBuilder.string(" == ").typeLiteral(executableType.getType().getPrimitiveType()); + polyChainBuilder.end(); + polyChainBuilder.startBlock(); + polyChainBuilder.startStatement(); + polyChainBuilder.tree(assignment); + polyChainBuilder.tree(callTemplateMethod(polyChainBuilder, CodeTreeBuilder.singleString(nodeFieldName(execution)), executableType, currentValues)).end(); + polyChainBuilder.end(); + hasUnexpectedResult |= executableType.hasUnexpectedValue(context); + } + + CodeTree executeGeneric = callTemplateMethod(polyChainBuilder, CodeTreeBuilder.singleString(nodeFieldName(execution)), genericExecutableType, currentValues); + + if (specializedExecutables.isEmpty()) { + builder.tree(assignment); + builder.tree(executeGeneric); + } else { + CodeTree accessPolymorphicProfile = createAccessPolymorphicField(execution, shared); + polyChainBuilder.startElseIf().tree(accessPolymorphicProfile).string(" == null").end(); + polyChainBuilder.startBlock(); + polyChainBuilder.tree(createTransferToInterpreterAndInvalidate()); + polyChainBuilder.declaration(genericExecutableType.getType().getPrimitiveType(), "value_", executeGeneric); + + hasSpecializedTypes = false; + for (ExecutableTypeData executableType : specializedExecutables) { + hasSpecializedTypes = polyChainBuilder.startIf(hasSpecializedTypes); + polyChainBuilder.tree(TypeSystemCodeGenerator.check(executableType.getType(), CodeTreeBuilder.singleString("value_"))); + polyChainBuilder.end(); + polyChainBuilder.startBlock(); + polyChainBuilder.startStatement().tree(accessPolymorphicProfile).string(" = ").typeLiteral(executableType.getType().getPrimitiveType()).end(); + polyChainBuilder.end(); + } + + polyChainBuilder.startElseBlock(); + polyChainBuilder.startStatement().tree(accessPolymorphicProfile).string(" = ").typeLiteral(genericType.getPrimitiveType()).end(); + polyChainBuilder.end(); + + polyChainBuilder.startReturn().string("value_").end(); + + polyChainBuilder.end(); + polyChainBuilder.startElseBlock(); + polyChainBuilder.startStatement().tree(assignment).tree(executeGeneric).end(); + polyChainBuilder.end(); + + if (hasUnexpectedResult) { + builder.startTryBlock(); + } + + builder.tree(polyChainBuilder.build()); + + if (hasUnexpectedResult) { + builder.end(); + builder.startCatchBlock(getType(UnexpectedResultException.class), "ex"); + builder.startStatement().tree(accessPolymorphicProfile).string(" = ").typeLiteral(genericType.getPrimitiveType()).end(); + builder.startReturn().string("ex.getResult()").end(); + builder.end(); + } + } + return builder.build(); + } + + private static CodeTree createAssignmentStart(LocalVariable target, boolean shared, boolean accessParent) { + CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); + if (shared) { + builder.string("return "); + } else { + builder.string(target.getName()).string(" = "); + if (accessParent) { + builder.tree(accessParent(null)).string("."); + } + } + return builder.build(); + } + + private static CodeTree createAccessPolymorphicField(NodeExecutionData execution, boolean shared) { + String name = polymorphicTypeProfileFieldName(execution); + if (shared) { + return CodeTreeBuilder.singleString(name); + } else { + return accessParent(name); + } + } + + private CodeTree createExecuteChildDuplicateTail(CodeTreeBuilder parent, NodeExecutionData execution, CodeTree assignment, LocalVariable target, LocalContext currentValues) { + CodeTreeBuilder builder = parent.create(); + List sourceTypes = target.getType().getImplicitSourceTypes(); + String implicitClassFieldName = implicitClassFieldName(execution); + String nodeFieldName = nodeFieldName(execution); + List executableTypes = findSpecializedExecutables(execution, sourceTypes, options.implicitTypeBoxingOptimization()); + + boolean elseIf = false; + for (ExecutableTypeData executableType : executableTypes) { + elseIf = builder.startIf(elseIf); + builder.string(implicitClassFieldName).string(" == ").typeLiteral(executableType.getType().getBoxedType()); + builder.end(); + builder.startBlock(); + builder.startStatement().tree(assignment); + + CodeTree execute = callTemplateMethod(builder, accessParent(nodeFieldName), executableType, currentValues); + ImplicitCastData cast = typeSystem.lookupCast(executableType.getType(), target.getType()); + if (cast != null) { + execute = callTemplateMethod(builder, null, cast, execute); + } + builder.tree(execute); + builder.end(); + builder.end(); + } + + if (!executableTypes.isEmpty()) { + builder.startElseBlock(); + } + + LocalVariable genericValue = target.makeGeneric().nextName(); + LocalVariable genericShortCircuit = resolveShortCircuit(null, execution, currentValues); + + builder.tree(createAssignExecuteChild(execution, genericValue.getType(), genericValue, genericShortCircuit, currentValues)); + if (executableTypes.size() == sourceTypes.size()) { + builder.startThrow().startNew(getType(UnexpectedResultException.class)).tree(genericValue.createReference()).end().end(); + } else { + builder.startStatement().tree(assignment); + builder.tree(TypeSystemCodeGenerator.implicitExpect(target.getType(), genericValue.createReference(), implicitClassFieldName)); + builder.end(); + } + + if (!executableTypes.isEmpty()) { + builder.end(); + } + return builder.build(); + } + + private static CodeTree createFastPathTryCatchRewriteException(SpecializationData specialization, TypeData forType, LocalContext currentValues, CodeTree execution) { + if (specialization.getExceptions().isEmpty()) { + return execution; + } + CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); + builder.startTryBlock(); + builder.tree(execution); + TypeMirror[] exceptionTypes = new TypeMirror[specialization.getExceptions().size()]; + for (int i = 0; i < exceptionTypes.length; i++) { + exceptionTypes[i] = specialization.getExceptions().get(i).getJavaClass(); + } + builder.end().startCatchBlock(exceptionTypes, "ex"); + builder.startStatement().tree(accessParent(excludedFieldName(specialization))).string(" = true").end(); + builder.startReturn(); + builder.tree(createCallDelegate("remove", "threw rewrite exception", forType, currentValues)); + builder.end(); + builder.end(); + return builder.build(); + } + + private static CodeTree createMethodGuardCheck(List guardExpressions, LocalContext currentValues) { + CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); + String and = ""; + for (GuardExpression guard : guardExpressions) { + builder.string(and); + if (guard.isNegated()) { + builder.string("!"); + } + builder.tree(callTemplateMethod(builder, accessParent(null), guard.getResolvedGuard(), currentValues)); + and = " && "; + } + return builder.build(); + } + + private CodeTree[] createTypeCheckAndCast(List typeGuards, Set castGuards, LocalContext currentValues, SpecializationExecution specializationExecution) { + CodeTreeBuilder checksBuilder = CodeTreeBuilder.createBuilder(); + CodeTreeBuilder castsBuilder = CodeTreeBuilder.createBuilder(); + for (TypeGuard typeGuard : typeGuards) { + int signatureIndex = typeGuard.getSignatureIndex(); + LocalVariable value = currentValues.getValue(signatureIndex); + TypeData targetType = typeGuard.getType(); + if (!value.getType().needsCastTo(targetType)) { + continue; + } + NodeExecutionData execution = node.getChildExecutions().get(signatureIndex); + if (!checksBuilder.isEmpty()) { + checksBuilder.string(" && "); + } + + CodeTreeBuilder checkBuilder = checksBuilder.create(); + CodeTreeBuilder castBuilder = checksBuilder.create(); + + LocalVariable shortCircuit = currentValues.getShortCircuit(execution); + if (shortCircuit != null) { + checkBuilder.string("("); + CodeTreeBuilder referenceBuilder = checkBuilder.create(); + if (!shortCircuit.getType().isPrimitive()) { + referenceBuilder.string("(boolean) "); + } + referenceBuilder.tree(shortCircuit.createReference()); + checkBuilder.string("!").tree(referenceBuilder.build()); + checkBuilder.string(" || "); + castBuilder.tree(referenceBuilder.build()).string(" ? "); + } + + List sourceTypes = typeSystem.lookupByTargetType(targetType); + CodeTree valueReference = value.createReference(); + if (sourceTypes.isEmpty()) { + checkBuilder.tree(TypeSystemCodeGenerator.check(targetType, value.createReference())); + castBuilder.tree(TypeSystemCodeGenerator.cast(targetType, valueReference)); + } else { + ImplicitCastOptimization opt = options.implicitCastOptimization(); + if (specializationExecution.isFastPath() && !opt.isNone()) { + if (opt.isDuplicateTail()) { + String typeHintField = implicitClassFieldName(execution); + checkBuilder.tree(TypeSystemCodeGenerator.implicitCheck(targetType, valueReference, typeHintField)); + castBuilder.tree(TypeSystemCodeGenerator.implicitCast(targetType, valueReference, typeHintField)); + } else if (opt.isMergeCasts()) { + checkBuilder.tree(ImplicitCastNodeFactory.check(implicitNodeFieldName(execution), valueReference)); + castBuilder.tree(ImplicitCastNodeFactory.cast(implicitNodeFieldName(execution), valueReference)); + } else { + throw new AssertionError("implicit cast opt"); + } + } else { + checkBuilder.tree(TypeSystemCodeGenerator.implicitCheck(targetType, valueReference, null)); + castBuilder.tree(TypeSystemCodeGenerator.implicitCast(targetType, valueReference, null)); + } + } + + if (shortCircuit != null) { + checkBuilder.string(")"); + castBuilder.string(" : ").defaultValue(targetType.getPrimitiveType()); + } + + if (castGuards == null || castGuards.contains(typeGuard)) { + LocalVariable castVariable = currentValues.getValue(execution).nextName().newType(typeGuard.getType()).accessWith(null); + currentValues.setValue(execution, castVariable); + castsBuilder.tree(castVariable.createDeclaration(castBuilder.build())); + } + + checksBuilder.tree(checkBuilder.build()); + } + return new CodeTree[]{checksBuilder.build(), castsBuilder.build()}; + } + + public static final class LocalContext { + + private final NodeGenFactory factory; + private final Map values = new HashMap<>(); + + private LocalContext(NodeGenFactory factory) { + this.factory = factory; + } + + public CodeExecutableElement createMethod(Set modifiers, TypeMirror returnType, String name, String... optionalArguments) { + CodeExecutableElement method = new CodeExecutableElement(modifiers, returnType, name); + addParametersTo(method, optionalArguments); + return method; + } + + public static LocalContext load(NodeGenFactory factory, int signatureSize) { + LocalContext context = new LocalContext(factory); + context.loadValues(signatureSize); + return context; + } + + public static LocalContext load(NodeGenFactory factory) { + return load(factory, factory.node.getSignatureSize()); + } + + public LocalContext copy() { + LocalContext copy = new LocalContext(factory); + copy.values.putAll(values); + return copy; + } + + private static String fieldValueName(NodeFieldData field) { + return field.getName() + "Value"; + } + + @SuppressWarnings("static-method") + public LocalVariable createValue(NodeExecutionData execution, TypeData type) { + return new LocalVariable(type, type.getPrimitiveType(), valueName(execution), null); + } + + public LocalVariable createShortCircuitValue(NodeExecutionData execution) { + return new LocalVariable(factory.typeSystem.getBooleanType(), factory.getType(boolean.class), shortCircuitName(execution), null); + } + + private static String valueName(NodeExecutionData execution) { + return execution.getName() + "Value"; + } + + private static String shortCircuitName(NodeExecutionData execution) { + return "has" + ElementUtils.firstLetterUpperCase(valueName(execution)); + } + + public LocalVariable get(String id) { + return values.get(id); + } + + public LocalVariable get(Parameter parameter, int signatureIndex) { + LocalVariable var = get(parameter.getLocalName()); + if (var == null && parameter.getSpecification().isSignature()) { + // lookup by signature index for executeWith + NodeExecutionData execution = factory.node.getChildExecutions().get(signatureIndex); + var = getValue(execution); + } + return var; + } + + public LocalVariable getValue(NodeExecutionData execution) { + return get(valueName(execution)); + } + + public LocalVariable getValue(int signatureIndex) { + return getValue(factory.node.getChildExecutions().get(signatureIndex)); + } + + public void removeValue(String id) { + values.remove(id); + } + + public void setValue(NodeExecutionData execution, LocalVariable var) { + values.put(valueName(execution), var); + } + + public void setShortCircuitValue(NodeExecutionData execution, LocalVariable var) { + if (var == null) { + return; + } + values.put(shortCircuitName(execution), var); + } + + private boolean needsVarargs(boolean requireLoaded) { + int size = 0; + for (NodeExecutionData execution : factory.node.getChildExecutions()) { + if (requireLoaded && getValue(execution) == null) { + continue; + } + if (execution.isShortCircuit()) { + size += 2; + } else { + size++; + } + } + return size > 4; + } + + private void loadValues(int evaluatedArguments) { + values.put(FRAME_VALUE, new LocalVariable(null, factory.getType(VirtualFrame.class), FRAME_VALUE, null)); + + for (NodeFieldData field : factory.node.getFields()) { + String fieldName = fieldValueName(field); + values.put(fieldName, new LocalVariable(null, field.getType(), fieldName, NodeGenFactory.accessParent(field.getName()))); + } + + boolean varargs = needsVarargs(false); + for (int i = 0; i < evaluatedArguments; i++) { + NodeExecutionData execution = factory.node.getChildExecutions().get(i); + if (execution.isShortCircuit()) { + LocalVariable shortCircuit = createShortCircuitValue(execution).makeGeneric(); + if (varargs) { + shortCircuit = shortCircuit.accessWith(createReadVarargs(i)); + } + values.put(shortCircuit.getName(), shortCircuit); + } + LocalVariable value = createValue(execution, factory.genericType); + if (varargs) { + value = value.accessWith(createReadVarargs(i)); + } + values.put(value.getName(), value); + } + } + + private static CodeTree createReadVarargs(int i) { + return CodeTreeBuilder.createBuilder().string("args_[").string(String.valueOf(i)).string("]").build(); + } + + public void addReferencesTo(CodeTreeBuilder builder, String... optionalNames) { + for (String var : optionalNames) { + LocalVariable local = values.get(var); + if (local == null) { + builder.nullLiteral(); + } else { + builder.tree(local.createReference()); + } + } + + List executions = factory.node.getChildExecutions(); + for (NodeExecutionData execution : executions) { + if (execution.isShortCircuit()) { + LocalVariable shortCircuitVar = getShortCircuit(execution); + if (shortCircuitVar != null) { + builder.tree(shortCircuitVar.createReference()); + } + } + LocalVariable var = getValue(execution); + if (var != null) { + builder.startGroup(); + if (executions.size() == 1 && ElementUtils.typeEquals(var.getTypeMirror(), factory.getType(Object[].class))) { + // if the current type is Object[] do not use varargs for a single argument + builder.string("(Object) "); + } + builder.tree(var.createReference()); + builder.end(); + } + } + } + + public void addParametersTo(CodeExecutableElement method, String... optionalNames) { + for (String var : optionalNames) { + LocalVariable local = values.get(var); + if (local != null) { + method.addParameter(local.createParameter()); + } + } + if (needsVarargs(true)) { + method.addParameter(new CodeVariableElement(factory.getType(Object[].class), "args_")); + method.setVarArgs(true); + } else { + for (NodeExecutionData execution : factory.node.getChildExecutions()) { + if (execution.isShortCircuit()) { + LocalVariable shortCircuitVar = getShortCircuit(execution); + if (shortCircuitVar != null) { + method.addParameter(shortCircuitVar.createParameter()); + } + } + + LocalVariable var = getValue(execution); + if (var != null) { + method.addParameter(var.createParameter()); + } + } + } + } + + private LocalVariable getShortCircuit(NodeExecutionData execution) { + return values.get(shortCircuitName(execution)); + } + + } + + public final static class LocalVariable { + + private final TypeData type; + private final TypeMirror typeMirror; + private final CodeTree accessorTree; + private final String name; + + public static LocalVariable fromParameter(Parameter parameter) { + NodeExecutionData execution = parameter.getSpecification().getExecution(); + String name = null; + if (execution == null) { + name = parameter.getLocalName(); + } else { + name = createName(execution); + } + return new LocalVariable(parameter.getTypeSystemType(), parameter.getType(), name, null); + } + + private LocalVariable(TypeData type, TypeMirror typeMirror, String name, CodeTree accessorTree) { + Objects.requireNonNull(typeMirror); + this.typeMirror = typeMirror; + this.accessorTree = accessorTree; + this.type = type; + this.name = name; + } + + public TypeData getType() { + return type; + } + + public String getShortCircuitName() { + return "has" + ElementUtils.firstLetterUpperCase(getName()); + } + + public String getName() { + return name; + } + + private static String createNextName(String name) { + return name + "_"; + } + + private static String createName(NodeExecutionData execution) { + if (execution == null) { + return ""; + } + return execution.getName() + "Value"; + } + + public TypeMirror getTypeMirror() { + return typeMirror; + } + + public CodeVariableElement createParameter() { + return new CodeVariableElement(getTypeMirror(), getName()); + } + + public CodeTree createDeclaration(CodeTree init) { + return CodeTreeBuilder.createBuilder().declaration(getTypeMirror(), getName(), init).build(); + } + + public CodeTree createReference() { + if (accessorTree != null) { + return accessorTree; + } else { + return CodeTreeBuilder.singleString(getName()); + } + } + + public LocalVariable newType(TypeData newType) { + return new LocalVariable(newType, newType.getPrimitiveType(), name, accessorTree); + } + + public final LocalVariable accessWith(CodeTree tree) { + return new LocalVariable(type, typeMirror, name, tree); + } + + public final LocalVariable nextName() { + return new LocalVariable(type, typeMirror, createNextName(name), accessorTree); + } + + public final LocalVariable makeGeneric() { + return newType(type.getTypeSystem().getGenericTypeData()); + } + + } + + private interface SpecializationExecution { + + boolean isFastPath(); + + CodeTree createExecute(SpecializationData specialization, LocalContext currentValues); + + } + +} diff -r 6fa3999631d8 -r a665483c3881 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/PolymorphicNodeFactory.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/PolymorphicNodeFactory.java Mon Dec 29 23:38:50 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/PolymorphicNodeFactory.java Mon Dec 29 23:38:54 2014 +0100 @@ -46,7 +46,7 @@ if (nodeGen != null) { baseType = nodeGen.asType(); } - CodeTypeElement clazz = GeneratorUtils.createClass(node, modifiers(PRIVATE, FINAL), nodePolymorphicClassName(node), baseType, false); + CodeTypeElement clazz = GeneratorUtils.createClass(node, null, modifiers(PRIVATE, FINAL), nodePolymorphicClassName(node), baseType); clazz.getAnnotationMirrors().add(createNodeInfo(NodeCost.POLYMORPHIC)); diff -r 6fa3999631d8 -r a665483c3881 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/SpecializedNodeFactory.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/SpecializedNodeFactory.java Mon Dec 29 23:38:50 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/SpecializedNodeFactory.java Mon Dec 29 23:38:54 2014 +0100 @@ -54,7 +54,7 @@ if (nodeGen != null) { baseType = nodeGen.asType(); } - CodeTypeElement clazz = GeneratorUtils.createClass(node, modifiers(PRIVATE, FINAL), nodeSpecializationClassName(specialization), baseType, false); + CodeTypeElement clazz = GeneratorUtils.createClass(node, null, modifiers(PRIVATE, FINAL), nodeSpecializationClassName(specialization), baseType); if (specialization.isSpecialized() || specialization.isUninitialized()) { clazz.add(createGetMetadata0(false)); @@ -62,7 +62,7 @@ } NodeCost cost; - if (specialization.isGeneric()) { + if (specialization.isFallback()) { cost = NodeCost.MEGAMORPHIC; } else if (specialization.isUninitialized()) { cost = NodeCost.UNINITIALIZED; @@ -162,7 +162,7 @@ builder.end(); } - return builder.getRoot(); + return builder.build(); } private CodeTree createSpecializationListLiteral(CodeTreeBuilder parent, Set list) { @@ -175,7 +175,7 @@ builder.startNewArray(classArray, null); for (SpecializationData current : list) { SpecializationData s = current; - if (s.isGeneric() || s.isPolymorphic()) { + if (s.isFallback() || s.isPolymorphic()) { s = getSpecialization().getNode().getUninitializedSpecialization(); } builder.startGroup().string(nodeSpecializationClassName(s)).string(".class").end(); @@ -183,7 +183,7 @@ builder.end(); } - return builder.getRoot(); + return builder.build(); } protected CodeAnnotationMirror createNodeInfo(NodeCost cost) { @@ -295,7 +295,7 @@ public CodeTree create(CodeTreeBuilder b, SpecializationData current) { return createGenericInvoke(b, polymorphic, current); } - }, elseBuilder.getRoot(), false, true, true, false)); + }, elseBuilder.build(), false, true, true, false)); } clazz.add(executeMethod); } @@ -309,7 +309,7 @@ } else { builder.tree(createDeoptimize(builder)); } - return builder.getRoot(); + return builder.build(); } private CodeTree createExecuteBody(CodeTreeBuilder parent, ExecutableTypeData execType, List primaryExecutes) { @@ -324,7 +324,7 @@ return null; } - return builder.getRoot(); + return builder.build(); } private CodeExecutableElement createExecutableTypeOverride(ExecutableTypeData execType, boolean evaluated) { @@ -444,7 +444,7 @@ CodeTreeBuilder returnBuilder = new CodeTreeBuilder(builder); returnBuilder.tree(createDeoptimize(builder)); returnBuilder.tree(createCallRewriteMonomorphic(builder, executable.hasUnexpectedValue(context), executable.getType(), null, "One of guards " + specialization.getGuards() + " failed")); - returnSpecialized = returnBuilder.getRoot(); + returnSpecialized = returnBuilder.build(); } builder.tree(createExecuteTree(builder, specialization, SpecializationGroup.create(specialization), new CodeBlock() { @@ -454,7 +454,7 @@ } }, returnSpecialized, false, false, false, false)); - return builder.getRoot(); + return builder.build(); } private CodeTree createExecute(CodeTreeBuilder parent, ExecutableTypeData executable) { @@ -490,17 +490,17 @@ builder.startReturn(); if (targetType == null || sourceType == null) { - builder.tree(returnBuilder.getRoot()); + builder.tree(returnBuilder.build()); } else if (sourceType.needsCastTo(targetType)) { CodeTree cast; if (executable.hasUnexpectedValue(context)) { - cast = TypeSystemCodeGenerator.expect(targetType, returnBuilder.getRoot()); + cast = TypeSystemCodeGenerator.expect(targetType, returnBuilder.build()); } else { - cast = TypeSystemCodeGenerator.cast(targetType, returnBuilder.getRoot()); + cast = TypeSystemCodeGenerator.cast(targetType, returnBuilder.build()); } builder.tree(cast); } else { - builder.tree(returnBuilder.getRoot()); + builder.tree(returnBuilder.build()); } builder.end(); } @@ -519,7 +519,7 @@ builder.end(); } - return builder.getRoot(); + return builder.build(); } private CodeExecutableElement createCopyConstructorFactoryMethod(CodeTypeElement clazz, TypeMirror baseType) { diff -r 6fa3999631d8 -r a665483c3881 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/TypeSystemCodeGenerator.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/TypeSystemCodeGenerator.java Mon Dec 29 23:38:50 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/TypeSystemCodeGenerator.java Mon Dec 29 23:38:54 2014 +0100 @@ -23,12 +23,14 @@ package com.oracle.truffle.dsl.processor.generator; import static com.oracle.truffle.dsl.processor.java.ElementUtils.*; +import static com.oracle.truffle.dsl.processor.generator.GeneratorUtils.*; import static javax.lang.model.element.Modifier.*; import java.util.*; import javax.lang.model.type.*; +import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.dsl.processor.*; import com.oracle.truffle.dsl.processor.java.*; import com.oracle.truffle.dsl.processor.java.model.*; @@ -40,15 +42,15 @@ return cast(type, CodeTreeBuilder.singleString(content)); } - public static CodeTree implicitType(TypeData type, String valueName) { + public static CodeTree implicitType(TypeData type, CodeTree value) { if (type.isGeneric()) { - return CodeTreeBuilder.singleString(valueName); + return value; } CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); TypeSystemData typeSystem = type.getTypeSystem(); - builder.startStaticCall(createTypeSystemGen(typeSystem), getImplicitClass(type)).string(valueName); + builder.startStaticCall(createTypeSystemGen(typeSystem), getImplicitClass(type)).tree(value); builder.end(); - return builder.getRoot(); + return builder.build(); } public static CodeTree invokeImplicitCast(ImplicitCastData cast, CodeTree expression) { @@ -56,35 +58,49 @@ TypeSystemData typeSystem = cast.getTargetType().getTypeSystem(); builder.startStaticCall(createTypeSystemGen(typeSystem), cast.getMethodName()).tree(expression); builder.end(); - return builder.getRoot(); + return builder.build(); } - public static CodeTree implicitCheck(TypeData type, String valueName, String typeHint) { + public static CodeTree implicitCheck(TypeData type, CodeTree value, String typeHint) { if (type.isGeneric()) { - return CodeTreeBuilder.singleString(valueName); + return value; } CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); TypeSystemData typeSystem = type.getTypeSystem(); - builder.startStaticCall(createTypeSystemGen(typeSystem), isImplicitTypeMethodName(type)).string(valueName); + builder.startStaticCall(createTypeSystemGen(typeSystem), isImplicitTypeMethodName(type)).tree(value); if (typeHint != null) { builder.string(typeHint); } builder.end(); - return builder.getRoot(); + return builder.build(); } - public static CodeTree implicitCast(TypeData type, String valueName, String typeHint) { + public static CodeTree implicitExpect(TypeData type, CodeTree value, String typeHint) { if (type.isGeneric()) { - return CodeTreeBuilder.singleString(valueName); + return value; } CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); TypeSystemData typeSystem = type.getTypeSystem(); - builder.startStaticCall(createTypeSystemGen(typeSystem), asImplicitTypeMethodName(type)).string(valueName); + builder.startStaticCall(createTypeSystemGen(typeSystem), expectImplicitTypeMethodName(type)).tree(value); if (typeHint != null) { builder.string(typeHint); } builder.end(); - return builder.getRoot(); + return builder.build(); + } + + public static CodeTree implicitCast(TypeData type, CodeTree value, String typeHint) { + if (type.isGeneric()) { + return value; + } + CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); + TypeSystemData typeSystem = type.getTypeSystem(); + builder.startStaticCall(createTypeSystemGen(typeSystem), asImplicitTypeMethodName(type)).tree(value); + if (typeHint != null) { + builder.string(typeHint); + } + builder.end(); + return builder.build(); } public static CodeTree cast(TypeData type, CodeTree content) { @@ -99,20 +115,28 @@ } else { builder.startStaticCall(typeSystem.getTemplateType().asType(), type.getTypeCasts().get(0).getMethodName()).tree(content).end(); } - return builder.getRoot(); + return builder.build(); } public static CodeTree expect(TypeData type, CodeTree content) { - if (type.isGeneric()) { + if (type.isGeneric() || type.isVoid()) { return content; } CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); TypeSystemData typeSystem = type.getTypeSystem(); builder.startStaticCall(createTypeSystemGen(typeSystem), expectTypeMethodName(type)).tree(content).end(); - return builder.getRoot(); + return builder.build(); } - private static CodeTypeMirror createTypeSystemGen(TypeSystemData typeSystem) { + public static CodeTree expect(TypeData sourceType, TypeData targetType, CodeTree content) { + if (sourceType != null && !sourceType.needsCastTo(targetType)) { + return content; + } else { + return expect(targetType, content); + } + } + + public static CodeTypeMirror createTypeSystemGen(TypeSystemData typeSystem) { return new GeneratedTypeMirror(ElementUtils.getPackageName(typeSystem.getTemplateType()), typeName(typeSystem)); } @@ -132,7 +156,7 @@ } else { builder.startStaticCall(typeSystem.getTemplateType().asType(), type.getTypeChecks().get(0).getMethodName()).tree(content).end(); } - return builder.getRoot(); + return builder.build(); } public static String isTypeMethodName(TypeData type) { @@ -151,6 +175,10 @@ return "asImplicit" + ElementUtils.getTypeId(type.getBoxedType()); } + static String expectImplicitTypeMethodName(TypeData type) { + return "expectImplicit" + ElementUtils.getTypeId(type.getBoxedType()); + } + static String getImplicitClass(TypeData type) { return "getImplicit" + ElementUtils.getTypeId(type.getBoxedType()) + "Class"; } @@ -170,7 +198,21 @@ @Override public CodeTypeElement create(ProcessorContext context, TypeSystemData typeSystem) { - return new TypeClassFactory(context, typeSystem).create(); + CodeTypeElement clazz = new TypeClassFactory(context, typeSystem).create(); + + if (typeSystem.getOptions().useNewLayout()) { + clazz.add(new TypeSystemNodeFactory(context, typeSystem).create()); + + if (typeSystem.getOptions().implicitCastOptimization().isMergeCasts()) { + for (TypeData type : typeSystem.getTypes()) { + List sourceTypes = typeSystem.lookupSourceTypes(type); + if (sourceTypes.size() > 1) { + clazz.add(new ImplicitCastNodeFactory(context, type).create()); + } + } + } + } + return clazz; } private static class TypeClassFactory { @@ -187,16 +229,17 @@ public CodeTypeElement create() { String name = typeName(typeSystem); - CodeTypeElement clazz = GeneratorUtils.createClass(typeSystem, modifiers(PUBLIC, FINAL), name, typeSystem.getTemplateType().asType(), false); + CodeTypeElement clazz = GeneratorUtils.createClass(typeSystem, null, modifiers(PUBLIC, FINAL), name, typeSystem.getTemplateType().asType()); - clazz.add(GeneratorUtils.createConstructorUsingFields(context, modifiers(PROTECTED), clazz)); + clazz.add(GeneratorUtils.createConstructorUsingFields(modifiers(PROTECTED), clazz)); CodeVariableElement singleton = createSingleton(clazz); clazz.add(singleton); for (TypeData type : typeSystem.getTypes()) { - if (type.isGeneric() || type.isVoid()) { + if (type.isVoid() || type.isGeneric()) { continue; } + clazz.addOptional(createIsTypeMethod(type)); clazz.addOptional(createAsTypeMethod(type)); @@ -204,11 +247,20 @@ clazz.addOptional(createExpectTypeMethod(type, sourceType)); } - clazz.addOptional(createAsImplicitTypeMethod(type, true)); - clazz.addOptional(createAsImplicitTypeMethod(type, false)); - clazz.addOptional(createIsImplicitTypeMethod(type, true)); - clazz.addOptional(createIsImplicitTypeMethod(type, false)); - clazz.addOptional(createGetTypeIndex(type)); + if (type.hasImplicitSourceTypes()) { + clazz.add(createAsImplicitTypeMethod(type, false)); + if (typeSystem.getOptions().implicitCastOptimization().isNone()) { + clazz.add(createExpectImplicitTypeMethod(type, false)); + } + clazz.add(createIsImplicitTypeMethod(type, false)); + + if (typeSystem.getOptions().implicitCastOptimization().isDuplicateTail()) { + clazz.add(createAsImplicitTypeMethod(type, true)); + clazz.add(createExpectImplicitTypeMethod(type, true)); + clazz.add(createIsImplicitTypeMethod(type, true)); + clazz.add(createGetImplicitClass(type)); + } + } } return clazz; @@ -238,10 +290,6 @@ } private CodeExecutableElement createIsImplicitTypeMethod(TypeData type, boolean typed) { - List casts = typeSystem.lookupByTargetType(type); - if (casts.isEmpty()) { - return null; - } CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), context.getType(boolean.class), TypeSystemCodeGenerator.isImplicitTypeMethodName(type)); method.addParameter(new CodeVariableElement(context.getType(Object.class), LOCAL_VALUE)); if (typed) { @@ -275,14 +323,11 @@ return method; } - private CodeExecutableElement createAsImplicitTypeMethod(TypeData type, boolean typed) { - List casts = typeSystem.lookupByTargetType(type); - if (casts.isEmpty()) { - return null; - } - CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), type.getPrimitiveType(), TypeSystemCodeGenerator.asImplicitTypeMethodName(type)); + private CodeExecutableElement createAsImplicitTypeMethod(TypeData type, boolean useTypeHint) { + String name = asImplicitTypeMethodName(type); + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), type.getPrimitiveType(), name); method.addParameter(new CodeVariableElement(context.getType(Object.class), LOCAL_VALUE)); - if (typed) { + if (useTypeHint) { method.addParameter(new CodeVariableElement(context.getType(Class.class), "typeHint")); } @@ -292,7 +337,7 @@ boolean elseIf = false; for (TypeData sourceType : sourceTypes) { elseIf = builder.startIf(elseIf); - if (typed) { + if (useTypeHint) { builder.string("typeHint == ").typeLiteral(sourceType.getPrimitiveType()); } else { builder.tree(check(sourceType, LOCAL_VALUE)); @@ -314,17 +359,55 @@ } builder.startElseBlock(); - builder.startStatement().startStaticCall(context.getTruffleTypes().getCompilerDirectives(), "transferToInterpreterAndInvalidate").end().end(); + builder.tree(createTransferToInterpreterAndInvalidate()); builder.startThrow().startNew(context.getType(IllegalArgumentException.class)).doubleQuote("Illegal type ").end().end(); builder.end(); return method; } - private CodeExecutableElement createGetTypeIndex(TypeData type) { - List casts = typeSystem.lookupByTargetType(type); - if (casts.isEmpty()) { - return null; + private CodeExecutableElement createExpectImplicitTypeMethod(TypeData type, boolean useTypeHint) { + String name = expectImplicitTypeMethodName(type); + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), type.getPrimitiveType(), name); + method.addParameter(new CodeVariableElement(context.getType(Object.class), LOCAL_VALUE)); + if (useTypeHint) { + method.addParameter(new CodeVariableElement(context.getType(Class.class), "typeHint")); } + method.getThrownTypes().add(context.getType(UnexpectedResultException.class)); + + List sourceTypes = typeSystem.lookupSourceTypes(type); + + CodeTreeBuilder builder = method.createBuilder(); + boolean elseIf = false; + for (TypeData sourceType : sourceTypes) { + elseIf = builder.startIf(elseIf); + if (useTypeHint) { + builder.string("typeHint == ").typeLiteral(sourceType.getPrimitiveType()); + builder.string(" && "); + } + builder.tree(check(sourceType, LOCAL_VALUE)); + + builder.end().startBlock(); + + builder.startReturn(); + ImplicitCastData cast = typeSystem.lookupCast(sourceType, type); + if (cast != null) { + builder.startCall(cast.getMethodName()); + } + builder.tree(cast(sourceType, LOCAL_VALUE)).end(); + if (cast != null) { + builder.end(); + } + builder.end(); + builder.end(); + } + + builder.startElseBlock(); + builder.startThrow().startNew(context.getType(UnexpectedResultException.class)).string(LOCAL_VALUE).end().end(); + builder.end(); + return method; + } + + private CodeExecutableElement createGetImplicitClass(TypeData type) { CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), context.getType(Class.class), TypeSystemCodeGenerator.getImplicitClass(type)); method.addParameter(new CodeVariableElement(context.getType(Object.class), LOCAL_VALUE)); @@ -340,7 +423,7 @@ } builder.startElseBlock(); - builder.startStatement().startStaticCall(context.getTruffleTypes().getCompilerDirectives(), "transferToInterpreterAndInvalidate").end().end(); + builder.tree(createTransferToInterpreterAndInvalidate()); builder.startThrow().startNew(context.getType(IllegalArgumentException.class)).doubleQuote("Illegal type ").end().end(); builder.end(); diff -r 6fa3999631d8 -r a665483c3881 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/TypeSystemNodeFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/TypeSystemNodeFactory.java Mon Dec 29 23:38:54 2014 +0100 @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2014, 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.generator; + +import static com.oracle.truffle.dsl.processor.java.ElementUtils.*; +import static javax.lang.model.element.Modifier.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; +import javax.lang.model.util.*; + +import com.oracle.truffle.api.dsl.internal.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.dsl.processor.*; +import com.oracle.truffle.dsl.processor.java.*; +import com.oracle.truffle.dsl.processor.java.model.*; +import com.oracle.truffle.dsl.processor.model.*; + +public class TypeSystemNodeFactory { + + private final ProcessorContext context; + private final TypeSystemData typeSystem; + private final DSLOptions options; + + public TypeSystemNodeFactory(ProcessorContext context, TypeSystemData typeSystem) { + this.context = context; + this.typeSystem = typeSystem; + this.options = typeSystem.getOptions(); + } + + public static TypeMirror nodeType(TypeSystemData typeSystem) { + TypeMirror parentType = TypeSystemCodeGenerator.createTypeSystemGen(typeSystem); + return new GeneratedTypeMirror(getQualifiedName(parentType), typeName(typeSystem)); + } + + public static String typeName(TypeSystemData typeSystem) { + return getTypeId(typeSystem.getTemplateType().asType()) + "Node"; + } + + public static String acceptAndExecuteName() { + return "acceptAndExecute"; + } + + public static String executeName(TypeData type) { + if (type == null) { + return acceptAndExecuteName(); + } else if (type.isGeneric()) { + return "executeGeneric"; + } else { + return "execute" + getTypeId(type.getBoxedType()); + } + } + + public static String voidBoxingExecuteName(TypeData type) { + return executeName(type) + "Void"; + } + + public CodeTypeElement create() { + String typeName = typeName(typeSystem); + TypeMirror baseType = context.getType(SpecializationNode.class); + CodeTypeElement clazz = GeneratorUtils.createClass(typeSystem, null, modifiers(PUBLIC, ABSTRACT, STATIC), typeName, baseType); + + for (ExecutableElement constructor : ElementFilter.constructorsIn(ElementUtils.fromTypeMirror(baseType).getEnclosedElements())) { + clazz.add(GeneratorUtils.createSuperConstructor(context, clazz, constructor)); + } + + for (TypeData type : typeSystem.getTypes()) { + clazz.add(createExecuteMethod(type)); + if (GeneratorUtils.isTypeBoxingOptimized(options.voidBoxingOptimization(), type)) { + clazz.add(createVoidBoxingExecuteMethod(type)); + } + } + return clazz; + } + + private Element createVoidBoxingExecuteMethod(TypeData type) { + TypeData voidType = typeSystem.getVoidType(); + String methodName = voidBoxingExecuteName(type); + CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, FINAL), voidType.getPrimitiveType(), methodName); + method.addParameter(new CodeVariableElement(context.getType(VirtualFrame.class), "frame")); + + CodeTreeBuilder builder = method.createBuilder(); + builder.startTryBlock(); + builder.startStatement().startCall(executeName(type)).string("frame").end().end(); + builder.end(); + builder.startCatchBlock(context.getType(UnexpectedResultException.class), "e"); + builder.end(); + + return method; + } + + private Element createExecuteMethod(TypeData type) { + TypeData genericType = typeSystem.getGenericTypeData(); + String methodName = executeName(type); + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), type.getPrimitiveType(), methodName); + method.addParameter(new CodeVariableElement(context.getType(VirtualFrame.class), "frame")); + + if (type.isGeneric()) { + method.getModifiers().add(ABSTRACT); + } else { + CodeTreeBuilder builder = method.createBuilder(); + CodeTree executeGeneric = builder.create().startCall(executeName(genericType)).string("frame").end().build(); + if (!type.isVoid()) { + method.getThrownTypes().add(context.getType(UnexpectedResultException.class)); + } + builder.startReturn().tree(TypeSystemCodeGenerator.expect(type, executeGeneric)).end(); + } + + return method; + } +} diff -r 6fa3999631d8 -r a665483c3881 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java Mon Dec 29 23:38:50 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java Mon Dec 29 23:38:54 2014 +0100 @@ -844,6 +844,7 @@ PrintWriter writer = new PrintWriter(string); e.printStackTrace(writer); writer.flush(); + string.flush(); return e.getMessage() + "\r\n" + string.toString(); } diff -r 6fa3999631d8 -r a665483c3881 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeElement.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeElement.java Mon Dec 29 23:38:50 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeElement.java Mon Dec 29 23:38:54 2014 +0100 @@ -65,7 +65,7 @@ return generatorElement; } - public E add(E element) { + public T add(T element) { if (element == null) { throw new NullPointerException(); } @@ -73,7 +73,7 @@ return element; } - public E addOptional(E element) { + public T addOptional(T element) { if (element != null) { add(element); } diff -r 6fa3999631d8 -r a665483c3881 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeElementScanner.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeElementScanner.java Mon Dec 29 23:38:50 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeElementScanner.java Mon Dec 29 23:38:54 2014 +0100 @@ -31,6 +31,9 @@ @Override public final R visitExecutable(ExecutableElement e, P p) { + if (!(e instanceof CodeExecutableElement)) { + throw new ClassCastException(e.toString()); + } return visitExecutable(cast(e, CodeExecutableElement.class), p); } diff -r 6fa3999631d8 -r a665483c3881 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeExecutableElement.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeExecutableElement.java Mon Dec 29 23:38:50 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeExecutableElement.java Mon Dec 29 23:38:54 2014 +0100 @@ -123,6 +123,17 @@ return builder; } + public CodeTreeBuilder appendBuilder() { + CodeTreeBuilder builder = new CodeTreeBuilder(null); + builder.setEnclosingElement(this); + if (bodyTree != null) { + builder.tree(bodyTree); + } + this.bodyTree = builder.getTree(); + this.body = null; + return builder; + } + public void setBodyTree(CodeTree body) { this.bodyTree = body; } diff -r 6fa3999631d8 -r a665483c3881 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeTree.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeTree.java Mon Dec 29 23:38:50 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeTree.java Mon Dec 29 23:38:54 2014 +0100 @@ -80,4 +80,26 @@ this.type = type; } + public boolean isEmpty() { + return children == null || children.isEmpty(); + } + + public boolean containsKind(CodeTreeKind k) { + if (this.kind == k) { + return true; + } + if (children != null) { + for (CodeTree child : children) { + if (child.containsKind(k)) { + return true; + } + } + } + return false; + } + + public boolean isSingleLine() { + return !containsKind(CodeTreeKind.NEW_LINE); + } + } diff -r 6fa3999631d8 -r a665483c3881 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeTreeBuilder.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeTreeBuilder.java Mon Dec 29 23:38:50 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeTreeBuilder.java Mon Dec 29 23:38:54 2014 +0100 @@ -174,7 +174,11 @@ } public CodeTreeBuilder startCall(String receiver, String callSite) { - return startCall(singleString(receiver), callSite); + if (receiver != null) { + return startCall(singleString(receiver), callSite); + } else { + return startCall(callSite); + } } public CodeTreeBuilder startCall(CodeTree receiver, String callSite) { @@ -614,7 +618,7 @@ return root; } - public CodeTree getRoot() { + public CodeTree build() { return root; } @@ -623,6 +627,11 @@ return this; } + public CodeTreeBuilder cast(TypeMirror type) { + string("(").type(type).string(") "); + return this; + } + public CodeTreeBuilder cast(TypeMirror type, CodeTree content) { if (ElementUtils.isVoid(type)) { tree(content); @@ -738,6 +747,21 @@ return startBlock(); } + public CodeTreeBuilder startCatchBlock(TypeMirror[] exceptionTypes, String localVarName) { + clearLast(CodeTreeKind.NEW_LINE); + string(" catch ("); + + for (int i = 0; i < exceptionTypes.length; i++) { + if (i != 0) { + string(" | "); + } + type(exceptionTypes[i]); + } + + string(" ").string(localVarName).string(") "); + return startBlock(); + } + public CodeTreeBuilder startFinallyBlock() { clearLast(CodeTreeKind.NEW_LINE); string(" finally "); diff -r 6fa3999631d8 -r a665483c3881 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/transform/AbstractCodeWriter.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/transform/AbstractCodeWriter.java Mon Dec 29 23:38:50 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/transform/AbstractCodeWriter.java Mon Dec 29 23:38:54 2014 +0100 @@ -525,9 +525,6 @@ return null; } - public void foo() { - } - @Override public void visitTree(CodeTree e, Void p, Element enclosingElement) { CodeTreeKind kind = e.getCodeKind(); diff -r 6fa3999631d8 -r a665483c3881 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ExecutableTypeData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ExecutableTypeData.java Mon Dec 29 23:38:50 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ExecutableTypeData.java Mon Dec 29 23:38:54 2014 +0100 @@ -84,4 +84,12 @@ return super.equals(obj); } + public boolean hasFrame() { + return getFrame() != null; + } + + public Parameter getFrame() { + return findParameter("frameValue"); + } + } diff -r 6fa3999631d8 -r a665483c3881 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeData.java Mon Dec 29 23:38:50 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeData.java Mon Dec 29 23:38:54 2014 +0100 @@ -56,7 +56,7 @@ public NodeData(ProcessorContext context, TypeElement type, String shortName, TypeSystemData typeSystem, List children, List executions, List fields, List assumptions, boolean generateFactory) { - super(context, type, null, null); + super(context, type, null); this.nodeId = type.getSimpleName().toString(); this.shortName = shortName; this.typeSystem = typeSystem; @@ -98,6 +98,35 @@ return childExecutions; } + public Set findSpecializedTypes(NodeExecutionData execution) { + Set types = new HashSet<>(); + for (SpecializationData specialization : getSpecializations()) { + if (!specialization.isSpecialized()) { + continue; + } + List parameters = specialization.findByExecutionData(execution); + for (Parameter parameter : parameters) { + TypeData type = parameter.getTypeSystemType(); + if (type == null) { + throw new AssertionError(); + } + types.add(type); + } + } + return types; + } + + public Collection findSpecializedReturnTypes() { + Set types = new HashSet<>(); + for (SpecializationData specialization : getSpecializations()) { + if (!specialization.isSpecialized()) { + continue; + } + types.add(specialization.getReturnType().getTypeSystemType()); + } + return types; + } + public int getSignatureSize() { if (getSpecializations() != null && !getSpecializations().isEmpty()) { return getSpecializations().get(0).getSignatureSize(); @@ -353,7 +382,7 @@ public SpecializationData getGenericSpecialization() { for (SpecializationData specialization : specializations) { - if (specialization.isGeneric()) { + if (specialization.isFallback()) { return specialization; } } diff -r 6fa3999631d8 -r a665483c3881 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ShortCircuitData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ShortCircuitData.java Mon Dec 29 23:38:50 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ShortCircuitData.java Mon Dec 29 23:38:54 2014 +0100 @@ -55,7 +55,7 @@ } public boolean isCompatibleTo(SpecializationData specialization) { - if (isGeneric() && specialization.isGeneric()) { + if (isGeneric() && specialization.isFallback()) { return true; } diff -r 6fa3999631d8 -r a665483c3881 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/SpecializationData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/SpecializationData.java Mon Dec 29 23:38:50 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/SpecializationData.java Mon Dec 29 23:38:54 2014 +0100 @@ -33,7 +33,7 @@ UNINITIALIZED, SPECIALIZED, POLYMORPHIC, - GENERIC + FALLBACK } private final NodeData node; @@ -221,13 +221,6 @@ return true; } - public String createReferenceName() { - if (getMethod() == null) { - return "-"; - } - return ElementUtils.createReferenceName(getMethod()); - } - public NodeData getNode() { return node; } @@ -240,8 +233,8 @@ return kind == SpecializationKind.SPECIALIZED; } - public boolean isGeneric() { - return kind == SpecializationKind.GENERIC; + public boolean isFallback() { + return kind == SpecializationKind.FALLBACK; } public boolean isUninitialized() { diff -r 6fa3999631d8 -r a665483c3881 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/Template.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/Template.java Mon Dec 29 23:38:50 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/Template.java Mon Dec 29 23:38:54 2014 +0100 @@ -33,13 +33,11 @@ private final ProcessorContext context; private final TypeElement templateType; - private final String templateMethodName; private final AnnotationMirror annotation; - public Template(ProcessorContext context, TypeElement templateType, String templateMethodName, AnnotationMirror annotation) { + public Template(ProcessorContext context, TypeElement templateType, AnnotationMirror annotation) { this.context = context; this.templateType = templateType; - this.templateMethodName = templateMethodName; this.annotation = annotation; } @@ -64,10 +62,6 @@ return Collections.emptyList(); } - public String getTemplateMethodName() { - return templateMethodName; - } - public TypeElement getTemplateType() { return templateType; } diff -r 6fa3999631d8 -r a665483c3881 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TemplateMethod.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TemplateMethod.java Mon Dec 29 23:38:50 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TemplateMethod.java Mon Dec 29 23:38:54 2014 +0100 @@ -68,6 +68,13 @@ this.id = id; } + public String createReferenceName() { + if (getMethod() == null) { + return "-"; + } + return ElementUtils.createReferenceName(getMethod()); + } + public int getNaturalOrder() { return naturalOrder; } @@ -160,6 +167,15 @@ return foundParameters; } + public Parameter findParameterOrDie(NodeExecutionData execution) { + for (Parameter parameter : parameters) { + if (parameter.getSpecification().isSignature() && parameter.getSpecification().getExecution() == execution) { + return parameter; + } + } + throw new AssertionError("Could not find parameter for execution"); + } + public List findByExecutionData(NodeExecutionData execution) { List foundParameters = new ArrayList<>(); for (Parameter parameter : getParameters()) { diff -r 6fa3999631d8 -r a665483c3881 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TypeData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TypeData.java Mon Dec 29 23:38:50 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TypeData.java Mon Dec 29 23:38:54 2014 +0100 @@ -156,6 +156,14 @@ return ElementUtils.isPrimitive(getPrimitiveType()); } + public List getImplicitSourceTypes() { + return getTypeSystem().lookupSourceTypes(this); + } + + public boolean hasImplicitSourceTypes() { + return getTypeSystem().hasImplicitSourceTypes(this); + } + public boolean isImplicitSubtypeOf(TypeData other) { List casts = other.getTypeSystem().lookupByTargetType(other); for (ImplicitCastData cast : casts) { diff -r 6fa3999631d8 -r a665483c3881 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TypeSystemData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TypeSystemData.java Mon Dec 29 23:38:50 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TypeSystemData.java Mon Dec 29 23:38:54 2014 +0100 @@ -27,6 +27,7 @@ import javax.lang.model.element.*; import javax.lang.model.type.*; +import com.oracle.truffle.api.dsl.internal.*; import com.oracle.truffle.dsl.processor.*; import com.oracle.truffle.dsl.processor.java.*; @@ -42,10 +43,18 @@ private List checks; private TypeMirror genericType; + private TypeData booleanType; private TypeData voidType; - public TypeSystemData(ProcessorContext context, TypeElement templateType, AnnotationMirror annotation) { - super(context, templateType, null, annotation); + private DSLOptions options; + + public TypeSystemData(ProcessorContext context, TypeElement templateType, AnnotationMirror annotation, DSLOptions options) { + super(context, templateType, annotation); + this.options = options; + } + + public DSLOptions getOptions() { + return options; } @Override @@ -196,6 +205,18 @@ return null; } + public boolean hasImplicitSourceTypes(TypeData targetType) { + if (getImplicitCasts() == null) { + return false; + } + for (ImplicitCastData cast : getImplicitCasts()) { + if (cast.getTargetType() == targetType) { + return true; + } + } + return false; + } + public List lookupSourceTypes(TypeData type) { List sourceTypes = new ArrayList<>(); sourceTypes.add(type); @@ -210,4 +231,12 @@ return sourceTypes; } + public TypeData getBooleanType() { + return booleanType; + } + + public void setBooleanType(TypeData booleanType) { + this.booleanType = booleanType; + } + } diff -r 6fa3999631d8 -r a665483c3881 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/ExecutableTypeMethodParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/ExecutableTypeMethodParser.java Mon Dec 29 23:38:50 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/ExecutableTypeMethodParser.java Mon Dec 29 23:38:54 2014 +0100 @@ -28,7 +28,9 @@ import javax.lang.model.element.*; import javax.lang.model.type.*; +import com.oracle.truffle.api.dsl.*; import com.oracle.truffle.dsl.processor.*; +import com.oracle.truffle.dsl.processor.java.*; import com.oracle.truffle.dsl.processor.model.*; public class ExecutableTypeMethodParser extends NodeMethodParser { @@ -77,6 +79,8 @@ return false; } else if (method.getModifiers().contains(Modifier.NATIVE)) { return false; + } else if (ElementUtils.findAnnotationMirror(getContext().getEnvironment(), method, Specialization.class) != null) { + return false; } return method.getSimpleName().toString().startsWith("execute"); } diff -r 6fa3999631d8 -r a665483c3881 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/GenericParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/GenericParser.java Mon Dec 29 23:38:50 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/GenericParser.java Mon Dec 29 23:38:54 2014 +0100 @@ -62,7 +62,7 @@ @Override public SpecializationData create(TemplateMethod method, boolean invalid) { - return new SpecializationData(getNode(), method, SpecializationKind.GENERIC); + return new SpecializationData(getNode(), method, SpecializationKind.FALLBACK); } @Override diff -r 6fa3999631d8 -r a665483c3881 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/ImplicitCastParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/ImplicitCastParser.java Mon Dec 29 23:38:50 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/ImplicitCastParser.java Mon Dec 29 23:38:54 2014 +0100 @@ -48,7 +48,7 @@ List types = getTypeSystem().getPrimitiveTypeMirrors(); Set identifiers = getTypeSystem().getTypeIdentifiers(); MethodSpec spec = new MethodSpec(new ParameterSpec("target", types, identifiers)); - spec.addRequired(new ParameterSpec("source", types, identifiers)); + spec.addRequired(new ParameterSpec("source", types, identifiers)).setSignature(true); return spec; } diff -r 6fa3999631d8 -r a665483c3881 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeMethodParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeMethodParser.java Mon Dec 29 23:38:50 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeMethodParser.java Mon Dec 29 23:38:54 2014 +0100 @@ -42,7 +42,8 @@ } protected ParameterSpec createValueParameterSpec(NodeExecutionData execution) { - ParameterSpec spec = new ParameterSpec(execution.getName(), nodeTypeMirrors(execution.getChild().getNodeData()), nodeTypeIdentifiers(execution.getChild().getNodeData())); + NodeData childNode = execution.getChild().getNodeData(); + ParameterSpec spec = new ParameterSpec(execution.getName(), nodeTypeMirrors(childNode), nodeTypeIdentifiers(childNode)); spec.setExecution(execution); return spec; } diff -r 6fa3999631d8 -r a665483c3881 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java Mon Dec 29 23:38:50 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java Mon Dec 29 23:38:54 2014 +0100 @@ -151,6 +151,22 @@ node.setExecutableTypes(groupExecutableTypes(new ExecutableTypeMethodParser(context, node).parse(elements))); initializeChildren(node); + // ensure the processed element has at least one @Specialization annotation. + boolean foundSpecialization = false; + for (ExecutableElement method : ElementFilter.methodsIn(elements)) { + if (ElementUtils.findAnnotationMirror(processingEnv, method, Specialization.class) != null) { + foundSpecialization = true; + break; + } + } + if (!foundSpecialization) { + return node; + } + + if (node.hasErrors()) { + return node; // error sync point + } + node.getSpecializations().addAll(new SpecializationMethodParser(context, node).parse(elements)); node.getSpecializations().addAll(new GenericParser(context, node).parse(elements)); node.getCasts().addAll(new CreateCastParser(context, node).parse(elements)); @@ -224,7 +240,7 @@ final TypeSystemData typeSystem = (TypeSystemData) context.getTemplate(typeSystemType, true); if (typeSystem == null) { NodeData nodeData = new NodeData(context, templateType); - nodeData.addError("The used type system '%s' is invalid or not a Node.", ElementUtils.getQualifiedName(typeSystemType)); + nodeData.addError("The used type system '%s' is invalid. Fix errors in the type system first.", ElementUtils.getQualifiedName(typeSystemType)); return nodeData; } @@ -565,14 +581,25 @@ initializeReachability(node); initializeContains(node); - if (!node.hasErrors()) { + if (!node.hasErrors() && !node.getTypeSystem().getOptions().useNewLayout()) { initializeExceptions(node); } resolveContains(node); + if (node.getTypeSystem().getOptions().useNewLayout()) { + List specializations = node.getSpecializations(); + for (SpecializationData cur : specializations) { + for (SpecializationData child : specializations) { + if (child != null && child != cur && child.getContains().contains(cur)) { + cur.getExcludedBy().add(child); + } + } + } + } + List needsId = new ArrayList<>(); for (SpecializationData specialization : node.getSpecializations()) { - if (specialization.isGeneric()) { + if (specialization.isFallback()) { specialization.setId("Generic"); } else if (specialization.isUninitialized()) { specialization.setId("Uninitialized"); @@ -643,6 +670,7 @@ private static void initializeExceptions(NodeData node) { List specializations = node.getSpecializations(); + for (int i = 0; i < specializations.size(); i++) { SpecializationData cur = specializations.get(i); if (cur.getExceptions().isEmpty()) { @@ -671,6 +699,7 @@ } } } + } private static void initializeContains(NodeData node) { @@ -771,7 +800,7 @@ name.append(shadowSpecialization.createReferenceName()); sep = ", "; } - current.addError("%s is not reachable. It is shadowed by %s.", current.isGeneric() ? "Generic" : "Specialization", name); + current.addError("%s is not reachable. It is shadowed by %s.", current.isFallback() ? "Generic" : "Specialization", name); } current.setReachable(shadowedBy == null); } @@ -966,7 +995,7 @@ List generics = new ArrayList<>(); for (SpecializationData spec : node.getSpecializations()) { - if (spec.isGeneric()) { + if (spec.isFallback()) { generics.add(spec); } } @@ -1313,6 +1342,24 @@ } private void verifyConstructors(NodeData nodeData) { + if (nodeData.getTypeSystem().getOptions().useNewLayout()) { + List constructors = ElementFilter.constructorsIn(nodeData.getTemplateType().getEnclosedElements()); + if (constructors.isEmpty()) { + return; + } + + boolean oneNonPrivate = false; + for (ExecutableElement constructor : constructors) { + if (ElementUtils.getVisibility(constructor.getModifiers()) != Modifier.PRIVATE) { + oneNonPrivate = true; + break; + } + } + if (!oneNonPrivate && !nodeData.getTemplateType().getModifiers().contains(Modifier.PRIVATE)) { + nodeData.addError("At least one constructor must be non-private."); + } + return; + } if (!nodeData.needsRewrites(context)) { // no specialization constructor is needed if the node never rewrites. return; diff -r 6fa3999631d8 -r a665483c3881 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationGroup.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationGroup.java Mon Dec 29 23:38:50 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationGroup.java Mon Dec 29 23:38:54 2014 +0100 @@ -444,4 +444,5 @@ return false; } + } diff -r 6fa3999631d8 -r a665483c3881 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeSystemParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeSystemParser.java Mon Dec 29 23:38:50 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeSystemParser.java Mon Dec 29 23:38:54 2014 +0100 @@ -32,10 +32,12 @@ import javax.lang.model.util.*; import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.dsl.internal.*; import com.oracle.truffle.dsl.processor.generator.*; import com.oracle.truffle.dsl.processor.java.*; import com.oracle.truffle.dsl.processor.model.*; +@DSLOptions public class TypeSystemParser extends AbstractParser { public static final List> ANNOTATIONS = Arrays.asList(TypeSystem.class, ExpectError.class); @@ -49,7 +51,13 @@ protected TypeSystemData parse(Element element, AnnotationMirror mirror) { TypeElement templateType = (TypeElement) element; AnnotationMirror templateTypeAnnotation = mirror; - TypeSystemData typeSystem = new TypeSystemData(context, templateType, templateTypeAnnotation); + DSLOptions options = element.getAnnotation(DSLOptions.class); + if (options == null) { + options = TypeSystemParser.class.getAnnotation(DSLOptions.class); + } + assert options != null; + + TypeSystemData typeSystem = new TypeSystemData(context, templateType, templateTypeAnnotation, options); // annotation type on class path!? TypeElement annotationTypeElement = processingEnv.getElementUtils().getTypeElement(getAnnotationType().getCanonicalName()); @@ -77,10 +85,15 @@ if (typeSystem.hasErrors()) { return typeSystem; } - typeSystem.setGenericType(genericType); typeSystem.setVoidType(voidType); + TypeData booleanType = typeSystem.findTypeData(context.getType(boolean.class)); + if (booleanType == null) { + booleanType = new TypeData(typeSystem, types.size(), null, context.getType(boolean.class), context.getType(Boolean.class)); + } + typeSystem.setBooleanType(booleanType); + verifyExclusiveMethodAnnotation(typeSystem, TypeCast.class, TypeCheck.class); List elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(templateType));