# HG changeset patch # User Christian Humer # Date 1422972427 -3600 # Node ID 62c43fcf5be2b46cbe19689c63a4acf9a6bc1bc0 # Parent 3a37116ef37ffe102f8ee81a8e989e2367e59102 Truffle-DSL: implement @Cached and fixes for the new guard expression syntax. diff -r 3a37116ef37f -r 62c43fcf5be2 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/CachedTest.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/CachedTest.java Tue Feb 03 15:07:07 2015 +0100 @@ -0,0 +1,320 @@ +/* + * Copyright (c) 2015, 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.*; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.dsl.test.CachedTestFactory.BoundCacheFactory; +import com.oracle.truffle.api.dsl.test.CachedTestFactory.BoundCacheOverflowFactory; +import com.oracle.truffle.api.dsl.test.CachedTestFactory.TestBoundCacheOverflowContainsFactory; +import com.oracle.truffle.api.dsl.test.CachedTestFactory.TestCacheFieldFactory; +import com.oracle.truffle.api.dsl.test.CachedTestFactory.TestCacheMethodFactory; +import com.oracle.truffle.api.dsl.test.CachedTestFactory.TestCacheNodeFieldFactory; +import com.oracle.truffle.api.dsl.test.CachedTestFactory.TestGuardWithCachedAndDynamicParameterFactory; +import com.oracle.truffle.api.dsl.test.CachedTestFactory.TestGuardWithJustCachedParameterFactory; +import com.oracle.truffle.api.dsl.test.CachedTestFactory.TestMultipleCachesFactory; +import com.oracle.truffle.api.dsl.test.CachedTestFactory.UnboundCacheFactory; +import com.oracle.truffle.api.dsl.test.TypeSystemTest.ValueNode; + +@SuppressWarnings("unused") +public class CachedTest { + + @Test + public void testUnboundCache() { + CallTarget root = createCallTarget(UnboundCacheFactory.getInstance()); + assertEquals(42, root.call(42)); + assertEquals(42, root.call(43)); + assertEquals(42, root.call(44)); + } + + @NodeChild + static class UnboundCache extends ValueNode { + @Specialization + static int do1(int value, @Cached("value") int cachedValue) { + return cachedValue; + } + } + + @Test + public void testBoundCache() { + CallTarget root = createCallTarget(BoundCacheFactory.getInstance()); + assertEquals(42, root.call(42)); + assertEquals(43, root.call(43)); + assertEquals(44, root.call(44)); + try { + root.call(45); + fail(); + } catch (UnsupportedSpecializationException e) { + } + } + + @NodeChild + static class BoundCache extends ValueNode { + + @Specialization(guards = "value == cachedValue", limit = "3") + static int do1(int value, @Cached("value") int cachedValue) { + return cachedValue; + } + + } + + @Test + public void testBoundCacheOverflow() { + CallTarget root = createCallTarget(BoundCacheOverflowFactory.getInstance()); + assertEquals(42, root.call(42)); + assertEquals(43, root.call(43)); + assertEquals(-1, root.call(44)); + assertEquals(42, root.call(42)); + assertEquals(43, root.call(43)); + assertEquals(-1, root.call(44)); + } + + @NodeChild + static class BoundCacheOverflow extends ValueNode { + + @Specialization(guards = "value == cachedValue", limit = "2") + static int do1(int value, @Cached("value") int cachedValue) { + return cachedValue; + } + + @Specialization + static int do2(int value) { + return -1; + } + + } + + @Test + public void testBoundCacheOverflowContains() { + CallTarget root = createCallTarget(TestBoundCacheOverflowContainsFactory.getInstance()); + assertEquals(42, root.call(42)); + assertEquals(43, root.call(43)); + assertEquals(-1, root.call(44)); + assertEquals(-1, root.call(42)); + assertEquals(-1, root.call(43)); + assertEquals(-1, root.call(44)); + } + + @NodeChild + static class TestBoundCacheOverflowContains extends ValueNode { + + @Specialization(guards = "value == cachedValue", limit = "2") + static int do1(int value, @Cached("value") int cachedValue) { + return cachedValue; + } + + @Specialization(contains = "do1") + static int do2(int value) { + return -1; + } + + } + + @Test + public void testCacheField() { + CallTarget root = createCallTarget(TestCacheFieldFactory.getInstance()); + assertEquals(3, root.call(42)); + assertEquals(3, root.call(43)); + } + + @NodeChild + static class TestCacheField extends ValueNode { + + protected int field = 3; + + @Specialization() + static int do1(int value, @Cached("field") int cachedValue) { + return cachedValue; + } + + } + + @Test + public void testCacheNodeField() { + CallTarget root = createCallTarget(TestCacheNodeFieldFactory.getInstance(), 21); + assertEquals(21, root.call(42)); + assertEquals(21, root.call(43)); + } + + @NodeChild + @NodeField(name = "field", type = int.class) + static class TestCacheNodeField extends ValueNode { + + @Specialization + static int do1(int value, @Cached("field") int cachedValue) { + return cachedValue; + } + + } + + @Test + public void testCacheMethod() { + TestCacheMethod.invocations = 0; + CallTarget root = createCallTarget(TestCacheMethodFactory.getInstance()); + assertEquals(42, root.call(42)); + assertEquals(42, root.call(43)); + assertEquals(42, root.call(44)); + assertEquals(1, TestCacheMethod.invocations); + } + + @NodeChild + static class TestCacheMethod extends ValueNode { + + static int invocations = 0; + + @Specialization + static int do1(int value, @Cached("someMethod(value)") int cachedValue) { + return cachedValue; + } + + static int someMethod(int value) { + invocations++; + return value; + } + + } + + @Test + public void testGuardWithJustCachedParameter() { + TestGuardWithJustCachedParameter.invocations = 0; + CallTarget root = createCallTarget(TestGuardWithJustCachedParameterFactory.getInstance()); + assertEquals(42, root.call(42)); + assertEquals(42, root.call(43)); + assertEquals(42, root.call(44)); + // guards with just cached parameters are just invoked on the slow path + assertEquals(assertionsEnabled() ? 4 : 1, TestGuardWithJustCachedParameter.invocations); + } + + @NodeChild + static class TestGuardWithJustCachedParameter extends ValueNode { + + static int invocations = 0; + + @Specialization(guards = "someMethod(cachedValue)") + static int do1(int value, @Cached("value") int cachedValue) { + return cachedValue; + } + + static boolean someMethod(int value) { + invocations++; + return true; + } + + } + + @Test + public void testGuardWithCachedAndDynamicParameter() { + TestGuardWithCachedAndDynamicParameter.cachedMethodInvocations = 0; + TestGuardWithCachedAndDynamicParameter.dynamicMethodInvocations = 0; + CallTarget root = createCallTarget(TestGuardWithCachedAndDynamicParameterFactory.getInstance()); + assertEquals(42, root.call(42)); + assertEquals(42, root.call(43)); + assertEquals(42, root.call(44)); + // guards with just cached parameters are just invoked on the slow path + assertEquals(assertionsEnabled() ? 4 : 1, TestGuardWithCachedAndDynamicParameter.cachedMethodInvocations); + assertEquals(4, TestGuardWithCachedAndDynamicParameter.dynamicMethodInvocations); + } + + @NodeChild + static class TestGuardWithCachedAndDynamicParameter extends ValueNode { + + static int cachedMethodInvocations = 0; + static int dynamicMethodInvocations = 0; + + @Specialization(guards = {"dynamicMethod(value)", "cachedMethod(cachedValue)"}) + static int do1(int value, @Cached("value") int cachedValue) { + return cachedValue; + } + + static boolean cachedMethod(int value) { + cachedMethodInvocations++; + return true; + } + + static boolean dynamicMethod(int value) { + dynamicMethodInvocations++; + return true; + } + + } + + @NodeChild + static class TestMultipleCaches extends ValueNode { + + @Specialization + static int do1(int value, @Cached("value") int cachedValue1, @Cached("value") int cachedValue2) { + return cachedValue1 + cachedValue2; + } + + } + + @Test + public void testMultipleCaches() { + CallTarget root = createCallTarget(TestMultipleCachesFactory.getInstance()); + assertEquals(42, root.call(21)); + assertEquals(42, root.call(22)); + assertEquals(42, root.call(23)); + } + + @NodeChild + static class CachedError1 extends ValueNode { + @Specialization + static int do1(int value, @ExpectError("Incompatible return type int. The expression type must be equal to the parameter type double.")// + @Cached("value") double cachedValue) { + return value; + } + } + + @NodeChild + static class CachedError2 extends ValueNode { + + // caches are not allowed to make backward references + + @Specialization + static int do1(int value, + @ExpectError("The initializer expression of parameter 'cachedValue1' binds unitialized parameter 'cachedValue2. Reorder the parameters to resolve the problem.") @Cached("cachedValue2") int cachedValue1, + @Cached("value") int cachedValue2) { + return cachedValue1 + cachedValue2; + } + + } + + @NodeChild + static class CachedError3 extends ValueNode { + + // cyclic dependency between cached expressions + @Specialization + static int do1(int value, + @ExpectError("The initializer expression of parameter 'cachedValue1' binds unitialized parameter 'cachedValue2. Reorder the parameters to resolve the problem.") @Cached("cachedValue2") int cachedValue1, + @Cached("cachedValue1") int cachedValue2) { + return cachedValue1 + cachedValue2; + } + + } + +} diff -r 3a37116ef37f -r 62c43fcf5be2 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/LimitTest.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/LimitTest.java Tue Feb 03 15:07:07 2015 +0100 @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2015, 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.*; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.dsl.test.LimitTestFactory.ConstantLimitTestFactory; +import com.oracle.truffle.api.dsl.test.LimitTestFactory.DefaultLimit3TestFactory; +import com.oracle.truffle.api.dsl.test.LimitTestFactory.LocalLimitTestFactory; +import com.oracle.truffle.api.dsl.test.LimitTestFactory.MethodLimitTestFactory; +import com.oracle.truffle.api.dsl.test.TypeSystemTest.ValueNode; + +@SuppressWarnings("unused") +public class LimitTest { + + @Test + public void testDefaultLimit3() { + CallTarget root = createCallTarget(DefaultLimit3TestFactory.getInstance()); + assertEquals(42, root.call(42)); + assertEquals(43, root.call(43)); + assertEquals(44, root.call(44)); + try { + root.call(45); + fail(); + } catch (UnsupportedSpecializationException e) { + } + } + + @NodeChild + static class DefaultLimit3Test extends ValueNode { + @Specialization(guards = "value == cachedValue") + static int do1(int value, @Cached("value") int cachedValue) { + return cachedValue; + } + } + + @Test + public void testConstantLimit() { + CallTarget root = createCallTarget(ConstantLimitTestFactory.getInstance()); + assertEquals(42, root.call(42)); + assertEquals(43, root.call(43)); + try { + root.call(44); + fail(); + } catch (UnsupportedSpecializationException e) { + } + } + + @NodeChild + static class ConstantLimitTest extends ValueNode { + + public static final int LIMIT = 2; + + @Specialization(limit = "LIMIT", guards = "value == cachedValue") + static int do1(int value, @Cached("value") int cachedValue) { + return cachedValue; + } + } + + @Test + public void testLocalLimit() { + CallTarget root = createCallTarget(LocalLimitTestFactory.getInstance()); + assertEquals(42, root.call(42)); + assertEquals(43, root.call(43)); + try { + root.call(44); + fail(); + } catch (UnsupportedSpecializationException e) { + } + } + + @NodeChild + static class LocalLimitTest extends ValueNode { + + protected int localLimit = 2; + + @Specialization(limit = "localLimit", guards = "value == cachedValue") + static int do1(int value, @Cached("value") int cachedValue) { + return cachedValue; + } + } + + @Test + public void testMethodLimit() { + MethodLimitTest.invocations = 0; + CallTarget root = createCallTarget(MethodLimitTestFactory.getInstance()); + assertEquals(42, root.call(42)); + assertEquals(43, root.call(43)); + try { + root.call(44); + fail(); + } catch (UnsupportedSpecializationException e) { + } + assertEquals(3, MethodLimitTest.invocations); + } + + @NodeChild + static class MethodLimitTest extends ValueNode { + + static int invocations = 0; + + @Specialization(limit = "calculateLimitFor(cachedValue, invocations)", guards = "value == cachedValue") + static int do1(int value, @Cached("value") int cachedValue) { + return cachedValue; + } + + int calculateLimitFor(int cachedValue, int boundField) { + invocations = boundField + 1; + return 2; + } + + } + + @NodeChild + static class LimitErrorTest1 extends ValueNode { + @ExpectError("The limit expression has no effect.%") + @Specialization(limit = "4") + static int do1(int value) { + return value; + } + } + + @NodeChild + static class LimitErrorTest2 extends ValueNode { + public static final Object CONSTANT = new Object(); + + @ExpectError("Incompatible return type Object. Limit expressions must return int.") + @Specialization(limit = "CONSTANT", guards = "value == cachedValue") + static int do1(int value, @Cached("value") int cachedValue) { + return value; + } + } + + @NodeChild + static class LimitErrorTest3 extends ValueNode { + + public static final Object CONSTANT = new Object(); + + @ExpectError("Limit expressions must not bind dynamic parameter values.") + @Specialization(limit = "value", guards = "value == cachedValue") + static int do1(int value, @Cached("value") int cachedValue) { + return value; + } + } + +} diff -r 3a37116ef37f -r 62c43fcf5be2 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/MethodGuardsTest.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/MethodGuardsTest.java Mon Dec 29 18:32:03 2014 +0100 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/MethodGuardsTest.java Tue Feb 03 15:07:07 2015 +0100 @@ -27,295 +27,473 @@ import org.junit.*; +import com.oracle.truffle.api.*; import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.Guard1Factory; -import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.Guard2Factory; -import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.GuardWithBaseClassFactory; -import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.GuardWithBoxedPrimitiveFactory; -import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.GuardWithObjectFactory; -import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.TestAbstractGuard1Factory; -import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.TestGuardResolve1Factory; -import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.TestGuardResolve2Factory; -import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.TestGuardResolve3Factory; -import com.oracle.truffle.api.dsl.test.TypeSystemTest.Abstract; -import com.oracle.truffle.api.dsl.test.TypeSystemTest.BExtendsAbstract; -import com.oracle.truffle.api.dsl.test.TypeSystemTest.CExtendsAbstract; -import com.oracle.truffle.api.dsl.test.TypeSystemTest.Interface; -import com.oracle.truffle.api.dsl.test.TypeSystemTest.TestRootNode; +import com.oracle.truffle.api.dsl.test.LimitTestFactory.ConstantLimitTestFactory; +import com.oracle.truffle.api.dsl.test.LimitTestFactory.LocalLimitTestFactory; +import com.oracle.truffle.api.dsl.test.LimitTestFactory.MethodLimitTestFactory; +import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.GuardCompareWithFieldTestFactory; +import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.GuardComplexTestFactory; +import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.GuardEqualTestFactory; +import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.GuardFieldTestFactory; +import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.GuardGreaterEqualTestFactory; +import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.GuardGreaterTestFactory; +import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.GuardLessEqualTestFactory; +import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.GuardLessTestFactory; +import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.GuardMethodTestFactory; +import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.GuardMultipleAndMethodTestFactory; +import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.GuardMultipleOrMethodTestFactory; +import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.GuardNotTestFactory; +import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.GuardOrTestFactory; +import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.GuardStaticFieldTestFactory; +import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.GuardUnboundMethodTestFactory; import com.oracle.truffle.api.dsl.test.TypeSystemTest.ValueNode; @SuppressWarnings("unused") public class MethodGuardsTest { - private static final Object NULL = new Object(); + @Test + public void testGuardEqual() { + CallTarget root = createCallTarget(GuardEqualTestFactory.getInstance()); + assertEquals("do1", root.call(1)); + assertEquals("do2", root.call(2)); + assertEquals("do1", root.call(1)); + } + + @NodeChild + static class GuardEqualTest extends ValueNode { + @Specialization(guards = "value == 1") + static String do1(int value) { + return "do1"; + } + + @Specialization + static String do2(int value) { + return "do2"; + } + } @Test - public void testInvocations() { - TestRootNode root = createRoot(Guard1Factory.getInstance()); - - assertEquals(Integer.MAX_VALUE, executeWith(root, Integer.MAX_VALUE - 1)); - assertEquals(1, Guard1.specializedInvocations); - assertEquals(0, Guard1.genericInvocations); - - assertEquals(42, executeWith(root, Integer.MAX_VALUE)); - assertEquals(1, Guard1.specializedInvocations); - assertEquals(1, Guard1.genericInvocations); + public void testGuardLessEqual() { + CallTarget root = createCallTarget(GuardLessEqualTestFactory.getInstance()); + assertEquals("do1", root.call(1)); + assertEquals("do1", root.call(0)); + assertEquals("do2", root.call(2)); + assertEquals("do1", root.call(0)); } @NodeChild - static class Guard1 extends ValueNode { - - static int specializedInvocations = 0; - static int genericInvocations = 0; - - boolean g(int value0) { - return value0 != Integer.MAX_VALUE; + static class GuardLessEqualTest extends ValueNode { + @Specialization(guards = "value <= 1") + static String do1(int value) { + return "do1"; } - @Specialization(guards = "g(value0)") - int f1(int value0) { - specializedInvocations++; - return value0 + 1; + @Specialization + static String do2(int value) { + return "do2"; + } + } + + @Test + public void testGuardLess() { + CallTarget root = createCallTarget(GuardLessTestFactory.getInstance()); + assertEquals("do1", root.call(0)); + assertEquals("do2", root.call(1)); + assertEquals("do2", root.call(2)); + assertEquals("do1", root.call(-1)); + } + + @NodeChild + static class GuardLessTest extends ValueNode { + @Specialization(guards = "value < 1") + static String do1(int value) { + return "do1"; } - @Fallback - int f2(Object value0) { - genericInvocations++; - return 42; + @Specialization + static String do2(int value) { + return "do2"; + } + } + + @Test + public void testGuardGreaterEqual() { + CallTarget root = createCallTarget(GuardGreaterEqualTestFactory.getInstance()); + assertEquals("do1", root.call(1)); + assertEquals("do2", root.call(0)); + assertEquals("do1", root.call(2)); + assertEquals("do2", root.call(0)); + } + + @NodeChild + static class GuardGreaterEqualTest extends ValueNode { + @Specialization(guards = "value >= 1") + static String do1(int value) { + return "do1"; + } + + @Specialization + static String do2(int value) { + return "do2"; } } @Test - public void testGuardSideEffect() { - TestRootNode root = createRoot(Guard2Factory.getInstance()); - - assertEquals(42, executeWith(root, NULL)); - - Guard2.globalFlag = true; - assertEquals(41, executeWith(root, NULL)); - - Guard2.globalFlag = false; - assertEquals(42, executeWith(root, NULL)); + public void testGuardGreater() { + CallTarget root = createCallTarget(GuardGreaterTestFactory.getInstance()); + assertEquals("do1", root.call(2)); + assertEquals("do2", root.call(0)); + assertEquals("do2", root.call(1)); + assertEquals("do2", root.call(0)); } @NodeChild - static class Guard2 extends ValueNode { - - static boolean globalFlag = false; - - static boolean globalFlagGuard() { - return globalFlag; + static class GuardGreaterTest extends ValueNode { + @Specialization(guards = "value > 1") + static String do1(int value) { + return "do1"; } - @Specialization(guards = "globalFlagGuard()") - int f1(Object value0) { - return 41; + @Specialization + static String do2(int value) { + return "do2"; + } + } + + @Test + public void testGuardOr() { + CallTarget root = createCallTarget(GuardOrTestFactory.getInstance()); + assertEquals("do1", root.call(1)); + assertEquals("do1", root.call(0)); + assertEquals("do2", root.call(2)); + assertEquals("do2", root.call(-1)); + } + + @NodeChild + static class GuardOrTest extends ValueNode { + @Specialization(guards = "value == 1 || value == 0") + static String do1(int value) { + return "do1"; } - @Fallback - int f2(Object value0) { - return 42; // the generic answer to all questions + @Specialization + static String do2(int value) { + return "do2"; } } @Test - public void testGuardWithBaseClass() { - TestRootNode root = createRoot(GuardWithBaseClassFactory.getInstance()); - - assertEquals(42, executeWith(root, new BExtendsAbstract())); + public void testGuardNot() { + CallTarget root = createCallTarget(GuardNotTestFactory.getInstance()); + assertEquals("do1", root.call(0)); + assertEquals("do1", root.call(2)); + assertEquals("do2", root.call(1)); + assertEquals("do1", root.call(0)); } - @NodeChild("expression") - public abstract static class GuardWithBaseClass extends ValueNode { - - boolean baseGuard(Abstract base) { - return true; + @NodeChild + static class GuardNotTest extends ValueNode { + @Specialization(guards = "!(value == 1)") + static String do1(int value) { + return "do1"; } - @Specialization(guards = "baseGuard(value0)") - int doSpecialized(BExtendsAbstract value0) { - return 42; - } - } - - @NodeChild("expression") - public abstract static class GuardWithBaseInterface extends ValueNode { - - boolean baseGuard(CharSequence base) { - return true; - } - - @Specialization(guards = "baseGuard(value0)") - int doSpecialized(String value0) { - return 42; + @Specialization + static String do2(int value) { + return "do2"; } } @Test - public void testGuardWithPrimitive() { - TestRootNode root = createRoot(GuardWithBoxedPrimitiveFactory.getInstance()); + public void testGuardField() { + CallTarget root = createCallTarget(GuardFieldTestFactory.getInstance()); + GuardFieldTest node = getNode(root); + node.field = true; + assertEquals("do1", root.call(0)); + assertEquals("do1", root.call(2)); - assertEquals(42, executeWith(root, 42)); + node.field = false; + try { + root.call(2); + fail("expected Assertion failed"); + } catch (AssertionError e) { + } } - @NodeChild("expression") - public abstract static class GuardWithBoxedPrimitive extends ValueNode { + @NodeChild + static class GuardFieldTest extends ValueNode { - boolean baseGuard(Integer primitive) { - return true; + boolean field; + + @Specialization(guards = "field") + static String do1(int value) { + return "do1"; } - @Specialization(guards = "baseGuard(value0)") - int doSpecialized(int value0) { - return value0; + @Specialization + static String do2(int value) { + return "do2"; + } + } + + @Test + public void testGuardCompareWithField() { + CallTarget root = createCallTarget(GuardCompareWithFieldTestFactory.getInstance()); + GuardCompareWithFieldTest node = getNode(root); + node.field = 1; + assertEquals("do1", root.call(1)); + assertEquals("do2", root.call(2)); + + node.field = 2; + assertEquals("do2", root.call(1)); + assertEquals("do1", root.call(2)); + } + + @NodeChild + static class GuardCompareWithFieldTest extends ValueNode { + + int field; + + @Specialization(guards = "value == field") + static String do1(int value) { + return "do1"; + } + + @Specialization + static String do2(int value) { + return "do2"; } } @Test - public void testGuardWithObject() { - TestRootNode root = createRoot(GuardWithObjectFactory.getInstance()); - - assertEquals(42, executeWith(root, 42)); + public void testGuardStaticField() { + CallTarget root = createCallTarget(GuardStaticFieldTestFactory.getInstance()); + GuardStaticFieldTest.field = true; + assertEquals("do1", root.call(1)); + assertEquals("do1", root.call(2)); + GuardStaticFieldTest.field = false; + try { + root.call(2); + fail("expected Assertion failed"); + } catch (AssertionError e) { + } } - @NodeChild("expression") - public abstract static class GuardWithObject extends ValueNode { + @NodeChild + static class GuardStaticFieldTest extends ValueNode { - boolean baseGuard(Object primitive) { - return true; + static boolean field; + + @Specialization(guards = "field") + static String do1(int value) { + return "do1"; } - @Specialization(guards = "baseGuard(value0)") - int doSpecialized(int value0) { - return value0; + @Specialization + static String do2(int value) { + return "do2"; } } @Test - public void testGuardResolve1() { - TestRootNode root = createRoot(TestGuardResolve1Factory.getInstance()); - - assertEquals(42, executeWith(root, 42)); + public void testGuardMethod() { + CallTarget root = createCallTarget(GuardMethodTestFactory.getInstance()); + assertEquals("do1", root.call(1)); + assertEquals("do2", root.call(2)); + assertEquals("do1", root.call(1)); + assertEquals("do2", root.call(0)); } - @NodeChild("expression") - public abstract static class TestGuardResolve1 extends ValueNode { + @NodeChild + static class GuardMethodTest extends ValueNode { - boolean guard(Object primitive) { - return false; + @Specialization(guards = "method(value)") + static String do1(int value) { + return "do1"; } - boolean guard(int primitive) { - return true; + @Specialization + static String do2(int value) { + return "do2"; } - @Specialization(guards = "guard(value0)") - int doSpecialized(int value0) { - return value0; + boolean method(int value) { + return value == 1; } } @Test - public void testGuardResolve2() { - TestRootNode root = createRoot(TestGuardResolve2Factory.getInstance()); - assertEquals(42, executeWith(root, new BExtendsAbstract())); + public void testGuardUnboundMethodField() { + CallTarget root = createCallTarget(GuardUnboundMethodTestFactory.getInstance()); + GuardUnboundMethodTest node = getNode(root); + node.hiddenValue = true; + assertEquals("do1", root.call(1)); + assertEquals("do1", root.call(2)); + node.hiddenValue = false; + try { + root.call(2); + fail("expected Assertion failed"); + } catch (AssertionError e) { + } } - @NodeChild("expression") - public abstract static class TestGuardResolve2 extends ValueNode { + @NodeChild + static class GuardUnboundMethodTest extends ValueNode { - boolean guard(Object primitive) { - return false; + private boolean hiddenValue; + + @Specialization(guards = "method()") + static String do1(int value) { + return "do1"; } - boolean guard(Abstract primitive) { - return true; + boolean method() { + return hiddenValue; + } + } + + @Test + public void testStaticGuardMethod() { + CallTarget root = createCallTarget(GuardMethodTestFactory.getInstance()); + assertEquals("do1", root.call(1)); + assertEquals("do2", root.call(2)); + assertEquals("do1", root.call(1)); + assertEquals("do2", root.call(0)); + } + + @NodeChild + static class StaticGuardMethodTest extends ValueNode { + + @Specialization(guards = "method(value)") + static String do1(int value) { + return "do1"; } - @Specialization(guards = "guard(value0)") - int doSpecialized(BExtendsAbstract value0) { - return 42; + @Specialization + static String do2(int value) { + return "do2"; + } + + static boolean method(int value) { + return value == 1; } } @Test - public void testGuardResolve3() { - TestRootNode root = createRoot(TestGuardResolve3Factory.getInstance()); - - assertEquals(42, executeWith(root, new BExtendsAbstract())); + public void testMultipleGuardAndMethod() { + CallTarget root = createCallTarget(GuardMultipleAndMethodTestFactory.getInstance()); + assertEquals("do1", root.call(1)); + assertEquals("do1", root.call(2)); + assertEquals("do2", root.call(3)); + assertEquals("do2", root.call(0)); } - @NodeChild("expression") - public abstract static class TestGuardResolve3 extends ValueNode { - - boolean guard(Object primitive) { - return false; - } + @NodeChild + static class GuardMultipleAndMethodTest extends ValueNode { - boolean guard(Abstract primitive) { - return false; - } - - boolean guard(BExtendsAbstract primitive) { - return true; + @Specialization(guards = {"method1(value)", "method2(value)"}) + static String do1(int value) { + return "do1"; } - @Specialization(guards = "guard(value0)") - int doSpecialized(BExtendsAbstract value0) { - return 42; - } - } - - @NodeChild("expression") - public abstract static class TestGuardResolve4 extends ValueNode { - - boolean guard(Abstract primitive) { - return false; + @Specialization + static String do2(int value) { + return "do2"; } - @Specialization(guards = "guard(value0)") - int doSpecialized(BExtendsAbstract value0) { - return 42; - } - } - - @NodeChildren({@NodeChild("a"), @NodeChild("b")}) - abstract static class TestGuardResolve5 extends ValueNode { - - @Specialization(guards = "guard(left, right)") - int add(Interface left, Interface right) { - return 42; + boolean method1(int value) { + return value >= 1; } - boolean guard(Interface left, Object right) { - return true; + boolean method2(int value) { + return value <= 2; } } @Test - public void testAbstractGuard1() { - TestRootNode root = createRoot(TestAbstractGuard1Factory.getInstance()); - - assertEquals(BExtendsAbstract.INSTANCE, executeWith(root, BExtendsAbstract.INSTANCE)); - assertEquals(CExtendsAbstract.INSTANCE, executeWith(root, CExtendsAbstract.INSTANCE)); + public void testMultipleGuardOrMethod() { + CallTarget root = createCallTarget(GuardMultipleOrMethodTestFactory.getInstance()); + assertEquals("do1", root.call(1)); + assertEquals("do1", root.call(2)); + assertEquals("do2", root.call(3)); + assertEquals("do2", root.call(0)); } - @NodeChild("expression") - public abstract static class TestAbstractGuard1 extends ValueNode { + @NodeChild + static class GuardMultipleOrMethodTest extends ValueNode { - boolean guard(Abstract value0) { - return true; + @Specialization(guards = {"method1(value) || method2(value)"}) + static String do1(int value) { + return "do1"; } - @Specialization(guards = "guard(value0)") - BExtendsAbstract do1(BExtendsAbstract value0) { - return value0; + @Specialization + static String do2(int value) { + return "do2"; } - @Specialization(guards = "guard(value0)") - CExtendsAbstract do2(CExtendsAbstract value0) { - return value0; + boolean method1(int value) { + return value == 1; + } + + boolean method2(int value) { + return value == 2; } } + @Test + public void testComplexGuard() { + CallTarget root = createCallTarget(GuardComplexTestFactory.getInstance()); + assertEquals("do1", root.call(1)); + assertEquals("do1", root.call(2)); + assertEquals("do2", root.call(3)); + assertEquals("do1", root.call(0)); + } + + @NodeChild + static class GuardComplexTest extends ValueNode { + + int field1 = 1; + static int field2 = 2; + + @Specialization(guards = {"method2(method1(field1 == 1), value <= 2)", "field2 == 2"}) + static String do1(int value) { + return "do1"; + } + + @Specialization + static String do2(int value) { + return "do2"; + } + + static boolean method1(boolean value) { + return value; + } + + boolean method2(boolean value1, boolean value2) { + return value1 && value2; + } + } + + @NodeChild + static class ErrorGuardNotTest extends ValueNode { + @ExpectError("Error parsing expression '!value == 1': The operator ! is undefined for the argument type int.") + @Specialization(guards = "!value == 1") + static String do1(int value) { + return "do1"; + } + } + + @NodeChild + static class ErrorIncompatibleReturnTypeTest extends ValueNode { + + @ExpectError("Incompatible return type int. Guards must return boolean.") + @Specialization(guards = "1") + static String do1(int value) { + return "do1"; + } + + } + } diff -r 3a37116ef37f -r 62c43fcf5be2 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TestHelper.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TestHelper.java Mon Dec 29 18:32:03 2014 +0100 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TestHelper.java Tue Feb 03 15:07:07 2015 +0100 @@ -84,6 +84,22 @@ return Truffle.getRuntime().createCallTarget(node); } + static RootCallTarget createCallTarget(NodeFactory factory, Object... constants) { + return Truffle.getRuntime().createCallTarget(createRoot(factory, constants)); + } + + static boolean assertionsEnabled() { + boolean assertOn = false; + // *assigns* true if assertions are on. + assert (assertOn = true) == true; + return assertOn; + } + + @SuppressWarnings("unchecked") + static T getNode(CallTarget target) { + return ((TestRootNode) ((RootCallTarget) target).getRootNode()).getNode(); + } + static Object executeWith(TestRootNode node, Object... values) { return createCallTarget(node).call(values); } diff -r 3a37116ef37f -r 62c43fcf5be2 graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/internal/SpecializationNode.java --- a/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/internal/SpecializationNode.java Mon Dec 29 18:32:03 2014 +0100 +++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/internal/SpecializationNode.java Tue Feb 03 15:07:07 2015 +0100 @@ -94,7 +94,7 @@ 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 removeSame(new RewriteEvent0(findRoot(), "merged polymorphic to monomorphic")); } return merged; } @@ -120,6 +120,22 @@ return next != null ? next.merge(newNode) : newNode; } + protected SpecializationNode mergeNoSame(SpecializationNode newNode) { + return next != null ? next.merge(newNode) : newNode; + } + + protected final int countSame(SpecializationNode node) { + return findStart().countSameImpl(node); + } + + private int countSameImpl(SpecializationNode node) { + if (next != null) { + return next.countSameImpl(node) + (isSame(node) ? 1 : 0); + } else { + return 0; + } + } + @Override public final boolean equals(Object obj) { if (obj instanceof SpecializationNode) { @@ -172,7 +188,7 @@ return node; } - private Node findParentNode() { + private Node findRoot() { return findStart().getParent(); } @@ -188,7 +204,7 @@ } current = current.next; } - return start; + return findEnd().findStart(); } public Object acceptAndExecute(Frame frame) { @@ -264,7 +280,7 @@ if (nextSpecialization == null) { return unsupported(frame); } - return insertSpecialization(nextSpecialization, new RewriteEvent0(findParentNode(), "inserted new specialization")).acceptAndExecute(frame); + return insertSpecialization(nextSpecialization, new RewriteEvent0(findRoot(), "inserted new specialization")).acceptAndExecute(frame); } protected final Object uninitialized(Frame frame, Object o1) { @@ -276,7 +292,7 @@ if (nextSpecialization == null) { return unsupported(frame, o1); } - return insertSpecialization(nextSpecialization, new RewriteEvent1(findParentNode(), "inserted new specialization", o1)).acceptAndExecute(frame, o1); + return insertSpecialization(nextSpecialization, new RewriteEvent1(findRoot(), "inserted new specialization", o1)).acceptAndExecute(frame, o1); } protected final Object uninitialized(Frame frame, Object o1, Object o2) { @@ -288,7 +304,7 @@ if (nextSpecialization == null) { return unsupported(frame, o1, o2); } - return insertSpecialization(nextSpecialization, new RewriteEvent2(findParentNode(), "inserted new specialization", o1, o2)).acceptAndExecute(frame, o1, o2); + return insertSpecialization(nextSpecialization, new RewriteEvent2(findRoot(), "inserted new specialization", o1, o2)).acceptAndExecute(frame, o1, o2); } protected final Object uninitialized(Frame frame, Object o1, Object o2, Object o3) { @@ -300,7 +316,7 @@ 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); + return insertSpecialization(nextSpecialization, new RewriteEvent3(findRoot(), "inserted new specialization", o1, o2, o3)).acceptAndExecute(frame, o1, o2, o3); } protected final Object uninitialized(Frame frame, Object o1, Object o2, Object o3, Object o4) { @@ -312,7 +328,7 @@ 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); + return insertSpecialization(nextSpecialization, new RewriteEvent4(findRoot(), "inserts new specialization", o1, o2, o3, o4)).acceptAndExecute(frame, o1, o2, o3, o4); } protected final Object uninitialized(Frame frame, Object o1, Object o2, Object o3, Object o4, Object o5) { @@ -324,7 +340,7 @@ if (nextSpecialization == null) { unsupported(frame, o1, o2, o3, o4, o5); } - return insertSpecialization(nextSpecialization, new RewriteEventN(findParentNode(), "inserts new specialization", o1, o2, o3, o4, o5)).acceptAndExecute(frame, o1, o2, o3, o4, o5); + return insertSpecialization(nextSpecialization, new RewriteEventN(findRoot(), "inserts new specialization", o1, o2, o3, o4, o5)).acceptAndExecute(frame, o1, o2, o3, o4, o5); } protected final Object uninitialized(Frame frame, Object... args) { @@ -336,7 +352,7 @@ if (nextSpecialization == null) { unsupported(frame, args); } - return insertSpecialization(nextSpecialization, new RewriteEventN(findParentNode(), "inserts new specialization", args)).acceptAndExecute(frame, args); + return insertSpecialization(nextSpecialization, new RewriteEventN(findRoot(), "inserts new specialization", args)).acceptAndExecute(frame, args); } private boolean needsPolymorphic() { @@ -344,59 +360,59 @@ } protected final Object remove(String reason, Frame frame) { - return removeSame(new RewriteEvent0(findParentNode(), reason)).acceptAndExecute(frame); + return removeSame(new RewriteEvent0(findRoot(), reason)).acceptAndExecute(frame); } protected final Object remove(String reason, Frame frame, Object o1) { - return removeSame(new RewriteEvent1(findParentNode(), reason, o1)).acceptAndExecute(frame, o1); + return removeSame(new RewriteEvent1(findRoot(), reason, o1)).acceptAndExecute(frame, o1); } protected final Object remove(String reason, Frame frame, Object o1, Object o2) { - return removeSame(new RewriteEvent2(findParentNode(), reason, o1, o2)).acceptAndExecute(frame, o1, o2); + return removeSame(new RewriteEvent2(findRoot(), reason, o1, o2)).acceptAndExecute(frame, o1, o2); } protected final Object remove(String reason, Frame frame, Object o1, Object o2, Object o3) { - return removeSame(new RewriteEvent3(findParentNode(), reason, o1, o2, o3)).acceptAndExecute(frame, o1, o2, o3); + return removeSame(new RewriteEvent3(findRoot(), reason, o1, o2, o3)).acceptAndExecute(frame, o1, o2, o3); } protected final Object remove(String reason, Frame 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); + return removeSame(new RewriteEvent4(findRoot(), reason, o1, o2, o3, o4)).acceptAndExecute(frame, o1, o2, o3, o4); } protected final Object remove(String reason, Frame frame, Object o1, Object o2, Object o3, Object o4, Object o5) { - return removeSame(new RewriteEventN(findParentNode(), reason, o1, o2, o3, o4, o5)).acceptAndExecute(frame, o1, o2, o3, o4, o5); + return removeSame(new RewriteEventN(findRoot(), reason, o1, o2, o3, o4, o5)).acceptAndExecute(frame, o1, o2, o3, o4, o5); } protected final Object remove(String reason, Frame frame, Object... args) { - return removeSame(new RewriteEventN(findParentNode(), reason, args)).acceptAndExecute(frame, args); + return removeSame(new RewriteEventN(findRoot(), reason, args)).acceptAndExecute(frame, args); } protected Object unsupported(Frame frame) { - throw new UnsupportedSpecializationException(findParentNode(), getSuppliedChildren()); + throw new UnsupportedSpecializationException(findRoot(), getSuppliedChildren()); } protected Object unsupported(Frame frame, Object o1) { - throw new UnsupportedSpecializationException(findParentNode(), getSuppliedChildren(), o1); + throw new UnsupportedSpecializationException(findRoot(), getSuppliedChildren(), o1); } protected Object unsupported(Frame frame, Object o1, Object o2) { - throw new UnsupportedSpecializationException(findParentNode(), getSuppliedChildren(), o1, o2); + throw new UnsupportedSpecializationException(findRoot(), getSuppliedChildren(), o1, o2); } protected Object unsupported(Frame frame, Object o1, Object o2, Object o3) { - throw new UnsupportedSpecializationException(findParentNode(), getSuppliedChildren(), o1, o2, o3); + throw new UnsupportedSpecializationException(findRoot(), getSuppliedChildren(), o1, o2, o3); } protected Object unsupported(Frame frame, Object o1, Object o2, Object o3, Object o4) { - throw new UnsupportedSpecializationException(findParentNode(), getSuppliedChildren(), o1, o2, o3, o4); + throw new UnsupportedSpecializationException(findRoot(), getSuppliedChildren(), o1, o2, o3, o4); } protected Object unsupported(Frame frame, Object o1, Object o2, Object o3, Object o4, Object o5) { - throw new UnsupportedSpecializationException(findParentNode(), getSuppliedChildren(), o1, o2, o3, o4, o5); + throw new UnsupportedSpecializationException(findRoot(), getSuppliedChildren(), o1, o2, o3, o4, o5); } protected Object unsupported(Frame frame, Object... args) { - throw new UnsupportedSpecializationException(findParentNode(), getSuppliedChildren(), args); + throw new UnsupportedSpecializationException(findRoot(), getSuppliedChildren(), args); } private SpecializationNode insertSpecialization(final SpecializationNode generated, final CharSequence message) { @@ -428,8 +444,8 @@ return insertBefore(insertBefore, generated, message); } else { // existing node - merged.replace(merged, new RewriteEvent0(merged.findParentNode(), "merged specialization")); - return merged; + merged.replace(merged, new RewriteEvent0(merged.findRoot(), "merged specialization")); + return start; } } diff -r 3a37116ef37f -r 62c43fcf5be2 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/expression/DSLExpression.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/expression/DSLExpression.java Mon Dec 29 18:32:03 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/expression/DSLExpression.java Tue Feb 03 15:07:07 2015 +0100 @@ -36,8 +36,23 @@ return Parser.parse(input); } - public final List findBoundVariables() { - final List variables = new ArrayList<>(); + public final Set findBoundVariableElements() { + final Set variables = new HashSet<>(); + this.accept(new AbstractDSLExpressionVisitor() { + + @Override + public void visitVariable(Variable variable) { + if (variable.getReceiver() == null) { + variables.add(variable.getResolvedVariable()); + } + } + + }); + return variables; + } + + public final Set findBoundVariables() { + final Set variables = new HashSet<>(); this.accept(new AbstractDSLExpressionVisitor() { @Override @@ -52,12 +67,7 @@ } public final boolean isVariableBound(VariableElement variableElement) { - for (Variable variable : findBoundVariables()) { - if (variable.getResolvedVariable() == variableElement) { - return true; - } - } - return false; + return findBoundVariableElements().contains(variableElement); } public abstract TypeMirror getResolvedType(); @@ -217,7 +227,11 @@ @Override public TypeMirror getResolvedType() { - return resolvedMethod != null ? resolvedMethod.getReturnType() : null; + if (resolvedMethod.getKind() == ElementKind.CONSTRUCTOR) { + return resolvedMethod.getEnclosingElement().asType(); + } else { + return resolvedMethod != null ? resolvedMethod.getReturnType() : null; + } } public ExecutableElement getResolvedMethod() { diff -r 3a37116ef37f -r 62c43fcf5be2 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/expression/DSLExpressionResolver.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/expression/DSLExpressionResolver.java Mon Dec 29 18:32:03 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/expression/DSLExpressionResolver.java Tue Feb 03 15:07:07 2015 +0100 @@ -45,29 +45,42 @@ private static final List IDENTITY_OPERATORS = Arrays.asList("==", "!="); private static final String CONSTRUCTOR_KEYWORD = "new"; - private List variables; - private List methods; + private final List variables = new ArrayList<>(); + private final List methods = new ArrayList<>(); private final ProcessorContext context; + private DSLExpressionResolver(ProcessorContext context) { + this.context = context; + } + public DSLExpressionResolver(ProcessorContext context, List lookupElements) { - this.context = context; - this.variables = variablesIn(lookupElements, false); - this.methods = methodsIn(lookupElements); + this(context); + lookup(lookupElements); } - private static List methodsIn(List lookupElements) { - List methods = new ArrayList<>(); + public DSLExpressionResolver copy(List prefixElements) { + DSLExpressionResolver resolver = new DSLExpressionResolver(context); + lookup(prefixElements); + resolver.variables.addAll(variables); + resolver.methods.addAll(methods); + return resolver; + } + + private void lookup(List lookupElements) { + variablesIn(variables, lookupElements, false); + methodsIn(lookupElements); + } + + private void methodsIn(List lookupElements) { for (Element variable : lookupElements) { ElementKind kind = variable.getKind(); if (kind == ElementKind.METHOD || kind == ElementKind.CONSTRUCTOR) { methods.add((ExecutableElement) variable); } } - return methods; } - private static List variablesIn(List lookupElements, boolean publicOnly) { - List variables = new ArrayList<>(); + private static void variablesIn(List variables, List lookupElements, boolean publicOnly) { for (Element variable : lookupElements) { ElementKind kind = variable.getKind(); if (kind == ElementKind.LOCAL_VARIABLE || kind == ElementKind.PARAMETER || kind == ElementKind.FIELD || kind == ElementKind.ENUM_CONSTANT) { @@ -77,7 +90,6 @@ } } } - return variables; } private static String getMethodName(ExecutableElement method) { @@ -189,7 +201,8 @@ TypeMirror type = receiver.getResolvedType(); if (type.getKind() == TypeKind.DECLARED) { type = context.reloadType(type); // ensure ECJ has the type loaded - lookupVariables = variablesIn(context.getEnvironment().getElementUtils().getAllMembers((TypeElement) ((DeclaredType) type).asElement()), true); + lookupVariables = new ArrayList<>(); + variablesIn(lookupVariables, context.getEnvironment().getElementUtils().getAllMembers((TypeElement) ((DeclaredType) type).asElement()), true); } else if (type.getKind() == TypeKind.ARRAY) { lookupVariables = Arrays. asList(new CodeVariableElement(context.getType(int.class), "length")); } else { diff -r 3a37116ef37f -r 62c43fcf5be2 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/expression/Expression.atg --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/expression/Expression.atg Mon Dec 29 18:32:03 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/expression/Expression.atg Tue Feb 03 15:07:07 2015 +0100 @@ -31,9 +31,9 @@ CHARACTERS -letter = 'A'..'Z' + 'a'..'z'. +letter = 'A' .. 'Z' + 'a' .. 'z' + '_' + '$'. nonZeroDigit = "123456789". -digit = "0123456789". +digit = '0' + nonZeroDigit . TOKENS @@ -47,25 +47,35 @@ Expression = +LogicFactor +. + + +LogicFactor += +ComparisonFactor +[ + ("||") (. Token op = t; .) + ComparisonFactor (. result = new Binary(op.val, result, right); .) +] +. + +ComparisonFactor += NegateFactor +[ + ("<" | "<=" | ">" | ">=" | "==" | "!=" ) (. Token op = t; .) + NegateFactor (. result = new Binary(op.val, result, right); .) +] . + NegateFactor = (. boolean negated = false; .) [ "!" (. negated = true; .) ] - LogicFactor (. result = negated ? new Negate(result) : result;.) -. - - -LogicFactor -= -Factor -[ - ("<" | "<=" | ">" | ">=" | "==" | "!=" ) (. Token op = t; .) - Factor (. result = new Binary(op.val, result, right); .) -] + Factor (. result = negated ? new Negate(result) : result;.) . diff -r 3a37116ef37f -r 62c43fcf5be2 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/expression/Parser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/expression/Parser.java Mon Dec 29 18:32:03 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/expression/Parser.java Tue Feb 03 15:07:07 2015 +0100 @@ -34,10 +34,10 @@ // Checkstyle: stop // @formatter:off class Parser { - public static final int _EOF = 0; - public static final int _identifier = 1; - public static final int _numericLiteral = 2; - public static final int maxT = 14; + public static final int _EOF = 0; + public static final int _identifier = 1; + public static final int _numericLiteral = 2; + public static final int maxT = 15; static final boolean _T = true; static final boolean _x = false; @@ -120,122 +120,134 @@ } } - DSLExpression Expression() { - DSLExpression result; - result = NegateFactor(); - return result; - } - - DSLExpression NegateFactor() { - DSLExpression result; - boolean negated = false; - if (la.kind == 3) { - Get(); - negated = true; - } - result = LogicFactor(); - result = negated ? new Negate(result) : result; - return result; - } - - DSLExpression LogicFactor() { - DSLExpression result; - result = Factor(); - if (StartOf(1)) { - switch (la.kind) { - case 4: { - Get(); - break; - } - case 5: { - Get(); - break; - } - case 6: { - Get(); - break; - } - case 7: { - Get(); - break; - } - case 8: { - Get(); - break; - } - case 9: { - Get(); - break; - } - } - Token op = t; - DSLExpression right = Factor(); - result = new Binary(op.val, result, right); - } - return result; - } - - DSLExpression Factor() { - DSLExpression result; - result = null; - if (la.kind == 1) { - result = MemberExpression(result); - } else if (la.kind == 2) { - Get(); - result = new IntLiteral(t.val); - } else if (la.kind == 10) { - Get(); - result = Expression(); - Expect(11); - } else SynErr(15); - return result; - } - - DSLExpression MemberExpression(DSLExpression receiver) { - DSLExpression result; - result = null; - Expect(1); - Variable variable = new Variable(receiver, t.val); - result = variable; - if (la.kind == 10) { - Get(); - List parameters = new ArrayList<>(); - DSLExpression parameter; - if (StartOf(2)) { - parameter = Expression(); - parameters.add(parameter); - while (la.kind == 12) { - Get(); - parameter = Expression(); - parameters.add(parameter); - } - } - Expect(11); - result = new Call(variable.getReceiver(), variable.getName(), parameters); - } - if (la.kind == 13) { - Get(); - result = MemberExpression(result); - } - return result; - } - + DSLExpression Expression() { + DSLExpression result; + result = LogicFactor(); + return result; + } + + DSLExpression LogicFactor() { + DSLExpression result; + result = ComparisonFactor(); + if (la.kind == 3) { + Get(); + Token op = t; + DSLExpression right = ComparisonFactor(); + result = new Binary(op.val, result, right); + } + return result; + } + + DSLExpression ComparisonFactor() { + DSLExpression result; + result = NegateFactor(); + if (StartOf(1)) { + switch (la.kind) { + case 4: { + Get(); + break; + } + case 5: { + Get(); + break; + } + case 6: { + Get(); + break; + } + case 7: { + Get(); + break; + } + case 8: { + Get(); + break; + } + case 9: { + Get(); + break; + } + } + Token op = t; + DSLExpression right = NegateFactor(); + result = new Binary(op.val, result, right); + } + return result; + } + + DSLExpression NegateFactor() { + DSLExpression result; + boolean negated = false; + if (la.kind == 10) { + Get(); + negated = true; + } + result = Factor(); + result = negated ? new Negate(result) : result; + return result; + } + + DSLExpression Factor() { + DSLExpression result; + result = null; + if (la.kind == 1) { + result = MemberExpression(result); + } else if (la.kind == 2) { + Get(); + result = new IntLiteral(t.val); + } else if (la.kind == 11) { + Get(); + result = Expression(); + Expect(12); + } else SynErr(16); + return result; + } + + DSLExpression MemberExpression(DSLExpression receiver) { + DSLExpression result; + result = null; + Expect(1); + Variable variable = new Variable(receiver, t.val); + result = variable; + if (la.kind == 11) { + Get(); + List parameters = new ArrayList<>(); + DSLExpression parameter; + if (StartOf(2)) { + parameter = Expression(); + parameters.add(parameter); + while (la.kind == 13) { + Get(); + parameter = Expression(); + parameters.add(parameter); + } + } + Expect(12); + result = new Call(variable.getReceiver(), variable.getName(), parameters); + } + if (la.kind == 14) { + Get(); + result = MemberExpression(result); + } + return result; + } + private DSLExpression parseImpl() { la = new Token(); la.val = ""; Get(); - DSLExpression result = Expression(); - Expect(0); + DSLExpression result = Expression(); + Expect(0); return result; } private static final boolean[][] set = { - {_T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x}, - {_x,_x,_x,_x, _T,_T,_T,_T, _T,_T,_x,_x, _x,_x,_x,_x}, - {_x,_T,_T,_T, _x,_x,_x,_x, _x,_x,_T,_x, _x,_x,_x,_x} + {_T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x}, + {_x,_x,_x,_x, _T,_T,_T,_T, _T,_T,_x,_x, _x,_x,_x,_x, _x}, + {_x,_T,_T,_x, _x,_x,_x,_x, _x,_x,_T,_T, _x,_x,_x,_x, _x} }; @@ -282,23 +294,24 @@ public void SynErr(int line, int col, int n) { String s; - switch (n) { - case 0: s = "EOF expected"; break; - case 1: s = "identifier expected"; break; - case 2: s = "numericLiteral expected"; break; - case 3: s = "\"!\" expected"; break; - case 4: s = "\"<\" expected"; break; - case 5: s = "\"<=\" expected"; break; - case 6: s = "\">\" expected"; break; - case 7: s = "\">=\" expected"; break; - case 8: s = "\"==\" expected"; break; - case 9: s = "\"!=\" expected"; break; - case 10: s = "\"(\" expected"; break; - case 11: s = "\")\" expected"; break; - case 12: s = "\",\" expected"; break; - case 13: s = "\".\" expected"; break; - case 14: s = "??? expected"; break; - case 15: s = "invalid Factor"; break; + switch (n) { + case 0: s = "EOF expected"; break; + case 1: s = "identifier expected"; break; + case 2: s = "numericLiteral expected"; break; + case 3: s = "\"||\" expected"; break; + case 4: s = "\"<\" expected"; break; + case 5: s = "\"<=\" expected"; break; + case 6: s = "\">\" expected"; break; + case 7: s = "\">=\" expected"; break; + case 8: s = "\"==\" expected"; break; + case 9: s = "\"!=\" expected"; break; + case 10: s = "\"!\" expected"; break; + case 11: s = "\"(\" expected"; break; + case 12: s = "\")\" expected"; break; + case 13: s = "\",\" expected"; break; + case 14: s = "\".\" expected"; break; + case 15: s = "??? expected"; break; + case 16: s = "invalid Factor"; break; default: s = "error " + n; break; diff -r 3a37116ef37f -r 62c43fcf5be2 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/expression/Scanner.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/expression/Scanner.java Mon Dec 29 18:32:03 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/expression/Scanner.java Tue Feb 03 15:07:07 2015 +0100 @@ -311,8 +311,8 @@ static final char EOL = '\n'; static final int eofSym = 0; - static final int maxT = 14; - static final int noSym = 14; + static final int maxT = 15; + static final int noSym = 15; public Buffer buffer; // scanner buffer @@ -336,19 +336,22 @@ static { start = new StartStates(); literals = new HashMap(); - for (int i = 65; i <= 90; ++i) start.set(i, 1); - for (int i = 97; i <= 122; ++i) start.set(i, 1); - for (int i = 49; i <= 57; ++i) start.set(i, 2); - start.set(48, 3); - start.set(33, 13); - start.set(60, 14); - start.set(62, 15); - start.set(61, 6); - start.set(40, 9); - start.set(41, 10); - start.set(44, 11); - start.set(46, 12); - start.set(Buffer.EOF, -1); + for (int i = 36; i <= 36; ++i) start.set(i, 1); + for (int i = 65; i <= 90; ++i) start.set(i, 1); + for (int i = 95; i <= 95; ++i) start.set(i, 1); + for (int i = 97; i <= 122; ++i) start.set(i, 1); + for (int i = 49; i <= 57; ++i) start.set(i, 2); + start.set(48, 3); + start.set(124, 4); + start.set(60, 15); + start.set(62, 16); + start.set(61, 8); + start.set(33, 17); + start.set(40, 11); + start.set(41, 12); + start.set(44, 13); + start.set(46, 14); + start.set(Buffer.EOF, -1); } @@ -414,7 +417,7 @@ tval = newBuf; } if (ch != Buffer.EOF) { - tval[tlen++] = (char)ch; + tval[tlen++] = (char)ch; NextCh(); } @@ -461,47 +464,52 @@ t.kind = recKind; break loop; } // NextCh already done - case 1: - recEnd = pos; recKind = 1; - if (ch >= '0' && ch <= '9' || ch >= 'A' && ch <= 'Z' || ch >= 'a' && ch <= 'z') {AddCh(); state = 1; break;} - else {t.kind = 1; break loop;} - case 2: - recEnd = pos; recKind = 2; - if (ch >= '0' && ch <= '9') {AddCh(); state = 2; break;} - else {t.kind = 2; break loop;} - case 3: - {t.kind = 2; break loop;} - case 4: - {t.kind = 5; break loop;} - case 5: - {t.kind = 7; break loop;} - case 6: - if (ch == '=') {AddCh(); state = 7; break;} - else {state = 0; break;} - case 7: - {t.kind = 8; break loop;} - case 8: - {t.kind = 9; break loop;} - case 9: - {t.kind = 10; break loop;} - case 10: - {t.kind = 11; break loop;} - case 11: - {t.kind = 12; break loop;} - case 12: - {t.kind = 13; break loop;} - case 13: - recEnd = pos; recKind = 3; - if (ch == '=') {AddCh(); state = 8; break;} - else {t.kind = 3; break loop;} - case 14: - recEnd = pos; recKind = 4; - if (ch == '=') {AddCh(); state = 4; break;} - else {t.kind = 4; break loop;} - case 15: - recEnd = pos; recKind = 6; - if (ch == '=') {AddCh(); state = 5; break;} - else {t.kind = 6; break loop;} + case 1: + recEnd = pos; recKind = 1; + if (ch == '$' || ch >= '0' && ch <= '9' || ch >= 'A' && ch <= 'Z' || ch == '_' || ch >= 'a' && ch <= 'z') {AddCh(); state = 1; break;} + else {t.kind = 1; break loop;} + case 2: + recEnd = pos; recKind = 2; + if (ch >= '0' && ch <= '9') {AddCh(); state = 2; break;} + else {t.kind = 2; break loop;} + case 3: + {t.kind = 2; break loop;} + case 4: + if (ch == '|') {AddCh(); state = 5; break;} + else {state = 0; break;} + case 5: + {t.kind = 3; break loop;} + case 6: + {t.kind = 5; break loop;} + case 7: + {t.kind = 7; break loop;} + case 8: + if (ch == '=') {AddCh(); state = 9; break;} + else {state = 0; break;} + case 9: + {t.kind = 8; break loop;} + case 10: + {t.kind = 9; break loop;} + case 11: + {t.kind = 11; break loop;} + case 12: + {t.kind = 12; break loop;} + case 13: + {t.kind = 13; break loop;} + case 14: + {t.kind = 14; break loop;} + case 15: + recEnd = pos; recKind = 4; + if (ch == '=') {AddCh(); state = 6; break;} + else {t.kind = 4; break loop;} + case 16: + recEnd = pos; recKind = 6; + if (ch == '=') {AddCh(); state = 7; break;} + else {t.kind = 6; break loop;} + case 17: + recEnd = pos; recKind = 10; + if (ch == '=') {AddCh(); state = 10; break;} + else {t.kind = 10; break loop;} } } diff -r 3a37116ef37f -r 62c43fcf5be2 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/DSLExpressionGenerator.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/DSLExpressionGenerator.java Mon Dec 29 18:32:03 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/DSLExpressionGenerator.java Tue Feb 03 15:07:07 2015 +0100 @@ -61,7 +61,9 @@ CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); - if (call.getReceiver() == null) { + if (call.getResolvedMethod().getKind() == ElementKind.CONSTRUCTOR) { + builder.startNew(call.getResolvedType()); + } else if (call.getReceiver() == null) { if (isStatic(method)) { builder.startStaticCall(method); } else { @@ -89,7 +91,7 @@ } public void visitNegate(Negate negate) { - push(combine(string("!"), pop())); + push(combine(string("!"), combine(string("("), pop(), string(")")))); } public void visitVariable(Variable variable) { @@ -136,7 +138,7 @@ } private static CodeTree staticReference(VariableElement var) { - return CodeTreeBuilder.createBuilder().staticReference(var.asType(), var.getSimpleName().toString()).build(); + return CodeTreeBuilder.createBuilder().staticReference(var.getEnclosingElement().asType(), var.getSimpleName().toString()).build(); } private void push(CodeTree tree) { @@ -150,7 +152,7 @@ public static CodeTree write(DSLExpression expression, CodeTree root, Map bindings) { DSLExpressionGenerator writer = new DSLExpressionGenerator(root, bindings); expression.accept(writer); - return writer.pop(); + return combine(string("("), writer.pop(), string(")")); } } diff -r 3a37116ef37f -r 62c43fcf5be2 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java Mon Dec 29 18:32:03 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java Tue Feb 03 15:07:07 2015 +0100 @@ -42,11 +42,13 @@ import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.api.nodes.Node.Child; +import com.oracle.truffle.api.nodes.Node.Children; import com.oracle.truffle.dsl.processor.*; import com.oracle.truffle.dsl.processor.expression.*; import com.oracle.truffle.dsl.processor.expression.DSLExpression.Variable; import com.oracle.truffle.dsl.processor.java.*; import com.oracle.truffle.dsl.processor.java.model.*; +import com.oracle.truffle.dsl.processor.java.model.CodeTypeMirror.ArrayCodeTypeMirror; import com.oracle.truffle.dsl.processor.model.*; import com.oracle.truffle.dsl.processor.parser.*; import com.oracle.truffle.dsl.processor.parser.SpecializationGroup.TypeGuard; @@ -54,8 +56,8 @@ public class NodeGenFactory { private static final String FRAME_VALUE = TemplateMethod.FRAME_NAME; - private static final String NAME_SUFFIX = "_"; + private static final String NODE_SUFFIX = "NodeGen"; private final ProcessorContext context; private final NodeData node; @@ -90,7 +92,7 @@ } public static String nodeTypeName(NodeData node) { - return resolveNodeId(node) + "NodeGen"; + return resolveNodeId(node) + NODE_SUFFIX; } private static String resolveNodeId(NodeData node) { @@ -242,7 +244,7 @@ private Element createUnsupportedMethod() { LocalContext locals = LocalContext.load(this); - CodeExecutableElement method = locals.createMethod(modifiers(PRIVATE), getType(UnsupportedSpecializationException.class), "unsupported"); + CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED), getType(UnsupportedSpecializationException.class), "unsupported"); CodeTreeBuilder builder = method.createBuilder(); builder.startReturn(); @@ -320,7 +322,7 @@ return constructor; } - public static boolean mayBeExcluded(SpecializationData specialization) { + private static boolean mayBeExcluded(SpecializationData specialization) { return !specialization.getExceptions().isEmpty() || !specialization.getExcludedBy().isEmpty(); } @@ -334,7 +336,7 @@ List generateSpecializations = new ArrayList<>(); generateSpecializations.add(node.getUninitializedSpecialization()); - if (needsPolymorphic(reachableSpecializations)) { + if (needsPolymorphic()) { generateSpecializations.add(node.getPolymorphicSpecialization()); } generateSpecializations.addAll(reachableSpecializations); @@ -350,6 +352,26 @@ return node.getUninitializedSpecialization(); } + private boolean needsPolymorphic() { + List reachableSpecializations = getReachableSpecializations(); + if (reachableSpecializations.size() != 1) { + return true; + } + + SpecializationData specialization = reachableSpecializations.get(0); + for (Parameter parameter : specialization.getSignatureParameters()) { + TypeData type = parameter.getTypeSystemType(); + if (type != null && type.hasImplicitSourceTypes()) { + return true; + } + } + if (specialization.hasMultipleInstances()) { + return true; + } + return false; + + } + // create specialization private CodeTypeElement createBaseSpecialization() { @@ -492,7 +514,8 @@ } private Element createMergeMethod(SpecializationData specialization) { - if (specialization.getExcludedBy().isEmpty() && !specialization.isPolymorphic()) { + boolean cacheBoundGuard = specialization.hasMultipleInstances(); + if (specialization.getExcludedBy().isEmpty() && !specialization.isPolymorphic() && !cacheBoundGuard) { return null; } TypeMirror specializationNodeType = getType(SpecializationNode.class); @@ -513,7 +536,11 @@ builder.statement("removeSame(\"Contained by " + containedSpecialization.createReferenceName() + "\")"); builder.end(); } - builder.statement("return super.merge(newNode)"); + if (cacheBoundGuard) { + builder.statement("return super.mergeNoSame(newNode)"); + } else { + builder.statement("return super.merge(newNode)"); + } } return executable; @@ -555,21 +582,6 @@ 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) { @@ -614,7 +626,7 @@ if (generatedType == null) { throw new AssertionError("No generated type for " + specialization); } - return createSlowPathExecute(specialization, locals); + return createSlowPathExecute(specialization, values); } public boolean isFastPath() { @@ -624,7 +636,7 @@ builder.tree(execution); - if (hasFallthrough(group, genericType, locals, false)) { + if (hasFallthrough(group, genericType, locals, false, null)) { builder.returnNull(); } return method; @@ -713,8 +725,6 @@ return evaluatedCount; } - // create specialization - private Element createUnsupported() { SpecializationData fallback = node.getGenericSpecialization(); if (fallback == null || optimizeFallback(fallback) || fallback.getMethod() == null) { @@ -738,12 +748,20 @@ if (reachableSpecializations.size() != 1) { return false; } - for (Parameter parameter : reachableSpecializations.get(0).getSignatureParameters()) { + + SpecializationData specialization = reachableSpecializations.get(0); + + for (Parameter parameter : specialization.getSignatureParameters()) { TypeData type = parameter.getTypeSystemType(); if (type != null && type.hasImplicitSourceTypes()) { return false; } } + if (specialization.getCaches().size() > 0) { + // TODO chumer: caches do not yet support single specialization. + // it could be worthwhile to explore if this is possible + return false; + } return true; } @@ -1014,6 +1032,7 @@ if (specialization.isFallback()) { return builder.returnNull().build(); } + if (node.isFrameUsedByAnyGuard()) { builder.tree(createTransferToInterpreterAndInvalidate()); } @@ -1029,7 +1048,27 @@ } } - builder.startReturn().tree(createCallCreateMethod(specialization, null, currentValues)).end(); + CodeTree create = createCallCreateMethod(specialization, null, currentValues); + + if (specialization.hasMultipleInstances()) { + builder.declaration(getType(SpecializationNode.class), "s", create); + + DSLExpression limitExpression = specialization.getLimitExpression(); + CodeTree limitExpressionTree; + if (limitExpression == null) { + limitExpressionTree = CodeTreeBuilder.singleString("3"); + } else { + limitExpressionTree = DSLExpressionGenerator.write(limitExpression, accessParent(null), // + castBoundTypes(bindExpressionValues(limitExpression, specialization, currentValues))); + } + + builder.startIf().string("countSame(s) < ").tree(limitExpressionTree).end().startBlock(); + builder.statement("return s"); + builder.end(); + + } else { + builder.startReturn().tree(create).end(); + } if (mayBeExcluded(specialization)) { CodeTreeBuilder checkHasSeenBuilder = builder.create(); @@ -1041,7 +1080,7 @@ return builder.build(); } - private static boolean hasFallthrough(SpecializationGroup group, TypeData forType, LocalContext currentValues, boolean fastPath) { + private boolean hasFallthrough(SpecializationGroup group, TypeData forType, LocalContext currentValues, boolean fastPath, List ignoreGuards) { for (TypeGuard guard : group.getTypeGuards()) { if (currentValues.getValue(guard.getSignatureIndex()) == null) { // not evaluated @@ -1053,9 +1092,23 @@ } } - List expressions = new ArrayList<>(group.getGuards()); - expressions.removeAll(group.findElseConnectableGuards()); - if (!expressions.isEmpty()) { + List guards = new ArrayList<>(group.getGuards()); + List elseConnectable = group.findElseConnectableGuards(); + guards.removeAll(elseConnectable); + if (ignoreGuards != null) { + guards.removeAll(ignoreGuards); + } + SpecializationData specialization = group.getSpecialization(); + if (specialization != null && fastPath) { + for (ListIterator iterator = guards.listIterator(); iterator.hasNext();) { + GuardExpression guard = iterator.next(); + if (!specialization.isDynamicParameterBound(guard.getExpression())) { + iterator.remove(); + } + } + } + + if (!guards.isEmpty()) { return true; } @@ -1063,12 +1116,20 @@ return true; } - if (!fastPath && group.getSpecialization() != null && mayBeExcluded(group.getSpecialization())) { + if (!fastPath && specialization != null && mayBeExcluded(specialization)) { return true; } - if (!group.getChildren().isEmpty()) { - return hasFallthrough(group.getChildren().get(group.getChildren().size() - 1), forType, currentValues, fastPath); + if (!elseConnectable.isEmpty()) { + SpecializationGroup previous = group.getPrevious(); + if (previous != null && hasFallthrough(previous, forType, currentValues, fastPath, previous.getGuards())) { + return true; + } + } + + List groupChildren = group.getChildren(); + if (!groupChildren.isEmpty()) { + return hasFallthrough(groupChildren.get(groupChildren.size() - 1), forType, currentValues, fastPath, ignoreGuards); } return false; @@ -1119,12 +1180,20 @@ } 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()); + // we need the original name here + builder.tree(LocalVariable.fromParameter(p).createReference()); } } + for (CacheExpression cache : specialization.getCaches()) { + LocalVariable variable = currentValues.get(cache.getParameter().getLocalName()); + if (variable == null) { + throw new AssertionError("Could not bind cached value " + cache.getParameter().getLocalName() + ": " + currentValues); + } + builder.tree(variable.createReference()); + } + } builder.end(); @@ -1201,6 +1270,23 @@ } } } + for (CacheExpression cache : specialization.getCaches()) { + String name = cache.getParameter().getLocalName(); + TypeMirror type = cache.getParameter().getType(); + + if (ElementUtils.isAssignable(type, new ArrayCodeTypeMirror(getType(Node.class)))) { + CodeVariableElement var = clazz.add(new CodeVariableElement(modifiers(PRIVATE, FINAL), type, name)); + var.addAnnotationMirror(new CodeAnnotationMirror(context.getDeclaredType(Children.class))); + } else if (ElementUtils.isAssignable(type, getType(Node.class))) { + CodeVariableElement var = clazz.add(new CodeVariableElement(modifiers(PRIVATE), type, name)); + var.addAnnotationMirror(new CodeAnnotationMirror(context.getDeclaredType(Child.class))); + } else { + clazz.add(new CodeVariableElement(modifiers(PRIVATE, FINAL), type, name)); + } + constructor.addParameter(new CodeVariableElement(type, name)); + builder.startStatement().string("this.").string(name).string(" = ").string(name).end(); + } + } if (constructor.getParameters().isEmpty()) { @@ -1302,6 +1388,10 @@ TypeData type = forType == null ? genericType : forType; LocalContext currentLocals = LocalContext.load(this, evaluatedArguments, varArgsThreshold); + if (specialization != null) { + currentLocals.loadFastPathCachedValues(specialization); + } + CodeExecutableElement executable = currentLocals.createMethod(modifiers(PUBLIC), type.getPrimitiveType(), TypeSystemNodeFactory.executeName(forType), FRAME_VALUE); executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); @@ -1354,7 +1444,7 @@ } }; builder.tree(createGuardAndCast(group, type, currentLocals, executionFactory)); - if (hasFallthrough(group, type, originalValues, true) || group.getSpecialization().isFallback()) { + if (hasFallthrough(group, type, originalValues, true, null) || group.getSpecialization().isFallback()) { builder.tree(createCallNext(type, originalValues)); } } @@ -1428,19 +1518,24 @@ } else { castGuards = new HashSet<>(); for (TypeGuard castGuard : group.getTypeGuards()) { - if (isTypeGuardUsedInAnyGuardBelow(group, currentValues, castGuard)) { + if (isTypeGuardUsedInAnyGuardOrCacheBelow(group, currentValues, castGuard)) { castGuards.add(castGuard); } } } - CodeTree[] checkAndCast = createTypeCheckAndCast(group.getTypeGuards(), castGuards, currentValues, execution); + + SpecializationData specialization = group.getSpecialization(); + CodeTree[] checkAndCast = createTypeCheckCastAndCaches(specialization, 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, group.getSpecialization(), currentValues); + CodeTree[] methodGuardAndAssertions = createMethodGuardCheck(guardExpressions, specialization, currentValues, execution.isFastPath()); + CodeTree methodGuards = methodGuardAndAssertions[0]; + CodeTree guardAssertions = methodGuardAndAssertions[1]; if (!group.getAssumptions().isEmpty()) { if (execution.isFastPath() && !forType.isGeneric()) { @@ -1460,6 +1555,9 @@ if (!cast.isEmpty()) { builder.tree(cast); } + if (!guardAssertions.isEmpty()) { + builder.tree(guardAssertions); + } boolean elseIf = !elseGuardExpressions.isEmpty(); if (!methodGuards.isEmpty()) { builder.startIf(elseIf); @@ -1476,7 +1574,6 @@ 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)); } @@ -1534,21 +1631,25 @@ return true; } - private boolean isTypeGuardUsedInAnyGuardBelow(SpecializationGroup group, LocalContext currentValues, TypeGuard typeGuard) { - LocalVariable localVariable = currentValues.getValue(typeGuard.getSignatureIndex()); + private boolean isTypeGuardUsedInAnyGuardOrCacheBelow(SpecializationGroup group, LocalContext currentValues, TypeGuard typeGuard) { + String localName = currentValues.getValue(typeGuard.getSignatureIndex()).getName(); + SpecializationData specialization = group.getSpecialization(); for (GuardExpression guard : group.getGuards()) { - Map boundValues = bindLocalValues(guard.getExpression(), group.getSpecialization(), currentValues); - for (Variable var : guard.getExpression().findBoundVariables()) { - LocalVariable target = boundValues.get(var); - if (localVariable.getName().equals(target.getName())) { + if (isVariableBoundIn(specialization, guard.getExpression(), localName, currentValues)) { + return true; + } + } + if (specialization != null) { + for (CacheExpression cache : specialization.getCaches()) { + if (isVariableBoundIn(specialization, cache.getExpression(), localName, currentValues)) { return true; } } } for (SpecializationGroup child : group.getChildren()) { - if (isTypeGuardUsedInAnyGuardBelow(child, currentValues, typeGuard)) { + if (isTypeGuardUsedInAnyGuardOrCacheBelow(child, currentValues, typeGuard)) { return true; } } @@ -1556,6 +1657,17 @@ return false; } + private static boolean isVariableBoundIn(SpecializationData specialization, DSLExpression expression, String localName, LocalContext currentValues) throws AssertionError { + Map boundValues = bindExpressionValues(expression, specialization, currentValues); + for (Variable var : expression.findBoundVariables()) { + LocalVariable target = boundValues.get(var); + if (target != null && localName.equals(target.getName())) { + return true; + } + } + return false; + } + private CodeExecutableElement createExecuteChildMethod(NodeExecutionData execution, TypeData targetType) { LocalContext locals = LocalContext.load(this, 0, varArgsThreshold); @@ -1947,33 +2059,48 @@ return builder.build(); } - private CodeTree createMethodGuardCheck(List guardExpressions, SpecializationData specialization, LocalContext currentValues) { - CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); + private CodeTree[] createMethodGuardCheck(List guardExpressions, SpecializationData specialization, LocalContext currentValues, boolean fastPath) { + CodeTreeBuilder expressionBuilder = CodeTreeBuilder.createBuilder(); + CodeTreeBuilder assertionBuilder = CodeTreeBuilder.createBuilder(); String and = ""; for (GuardExpression guard : guardExpressions) { DSLExpression expression = guard.getExpression(); - Map bindings = bindLocalValues(expression, specialization, currentValues); - Map resolvedBindings = new HashMap<>(); - for (Variable variable : bindings.keySet()) { - LocalVariable localVariable = bindings.get(variable); - CodeTree resolved = CodeTreeBuilder.singleString(localVariable.getName()); - if (!ElementUtils.typeEquals(variable.getResolvedType(), localVariable.getTypeMirror())) { - resolved = CodeTreeBuilder.createBuilder().cast(variable.getResolvedType(), resolved).build(); - } - resolvedBindings.put(variable, resolved); + + Map resolvedBindings = castBoundTypes(bindExpressionValues(expression, specialization, currentValues)); + CodeTree expressionCode = DSLExpressionGenerator.write(expression, accessParent(null), resolvedBindings); + + if (!specialization.isDynamicParameterBound(expression) && fastPath) { + /* + * Guards where no dynamic parameters are bound can just be executed on the fast + * path. + */ + assertionBuilder.startAssert().tree(expressionCode).end(); + } else { + expressionBuilder.string(and); + expressionBuilder.tree(expressionCode); + and = " && "; } - - builder.string(and); - builder.tree(DSLExpressionGenerator.write(expression, accessParent(null), resolvedBindings)); - and = " && "; } - return builder.build(); + return new CodeTree[]{expressionBuilder.build(), assertionBuilder.build()}; } - private static Map bindLocalValues(DSLExpression expression, SpecializationData specialization, LocalContext currentValues) throws AssertionError { + private static Map castBoundTypes(Map bindings) { + Map resolvedBindings = new HashMap<>(); + for (Variable variable : bindings.keySet()) { + LocalVariable localVariable = bindings.get(variable); + CodeTree resolved = localVariable.createReference(); + if (!ElementUtils.typeEquals(variable.getResolvedType(), localVariable.getTypeMirror())) { + resolved = CodeTreeBuilder.createBuilder().cast(variable.getResolvedType(), resolved).build(); + } + resolvedBindings.put(variable, resolved); + } + return resolvedBindings; + } + + private static Map bindExpressionValues(DSLExpression expression, SpecializationData specialization, LocalContext currentValues) throws AssertionError { Map bindings = new HashMap<>(); - List boundVariables = expression.findBoundVariables(); + Set boundVariables = expression.findBoundVariables(); if (specialization == null && !boundVariables.isEmpty()) { throw new AssertionError("Cannot bind guard variable in non-specialization group. yet."); } @@ -1989,18 +2116,18 @@ } else { localVariable = currentValues.get(resolvedParameter.getLocalName()); } - if (localVariable == null) { - throw new AssertionError("Could not resolve local for execution."); + if (localVariable != null) { + bindings.put(variable, localVariable); } - bindings.put(variable, localVariable); } } return bindings; } - private CodeTree[] createTypeCheckAndCast(List typeGuards, Set castGuards, LocalContext currentValues, SpecializationExecution specializationExecution) { + private CodeTree[] createTypeCheckCastAndCaches(SpecializationData specialization, List typeGuards, Set castGuards, LocalContext currentValues, + SpecializationExecution specializationExecution) { CodeTreeBuilder checksBuilder = CodeTreeBuilder.createBuilder(); - CodeTreeBuilder castsBuilder = CodeTreeBuilder.createBuilder(); + CodeTreeBuilder castsAndCaches = CodeTreeBuilder.createBuilder(); for (TypeGuard typeGuard : typeGuards) { int signatureIndex = typeGuard.getSignatureIndex(); LocalVariable value = currentValues.getValue(signatureIndex); @@ -2061,12 +2188,26 @@ 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())); + castsAndCaches.tree(castVariable.createDeclaration(castBuilder.build())); } checksBuilder.tree(checkBuilder.build()); } - return new CodeTree[]{checksBuilder.build(), castsBuilder.build()}; + + if (specialization != null && !specializationExecution.isFastPath()) { + for (CacheExpression cache : specialization.getCaches()) { + CodeTree initializer = DSLExpressionGenerator.write(cache.getExpression(), accessParent(null), + castBoundTypes(bindExpressionValues(cache.getExpression(), specialization, currentValues))); + String name = cache.getParameter().getLocalName(); + // multiple specializations might use the same name + String varName = name + specialization.getIndex(); + TypeMirror type = cache.getParameter().getType(); + castsAndCaches.declaration(type, varName, initializer); + currentValues.set(name, new LocalVariable(null, type, varName, null)); + } + } + + return new CodeTree[]{checksBuilder.build(), castsAndCaches.build()}; } public static final class LocalContext { @@ -2078,6 +2219,14 @@ this.factory = factory; } + public void loadFastPathCachedValues(SpecializationData specialization) { + for (CacheExpression cache : specialization.getCaches()) { + Parameter cacheParameter = cache.getParameter(); + String name = cacheParameter.getVariableElement().getSimpleName().toString(); + set(cacheParameter.getLocalName(), new LocalVariable(cacheParameter.getTypeSystemType(), cacheParameter.getType(), name, CodeTreeBuilder.singleString("this." + name))); + } + } + public CodeExecutableElement createMethod(Set modifiers, TypeMirror returnType, String name, String... optionalArguments) { CodeExecutableElement method = new CodeExecutableElement(modifiers, returnType, name); addParametersTo(method, optionalArguments); diff -r 3a37116ef37f -r 62c43fcf5be2 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 18:32:03 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java Tue Feb 03 15:07:07 2015 +0100 @@ -1120,4 +1120,53 @@ return types; } + public static boolean variableEquals(VariableElement var1, VariableElement var2) { + if (!var1.getSimpleName().equals(var2.getSimpleName())) { + return false; + } + if (!ElementUtils.typeEquals(var1.asType(), var2.asType())) { + return false; + } + if (!ElementUtils.elementEquals(var1.getEnclosingElement(), var2.getEnclosingElement())) { + return false; + } + return true; + } + + public static boolean executableEquals(ExecutableElement var1, ExecutableElement var2) { + if (!var1.getSimpleName().equals(var2.getSimpleName())) { + return false; + } + if (var1.getParameters().size() != var2.getParameters().size()) { + return false; + } + if (!ElementUtils.typeEquals(var1.asType(), var2.asType())) { + return false; + } + if (!ElementUtils.elementEquals(var1.getEnclosingElement(), var2.getEnclosingElement())) { + return false; + } + for (int i = 0; i < var1.getParameters().size(); i++) { + if (!typeEquals(var1.getParameters().get(i).asType(), var2.getParameters().get(i).asType())) { + return false; + } + } + return true; + } + + public static boolean elementEquals(Element element1, Element element2) { + if (element1.getKind() != element2.getKind()) { + return false; + } else if (element1 instanceof VariableElement) { + return variableEquals((VariableElement) element1, (VariableElement) element2); + } else if (element1 instanceof ExecutableElement) { + return executableEquals((ExecutableElement) element1, (ExecutableElement) element2); + } else if (element1 instanceof TypeElement) { + return typeEquals(element1.asType(), element2.asType()); + } else if (element1 instanceof PackageElement) { + return element1.getSimpleName().equals(element2.getSimpleName()); + } else { + throw new AssertionError("unsupported element type"); + } + } } diff -r 3a37116ef37f -r 62c43fcf5be2 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/AnnotatedParameterSpec.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/AnnotatedParameterSpec.java Tue Feb 03 15:07:07 2015 +0100 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.dsl.processor.model; + +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +import com.oracle.truffle.dsl.processor.java.*; + +public final class AnnotatedParameterSpec extends ParameterSpec { + + private final DeclaredType annotationType; + + public AnnotatedParameterSpec(DeclaredType type) { + super("annotated", Collections. emptyList()); + this.annotationType = type; + } + + public DeclaredType getAnnotationType() { + return annotationType; + } + + @Override + public boolean matches(VariableElement variable) { + if (ElementUtils.findAnnotationMirror(variable.getAnnotationMirrors(), annotationType) != null) { + return true; + } + return false; + } + +} diff -r 3a37116ef37f -r 62c43fcf5be2 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/CacheExpression.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/CacheExpression.java Mon Dec 29 18:32:03 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/CacheExpression.java Tue Feb 03 15:07:07 2015 +0100 @@ -39,6 +39,10 @@ this.sourceAnnotationMirror = sourceAnnotationMirror; } + public Parameter getParameter() { + return sourceParameter; + } + @Override public Element getMessageElement() { return sourceParameter.getVariableElement(); diff -r 3a37116ef37f -r 62c43fcf5be2 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/MessageContainer.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/MessageContainer.java Mon Dec 29 18:32:03 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/MessageContainer.java Tue Feb 03 15:07:07 2015 +0100 @@ -119,7 +119,7 @@ TypeElement expectError = context.getTruffleTypes().getExpectError(); if (expectError != null) { Element element = getMessageElement(); - AnnotationMirror mirror = ElementUtils.findAnnotationMirror(element.getAnnotationMirrors(), expectError); + AnnotationMirror mirror = ElementUtils.findAnnotationMirror(element.getAnnotationMirrors(), expectError.asType()); if (mirror != null) { List values = ElementUtils.getAnnotationValueList(String.class, mirror, "value"); if (values == null) { @@ -149,7 +149,7 @@ TypeElement expectError = context.getTruffleTypes().getExpectError(); if (expectError != null) { - AnnotationMirror mirror = ElementUtils.findAnnotationMirror(messageElement.getAnnotationMirrors(), expectError); + AnnotationMirror mirror = ElementUtils.findAnnotationMirror(messageElement.getAnnotationMirrors(), expectError.asType()); if (mirror != null) { List expectedTexts = ElementUtils.getAnnotationValueList(String.class, mirror, "value"); boolean found = false; diff -r 3a37116ef37f -r 62c43fcf5be2 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/MethodSpec.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/MethodSpec.java Mon Dec 29 18:32:03 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/MethodSpec.java Tue Feb 03 15:07:07 2015 +0100 @@ -33,6 +33,7 @@ private final ParameterSpec returnType; private final List optional = new ArrayList<>(); private final List required = new ArrayList<>(); + private final List annotations = new ArrayList<>(); private boolean ignoreAdditionalParameters; private boolean ignoreAdditionalSpecifications; @@ -69,6 +70,10 @@ return spec; } + public List getAnnotations() { + return annotations; + } + public ParameterSpec getReturnType() { return returnType; } diff -r 3a37116ef37f -r 62c43fcf5be2 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeFieldData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeFieldData.java Mon Dec 29 18:32:03 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeFieldData.java Tue Feb 03 15:07:07 2015 +0100 @@ -29,17 +29,19 @@ private final Element messageElement; private final AnnotationMirror messageAnnotation; - private final String name; - private final TypeMirror type; private final boolean generated; private ExecutableElement getter; + private final VariableElement variable; - public NodeFieldData(Element messageElement, AnnotationMirror messageAnnotation, TypeMirror type, String name, boolean generated) { + public NodeFieldData(Element messageElement, AnnotationMirror messageAnnotation, VariableElement variableElement, boolean generated) { this.messageElement = messageElement; this.messageAnnotation = messageAnnotation; - this.name = name; - this.type = type; this.generated = generated; + this.variable = variableElement; + } + + public VariableElement getVariable() { + return variable; } public void setGetter(ExecutableElement getter) { @@ -57,11 +59,11 @@ } public String getName() { - return name; + return variable.getSimpleName().toString(); } public TypeMirror getType() { - return type; + return variable.asType(); } public boolean isGenerated() { diff -r 3a37116ef37f -r 62c43fcf5be2 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/Parameter.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/Parameter.java Mon Dec 29 18:32:03 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/Parameter.java Tue Feb 03 15:07:07 2015 +0100 @@ -25,23 +25,20 @@ import javax.lang.model.element.*; import javax.lang.model.type.*; -import com.oracle.truffle.dsl.processor.java.*; - public final class Parameter { private final ParameterSpec specification; private TypeData typeSystemType; private TemplateMethod method; - private final String localName; + private String localName; private final int specificationVarArgsIndex; private final int typeVarArgsIndex; - private final TypeMirror actualType; - private VariableElement variableElement; + private final VariableElement variableElement; - public Parameter(ParameterSpec specification, TypeMirror actualType, int specificationVarArgsIndex, int typeVarArgsIndex) { + public Parameter(ParameterSpec specification, VariableElement variableElement, int specificationVarArgsIndex, int typeVarArgsIndex) { this.specification = specification; - this.actualType = actualType; + this.variableElement = variableElement; this.typeSystemType = null; this.specificationVarArgsIndex = specificationVarArgsIndex; @@ -54,18 +51,17 @@ this.localName = valueName; } - public Parameter(ParameterSpec specification, TypeData actualType, int specificationIndex, int varArgsIndex) { - this(specification, actualType.getPrimitiveType(), specificationIndex, varArgsIndex); + public Parameter(ParameterSpec specification, TypeData actualType, VariableElement variableElement, int specificationIndex, int varArgsIndex) { + this(specification, variableElement, specificationIndex, varArgsIndex); this.typeSystemType = actualType; } public Parameter(Parameter parameter, TypeData otherType) { - this(parameter.specification, otherType, parameter.specificationVarArgsIndex, parameter.typeVarArgsIndex); + this(parameter.specification, otherType, parameter.variableElement, parameter.specificationVarArgsIndex, parameter.typeVarArgsIndex); } public Parameter(Parameter parameter) { this.specification = parameter.specification; - this.actualType = parameter.actualType; this.typeSystemType = parameter.typeSystemType; this.specificationVarArgsIndex = parameter.specificationVarArgsIndex; this.localName = parameter.localName; @@ -73,8 +69,8 @@ this.variableElement = parameter.variableElement; } - public void setVariableElement(VariableElement variableElement) { - this.variableElement = variableElement; + public void setLocalName(String localName) { + this.localName = localName; } public VariableElement getVariableElement() { @@ -106,7 +102,7 @@ } public TypeMirror getType() { - return actualType; + return variableElement.asType(); } public TypeData getTypeSystemType() { @@ -123,6 +119,6 @@ @Override public String toString() { - return ElementUtils.getSimpleName(actualType); + return variableElement.getSimpleName().toString(); } } diff -r 3a37116ef37f -r 62c43fcf5be2 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ParameterSpec.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ParameterSpec.java Mon Dec 29 18:32:03 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ParameterSpec.java Tue Feb 03 15:07:07 2015 +0100 @@ -24,6 +24,7 @@ import java.util.*; +import javax.lang.model.element.*; import javax.lang.model.type.*; import com.oracle.truffle.dsl.processor.java.*; @@ -114,8 +115,11 @@ return allowedTypes; } - public boolean matches(TypeMirror actualType) { - return allowedTypesIdentifier.contains(ElementUtils.getUniqueIdentifier(actualType)); + public boolean matches(VariableElement variable) { + if (allowedTypesIdentifier != null) { + return allowedTypesIdentifier.contains(ElementUtils.getUniqueIdentifier(variable.asType())); + } + return true; } @Override diff -r 3a37116ef37f -r 62c43fcf5be2 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 18:32:03 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/SpecializationData.java Tue Feb 03 15:07:07 2015 +0100 @@ -27,6 +27,8 @@ import javax.lang.model.element.*; import com.oracle.truffle.dsl.processor.*; +import com.oracle.truffle.dsl.processor.expression.*; +import com.oracle.truffle.dsl.processor.java.*; public final class SpecializationData extends TemplateMethod { @@ -52,6 +54,7 @@ private SpecializationData insertBefore; private boolean reachable; private int index; + private DSLExpression limitExpression; public SpecializationData(NodeData node, TemplateMethod template, SpecializationKind kind, List exceptions) { super(template); @@ -65,15 +68,33 @@ } } + public boolean isDynamicParameterBound(DSLExpression expression) { + Set boundVariables = expression.findBoundVariableElements(); + for (Parameter parameter : getDynamicParameters()) { + if (boundVariables.contains(parameter.getVariableElement())) { + return true; + } + } + return false; + } + public Parameter findByVariable(VariableElement variable) { for (Parameter parameter : getParameters()) { - if (parameter.getVariableElement() == variable) { + if (ElementUtils.variableEquals(parameter.getVariableElement(), variable)) { return parameter; } } return null; } + public DSLExpression getLimitExpression() { + return limitExpression; + } + + public void setLimitExpression(DSLExpression limitExpression) { + this.limitExpression = limitExpression; + } + public void setInsertBefore(SpecializationData insertBefore) { this.insertBefore = insertBefore; } @@ -118,6 +139,14 @@ return kind == SpecializationKind.POLYMORPHIC; } + public List getDynamicParameters() { + List uncachedParameters = new ArrayList<>(getParameters()); + for (CacheExpression cacheExpression : getCaches()) { + uncachedParameters.remove(cacheExpression.getParameter()); + } + return uncachedParameters; + } + @Override protected List findChildContainers() { List sinks = new ArrayList<>(); @@ -127,6 +156,9 @@ if (guards != null) { sinks.addAll(guards); } + if (caches != null) { + sinks.addAll(caches); + } return sinks; } @@ -140,6 +172,7 @@ if (!getAssumptions().isEmpty()) { return true; } + for (Parameter parameter : getSignatureParameters()) { NodeChildData child = parameter.getSpecification().getExecution().getChild(); ExecutableTypeData type = child.findExecutableType(parameter.getTypeSystemType()); @@ -191,48 +224,6 @@ return index; } - public boolean isContainedBy(SpecializationData next) { - if (compareTo(next) > 0) { - // must be declared after the current specialization - return false; - } - - Iterator currentSignature = getSignatureParameters().iterator(); - Iterator nextSignature = next.getSignatureParameters().iterator(); - - while (currentSignature.hasNext() && nextSignature.hasNext()) { - TypeData currentType = currentSignature.next().getTypeSystemType(); - TypeData prevType = nextSignature.next().getTypeSystemType(); - - if (!currentType.isImplicitSubtypeOf(prevType)) { - return false; - } - } - - for (String nextAssumption : next.getAssumptions()) { - if (!getAssumptions().contains(nextAssumption)) { - return false; - } - } - - Iterator nextGuards = next.getGuards().iterator(); - while (nextGuards.hasNext()) { - GuardExpression nextGuard = nextGuards.next(); - boolean implied = false; - for (GuardExpression currentGuard : getGuards()) { - if (currentGuard.implies(nextGuard)) { - implied = true; - break; - } - } - if (!implied) { - return false; - } - } - - return true; - } - public NodeData getNode() { return node; } @@ -312,12 +303,37 @@ return assumptionExpressions; } + public boolean hasMultipleInstances() { + if (!getCaches().isEmpty()) { + for (GuardExpression guard : getGuards()) { + DSLExpression guardExpression = guard.getExpression(); + Set boundVariables = guardExpression.findBoundVariableElements(); + if (isDynamicParameterBound(guardExpression)) { + for (CacheExpression cache : getCaches()) { + if (boundVariables.contains(cache.getParameter().getVariableElement())) { + return true; + } + } + } + } + } + + return false; + + } + public boolean isReachableAfter(SpecializationData prev) { if (!prev.isSpecialized()) { return true; } if (!prev.getExceptions().isEmpty()) { + // may get excluded by exception + return true; + } + + if (hasMultipleInstances()) { + // may fallthrough due to limit return true; } @@ -351,4 +367,14 @@ return false; } + + public CacheExpression findCache(Parameter resolvedParameter) { + for (CacheExpression cache : getCaches()) { + if (cache.getParameter() == resolvedParameter) { + return cache; + } + } + return null; + } + } diff -r 3a37116ef37f -r 62c43fcf5be2 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 18:32:03 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TemplateMethod.java Tue Feb 03 15:07:07 2015 +0100 @@ -140,16 +140,6 @@ } } - public List getRequiredParameters() { - List requiredParameters = new ArrayList<>(); - for (Parameter parameter : getParameters()) { - if (getSpecification().getRequired().contains(parameter.getSpecification())) { - requiredParameters.add(parameter); - } - } - return requiredParameters; - } - public Iterable getSignatureParameters() { return new FilteredIterable<>(getParameters(), new Predicate() { public boolean evaluate(Parameter value) { diff -r 3a37116ef37f -r 62c43fcf5be2 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/CreateCastParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/CreateCastParser.java Mon Dec 29 18:32:03 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/CreateCastParser.java Tue Feb 03 15:07:07 2015 +0100 @@ -103,10 +103,10 @@ } @Override - public boolean matches(TypeMirror actualType) { + public boolean matches(VariableElement variable) { boolean found = false; for (TypeMirror specType : getAllowedTypes()) { - if (ElementUtils.isAssignable(actualType, specType)) { + if (ElementUtils.isAssignable(variable.asType(), specType)) { found = true; break; } diff -r 3a37116ef37f -r 62c43fcf5be2 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/MethodSpecParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/MethodSpecParser.java Mon Dec 29 18:32:03 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/MethodSpecParser.java Tue Feb 03 15:07:07 2015 +0100 @@ -30,6 +30,7 @@ import javax.lang.model.type.*; import com.oracle.truffle.dsl.processor.java.*; +import com.oracle.truffle.dsl.processor.java.model.*; import com.oracle.truffle.dsl.processor.model.*; public final class MethodSpecParser { @@ -76,26 +77,13 @@ String id = method.getSimpleName().toString(); TypeMirror returnType = method.getReturnType(); - List parameterTypes = new ArrayList<>(); - for (VariableElement var : method.getParameters()) { - parameterTypes.add(var.asType()); - } - - TemplateMethod templateMethod = parseImpl(methodSpecification, naturalOrder, id, method, annotation, returnType, parameterTypes); - if (templateMethod != null) { - for (int i = 0; i < templateMethod.getParameters().size(); i++) { - if (i < method.getParameters().size()) { - templateMethod.getParameters().get(i).setVariableElement(method.getParameters().get(i)); - } - } - } - return templateMethod; + return parseImpl(methodSpecification, naturalOrder, id, method, annotation, returnType, method.getParameters()); } public TemplateMethod parseImpl(MethodSpec methodSpecification, int naturalOrder, String id, ExecutableElement method, AnnotationMirror annotation, TypeMirror returnType, - List parameterTypes) { + List parameterTypes) { ParameterSpec returnTypeSpec = methodSpecification.getReturnType(); - Parameter returnTypeMirror = matchParameter(returnTypeSpec, returnType, -1, -1); + Parameter returnTypeMirror = matchParameter(returnTypeSpec, new CodeVariableElement(returnType, "returnType"), -1, -1); if (returnTypeMirror == null) { if (emitErrors) { TemplateMethod invalidMethod = new TemplateMethod(id, naturalOrder, template, methodSpecification, method, annotation, returnTypeMirror, Collections. emptyList()); @@ -147,11 +135,11 @@ * end matching the required arguments, parsing fails. Parameters prior to the parsed required * ones are cut and used to parse the optional parameters. */ - private List parseParameters(MethodSpec spec, List parameterTypes, boolean varArgs) { + private List parseParameters(MethodSpec spec, List parameterTypes, boolean varArgs) { List parsedRequired = null; int offset = 0; for (; offset <= parameterTypes.size(); offset++) { - List parameters = new ArrayList<>(); + List parameters = new ArrayList<>(); parameters.addAll(parameterTypes.subList(offset, parameterTypes.size())); parsedRequired = parseParametersRequired(spec, parameters, varArgs); if (parsedRequired != null) { @@ -166,7 +154,7 @@ if (parsedRequired.isEmpty() && offset == 0) { offset = parameterTypes.size(); } - List potentialOptionals = parameterTypes.subList(0, offset); + List potentialOptionals = parameterTypes.subList(0, offset); List parsedOptionals = parseParametersOptional(spec, potentialOptionals); if (parsedOptionals == null) { return null; @@ -178,7 +166,7 @@ return finalParameters; } - private List parseParametersOptional(MethodSpec spec, List types) { + private List parseParametersOptional(MethodSpec spec, List types) { List parsedParams = new ArrayList<>(); int typeStartIndex = 0; @@ -186,8 +174,8 @@ outer: for (int specIndex = 0; specIndex < specifications.size(); specIndex++) { ParameterSpec specification = specifications.get(specIndex); for (int typeIndex = typeStartIndex; typeIndex < types.size(); typeIndex++) { - TypeMirror actualType = types.get(typeIndex); - Parameter optionalParam = matchParameter(specification, actualType, -1, -1); + VariableElement variable = types.get(typeIndex); + Parameter optionalParam = matchParameter(specification, variable, -1, -1); if (optionalParam != null) { parsedParams.add(optionalParam); typeStartIndex = typeIndex + 1; @@ -203,7 +191,7 @@ return parsedParams; } - private List parseParametersRequired(MethodSpec spec, List types, boolean typeVarArgs) { + private List parseParametersRequired(MethodSpec spec, List types, boolean typeVarArgs) { List parsedParams = new ArrayList<>(); List specifications = spec.getRequired(); boolean specVarArgs = spec.isVariableRequiredParameters(); @@ -212,7 +200,7 @@ ParameterSpec specification; while ((specification = nextSpecification(specifications, specificationIndex, specVarArgs)) != null) { - TypeMirror actualType = nextActualType(types, typeIndex, typeVarArgs); + VariableElement actualType = nextActualType(types, typeIndex, typeVarArgs); if (actualType == null) { if (spec.isIgnoreAdditionalSpecifications()) { break; @@ -238,8 +226,18 @@ specificationIndex++; } + // consume randomly ordered annotated parameters + VariableElement variable; + while ((variable = nextActualType(types, typeIndex, typeVarArgs)) != null) { + Parameter matchedParamter = matchAnnotatedParameter(spec, variable); + if (matchedParamter == null) { + break; + } + parsedParams.add(matchedParamter); + typeIndex++; + } + if (typeIndex < types.size()) { - // additional types available if (spec.isIgnoreAdditionalParameters()) { return parsedParams; } else { @@ -250,6 +248,19 @@ return parsedParams; } + private Parameter matchAnnotatedParameter(MethodSpec spec, VariableElement variable) { + for (ParameterSpec parameterSpec : spec.getAnnotations()) { + if (parameterSpec.matches(variable)) { + Parameter matchedParameter = matchParameter(parameterSpec, variable, -1, -1); + if (matchedParameter != null) { + matchedParameter.setLocalName(variable.getSimpleName().toString()); + return matchedParameter; + } + } + } + return null; + } + private static ParameterSpec nextSpecification(List specifications, int specIndex, boolean varArgs) { if (varArgs && specIndex >= specifications.size() - 1 && !specifications.isEmpty()) { return specifications.get(specifications.size() - 1); @@ -260,12 +271,12 @@ } } - private static TypeMirror nextActualType(List types, int typeIndex, boolean varArgs) { + private static VariableElement nextActualType(List types, int typeIndex, boolean varArgs) { if (varArgs && typeIndex >= types.size() - 1 && !types.isEmpty()) { // unpack varargs array argument - TypeMirror actualType = types.get(types.size() - 1); - if (actualType.getKind() == TypeKind.ARRAY) { - actualType = ((ArrayType) actualType).getComponentType(); + VariableElement actualType = types.get(types.size() - 1); + if (actualType.asType().getKind() == TypeKind.ARRAY) { + actualType = new CodeVariableElement(((ArrayType) actualType.asType()).getComponentType(), actualType.getSimpleName().toString()); } return actualType; } else if (typeIndex < types.size()) { @@ -275,21 +286,21 @@ } } - private Parameter matchParameter(ParameterSpec specification, TypeMirror mirror, int specificationIndex, int varArgsIndex) { - TypeMirror resolvedType = mirror; + private Parameter matchParameter(ParameterSpec specification, VariableElement variable, int specificationIndex, int varArgsIndex) { + TypeMirror resolvedType = variable.asType(); if (hasError(resolvedType)) { return null; } - if (!specification.matches(resolvedType)) { + if (!specification.matches(variable)) { return null; } TypeData resolvedTypeData = getTypeSystem().findTypeData(resolvedType); if (resolvedTypeData != null) { - return new Parameter(specification, resolvedTypeData, specificationIndex, varArgsIndex); + return new Parameter(specification, resolvedTypeData, variable, specificationIndex, varArgsIndex); } else { - return new Parameter(specification, resolvedType, specificationIndex, varArgsIndex); + return new Parameter(specification, variable, specificationIndex, varArgsIndex); } } diff -r 3a37116ef37f -r 62c43fcf5be2 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 18:32:03 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java Tue Feb 03 15:07:07 2015 +0100 @@ -36,6 +36,7 @@ import com.oracle.truffle.dsl.processor.expression.*; import com.oracle.truffle.dsl.processor.java.*; import com.oracle.truffle.dsl.processor.java.compiler.*; +import com.oracle.truffle.dsl.processor.java.model.*; import com.oracle.truffle.dsl.processor.model.*; import com.oracle.truffle.dsl.processor.model.NodeChildData.Cardinality; import com.oracle.truffle.dsl.processor.model.SpecializationData.SpecializationKind; @@ -99,7 +100,8 @@ } catch (CompileErrorException e) { throw e; } catch (Throwable e) { - throw new RuntimeException(String.format("Parsing of Node %s failed.", ElementUtils.getQualifiedName(rootType)), e); + e.addSuppressed(new RuntimeException(String.format("Parsing of Node %s failed.", ElementUtils.getQualifiedName(rootType)), e)); + throw e; } if (node == null && !enclosedNodes.isEmpty()) { node = new NodeData(context, rootType); @@ -209,29 +211,44 @@ node.addError(importAnnotation, importClassesValue, "The specified import guard class '%s' is not a declared type.", ElementUtils.getQualifiedName(importGuardClass)); continue; } + TypeElement typeElement = ElementUtils.fromTypeMirror(importGuardClass); - - // hack to reload type is necessary for incremental compiling in eclipse. - // otherwise methods inside of import guard types are just not found. - typeElement = ElementUtils.fromTypeMirror(context.reloadType(typeElement.asType())); - if (typeElement.getEnclosingElement().getKind().isClass() && !typeElement.getModifiers().contains(Modifier.PUBLIC)) { node.addError(importAnnotation, importClassesValue, "The specified import guard class '%s' must be public.", ElementUtils.getQualifiedName(importGuardClass)); continue; } - - List importMethods = ElementFilter.methodsIn(processingEnv.getElementUtils().getAllMembers(typeElement)); - - for (ExecutableElement importMethod : importMethods) { - if (!importMethod.getModifiers().contains(Modifier.PUBLIC) || !importMethod.getModifiers().contains(Modifier.STATIC)) { - continue; - } - elements.add(importMethod); - } + elements.addAll(importPublicStaticMembers(typeElement, false)); } } } + private List importPublicStaticMembers(TypeElement importGuardClass, boolean includeConstructors) { + // hack to reload type is necessary for incremental compiling in eclipse. + // otherwise methods inside of import guard types are just not found. + TypeElement typeElement = ElementUtils.fromTypeMirror(context.reloadType(importGuardClass.asType())); + + List members = new ArrayList<>(); + for (Element importElement : processingEnv.getElementUtils().getAllMembers(typeElement)) { + if (!importElement.getModifiers().contains(Modifier.PUBLIC)) { + continue; + } + + if (includeConstructors && importElement.getKind() == ElementKind.CONSTRUCTOR) { + members.add(importElement); + } + + if (!importElement.getModifiers().contains(Modifier.STATIC)) { + continue; + } + + ElementKind kind = importElement.getKind(); + if (kind.isField() || kind == ElementKind.METHOD) { + members.add(importElement); + } + } + return members; + } + private NodeData parseNodeData(TypeElement templateType, List typeHierarchy) { AnnotationMirror typeSystemMirror = findFirstAnnotation(typeHierarchy, TypeSystemReference.class); if (typeSystemMirror == null) { @@ -286,7 +303,7 @@ } if (field.getModifiers().contains(Modifier.PUBLIC) || field.getModifiers().contains(Modifier.PROTECTED)) { String name = field.getSimpleName().toString(); - fields.add(new NodeFieldData(field, null, field.asType(), name, false)); + fields.add(new NodeFieldData(field, null, field, false)); names.add(name); } } @@ -301,7 +318,7 @@ String name = ElementUtils.firstLetterLowerCase(ElementUtils.getAnnotationValue(String.class, mirror, "name")); TypeMirror type = ElementUtils.getAnnotationValue(TypeMirror.class, mirror, "type"); - NodeFieldData field = new NodeFieldData(typeElement, mirror, type, name, true); + NodeFieldData field = new NodeFieldData(typeElement, mirror, new CodeVariableElement(type, name), true); if (name.isEmpty()) { field.addError(ElementUtils.getAnnotationValue(mirror, "name"), "Field name cannot be empty."); } else if (names.contains(name)) { @@ -469,6 +486,7 @@ } } + TypeMirror cacheAnnotation = context.getType(Cached.class); List frameTypes = context.getFrameTypes(); // pre-parse specializations to find signature size for (ExecutableElement method : methods) { @@ -476,10 +494,10 @@ if (mirror == null) { continue; } - int currentArgumentIndex = 0; boolean skipShortCircuit = false; outer: for (VariableElement var : method.getParameters()) { + TypeMirror type = var.asType(); if (currentArgumentIndex == 0) { // skip optionals @@ -489,6 +507,11 @@ } } } + + if (ElementUtils.findAnnotationMirror(var.getAnnotationMirrors(), cacheAnnotation) != null) { + continue outer; + } + int childIndex = currentArgumentIndex < children.size() ? currentArgumentIndex : children.size() - 1; if (childIndex == -1) { continue; @@ -669,7 +692,9 @@ // Declaration order is not required for child nodes. List members = processingEnv.getElementUtils().getAllMembers(templateType); NodeData node = parseNodeData(templateType, lookupTypes); - + if (node.hasErrors()) { + return node; + } node.setExecutableTypes(groupExecutableTypes(new ExecutableTypeMethodParser(context, node, createAllowedChildFrameTypes(parentNode)).parse(members))); node.setFrameType(parentNode.getFrameType()); return node; @@ -691,6 +716,7 @@ } initializeExpressions(elements, node); + if (node.hasErrors()) { return; } @@ -701,19 +727,17 @@ initializePolymorphism(node); // requires specializations initializeReachability(node); initializeContains(node); - resolveContains(node); 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); + for (SpecializationData contained : cur.getContains()) { + if (contained != cur) { + contained.getExcludedBy().add(cur); } } } - // verify specialization parameter length initializeSpecializationIdsWithMethodNames(node.getSpecializations()); } @@ -778,15 +802,11 @@ AnnotationValue value = ElementUtils.getAnnotationValue(specialization.getMarkerAnnotation(), "contains"); specialization.addError(value, "The referenced specialization '%s' could not be found.", includeName); } else { - if (!foundSpecialization.isContainedBy(specialization)) { + if (foundSpecialization.compareTo(specialization) > 0) { AnnotationValue value = ElementUtils.getAnnotationValue(specialization.getMarkerAnnotation(), "contains"); if (foundSpecialization.compareTo(specialization) > 0) { specialization.addError(value, "The contained specialization '%s' must be declared before the containing specialization.", includeName); - }/* - * else { specialization.addError(value, - * "The contained specialization '%s' is not fully compatible. The contained specialization must be strictly more generic than the containing one." - * , includeName); } - */ + } } resolvedSpecializations.add(foundSpecialization); @@ -935,48 +955,143 @@ private void initializeExpressions(List elements, NodeData node) { List members = filterNotAccessibleElements(node.getTemplateType(), elements); - final TypeMirror booleanType = context.getType(boolean.class); + List fields = new ArrayList<>(); + for (NodeFieldData field : node.getFields()) { + fields.add(field.getVariable()); + } for (SpecializationData specialization : node.getSpecializations()) { if (specialization.getMethod() == null) { continue; } - List specializationMembers = new ArrayList<>(); + List specializationMembers = new ArrayList<>(members.size() + specialization.getParameters().size() + fields.size()); for (Parameter p : specialization.getParameters()) { - VariableElement variableElement = p.getVariableElement(); - if (variableElement == null) { - throw new AssertionError("All parameters must be resolved for " + specialization); + specializationMembers.add(p.getVariableElement()); + } + specializationMembers.addAll(fields); + specializationMembers.addAll(members); + DSLExpressionResolver resolver = new DSLExpressionResolver(context, specializationMembers); + + initializeCaches(specialization, resolver); + initializeGuards(specialization, resolver); + if (specialization.hasErrors()) { + continue; + } + initializeLimit(specialization, resolver); + } + } + + private void initializeLimit(SpecializationData specialization, DSLExpressionResolver resolver) { + AnnotationValue annotationValue = ElementUtils.getAnnotationValue(specialization.getMessageAnnotation(), "limit"); + + String limitValue; + if (annotationValue == null) { + limitValue = ""; + } else { + limitValue = (String) annotationValue.getValue(); + } + if (limitValue.isEmpty()) { + limitValue = "3"; + } else if (!specialization.hasMultipleInstances()) { + specialization.addWarning(annotationValue, "The limit expression has no effect. Multiple specialization instantiations are impossible for this specialization."); + return; + } + + TypeMirror expectedType = context.getType(int.class); + try { + DSLExpression expression = DSLExpression.parse(limitValue); + expression.accept(resolver); + if (!ElementUtils.typeEquals(expression.getResolvedType(), expectedType)) { + specialization.addError(annotationValue, "Incompatible return type %s. Limit expressions must return %s.", ElementUtils.getSimpleName(expression.getResolvedType()), + ElementUtils.getSimpleName(expectedType)); + } + if (specialization.isDynamicParameterBound(expression)) { + specialization.addError(annotationValue, "Limit expressions must not bind dynamic parameter values."); + } + + specialization.setLimitExpression(expression); + } catch (InvalidExpressionException e) { + specialization.addError(annotationValue, "Error parsing expression '%s': %s", limitValue, e.getMessage()); + } + } + + private void initializeCaches(SpecializationData specialization, DSLExpressionResolver resolver) { + TypeMirror cacheMirror = context.getType(Cached.class); + List expressions = new ArrayList<>(); + for (Parameter parameter : specialization.getParameters()) { + AnnotationMirror annotationMirror = ElementUtils.findAnnotationMirror(parameter.getVariableElement().getAnnotationMirrors(), cacheMirror); + if (annotationMirror != null) { + String initializer = ElementUtils.getAnnotationValue(String.class, annotationMirror, "value"); + + TypeMirror parameterType = parameter.getType(); + + DSLExpressionResolver localResolver = resolver; + if (parameterType.getKind() == TypeKind.DECLARED) { + localResolver = localResolver.copy(importPublicStaticMembers(ElementUtils.fromTypeMirror(parameterType), true)); } - specializationMembers.add(variableElement); - } - specializationMembers.addAll(members); - - DSLExpressionResolver resolver = new DSLExpressionResolver(context, specializationMembers); - List guardDefinitions = ElementUtils.getAnnotationValueList(String.class, specialization.getMarkerAnnotation(), "guards"); - List guardExpressions = new ArrayList<>(); - for (String guard : guardDefinitions) { - GuardExpression guardExpression; + CacheExpression cacheExpression; DSLExpression expression = null; try { - expression = DSLExpression.parse(guard); - expression.accept(resolver); - guardExpression = new GuardExpression(specialization, expression); - if (!ElementUtils.typeEquals(expression.getResolvedType(), booleanType)) { - guardExpression.addError("Incompatible return type %s. Guard expressions must return boolean.", ElementUtils.getSimpleName(expression.getResolvedType())); + expression = DSLExpression.parse(initializer); + expression.accept(localResolver); + cacheExpression = new CacheExpression(parameter, annotationMirror, expression); + if (!ElementUtils.typeEquals(expression.getResolvedType(), parameter.getType())) { + cacheExpression.addError("Incompatible return type %s. The expression type must be equal to the parameter type %s.", ElementUtils.getSimpleName(expression.getResolvedType()), + ElementUtils.getSimpleName(parameter.getType())); } -// guardExpression.addWarning("Expression:%s", expression.toString()); } catch (InvalidExpressionException e) { - guardExpression = new GuardExpression(specialization, null); - guardExpression.addError("Error parsing expression '%s': %s", guard, e.getMessage()); + cacheExpression = new CacheExpression(parameter, annotationMirror, null); + cacheExpression.addError("Error parsing expression '%s': %s", initializer, e.getMessage()); + } + expressions.add(cacheExpression); + } + } + specialization.setCaches(expressions); + + if (specialization.hasErrors()) { + return; + } + + // verify that cache expressions are bound in the correct order. + for (int i = 0; i < expressions.size(); i++) { + CacheExpression currentExpression = expressions.get(i); + Set boundVariables = currentExpression.getExpression().findBoundVariableElements(); + for (int j = i + 1; j < expressions.size(); j++) { + CacheExpression boundExpression = expressions.get(j); + if (boundVariables.contains(boundExpression.getParameter().getVariableElement())) { + currentExpression.addError("The initializer expression of parameter '%s' binds unitialized parameter '%s. Reorder the parameters to resolve the problem.", + currentExpression.getParameter().getLocalName(), boundExpression.getParameter().getLocalName()); + break; } - guardExpressions.add(guardExpression); } - specialization.setGuards(guardExpressions); } } + private void initializeGuards(SpecializationData specialization, DSLExpressionResolver resolver) { + final TypeMirror booleanType = context.getType(boolean.class); + List guardDefinitions = ElementUtils.getAnnotationValueList(String.class, specialization.getMarkerAnnotation(), "guards"); + List guardExpressions = new ArrayList<>(); + for (String guard : guardDefinitions) { + GuardExpression guardExpression; + DSLExpression expression = null; + try { + expression = DSLExpression.parse(guard); + expression.accept(resolver); + guardExpression = new GuardExpression(specialization, expression); + if (!ElementUtils.typeEquals(expression.getResolvedType(), booleanType)) { + guardExpression.addError("Incompatible return type %s. Guards must return %s.", ElementUtils.getSimpleName(expression.getResolvedType()), ElementUtils.getSimpleName(booleanType)); + } + } catch (InvalidExpressionException e) { + guardExpression = new GuardExpression(specialization, null); + guardExpression.addError("Error parsing expression '%s': %s", guard, e.getMessage()); + } + guardExpressions.add(guardExpression); + } + specialization.setGuards(guardExpressions); + } + private static List filterNotAccessibleElements(TypeElement templateType, List elements) { String packageName = ElementUtils.getPackageName(templateType); List filteredElements = new ArrayList<>(elements); @@ -1030,10 +1145,10 @@ GenericParser parser = new GenericParser(context, node); MethodSpec specification = parser.createDefaultMethodSpec(node.getSpecializations().iterator().next().getMethod(), null, true, null); - List parameterTypes = new ArrayList<>(); + List parameterTypes = new ArrayList<>(); int signatureIndex = 1; for (ParameterSpec spec : specification.getRequired()) { - parameterTypes.add(createGenericType(spec, node.getSpecializations(), signatureIndex)); + parameterTypes.add(new CodeVariableElement(createGenericType(spec, node.getSpecializations(), signatureIndex), "arg" + signatureIndex)); if (spec.isSignature()) { signatureIndex++; } diff -r 3a37116ef37f -r 62c43fcf5be2 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 18:32:03 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationGroup.java Tue Feb 03 15:07:07 2015 +0100 @@ -24,7 +24,6 @@ import java.util.*; -import com.oracle.truffle.dsl.processor.generator.*; import com.oracle.truffle.dsl.processor.model.*; import com.oracle.truffle.dsl.processor.model.TemplateMethod.TypeSignature; @@ -108,10 +107,6 @@ return null; } - if (previous.mayBeExcluded()) { - return null; - } - /* Guard is else branch can be connected in previous specialization. */ if (elseConnectedGuards.contains(guard)) { return guard; @@ -124,19 +119,6 @@ return null; } - private boolean mayBeExcluded() { - if (specialization != null) { - return NodeGenFactory.mayBeExcluded(specialization); - } else { - for (SpecializationGroup group : getChildren()) { - if (group.mayBeExcluded()) { - return true; - } - } - } - return false; - } - private void updateChildren(List childs) { if (!children.isEmpty()) { children.clear(); @@ -381,4 +363,16 @@ } } + public SpecializationGroup getPrevious() { + if (getParent() == null) { + return null; + } + + List parentChildren = getParent().getChildren(); + int index = parentChildren.indexOf(this); + if (index <= 0) { + return null; + } + return parentChildren.get(index - 1); + } } diff -r 3a37116ef37f -r 62c43fcf5be2 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationMethodParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationMethodParser.java Mon Dec 29 18:32:03 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationMethodParser.java Tue Feb 03 15:07:07 2015 +0100 @@ -42,7 +42,9 @@ @Override public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { - return createDefaultMethodSpec(method, mirror, true, null); + MethodSpec spec = createDefaultMethodSpec(method, mirror, true, null); + spec.getAnnotations().add(new AnnotatedParameterSpec(getContext().getDeclaredType(Cached.class))); + return spec; } @Override diff -r 3a37116ef37f -r 62c43fcf5be2 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TemplateMethodParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TemplateMethodParser.java Mon Dec 29 18:32:03 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TemplateMethodParser.java Tue Feb 03 15:07:07 2015 +0100 @@ -132,7 +132,7 @@ return null; } - public final E create(String id, int naturalOrder, ExecutableElement methodMetadata, AnnotationMirror mirror, TypeMirror returnType, List parameterTypes) { + public final E create(String id, int naturalOrder, ExecutableElement methodMetadata, AnnotationMirror mirror, TypeMirror returnType, List parameterTypes) { TemplateMethod method = parser.parseImpl(createSpecification(methodMetadata, mirror), naturalOrder, id, methodMetadata, mirror, returnType, parameterTypes); if (method != null) { return create(method, method.hasErrors());