# HG changeset patch # User Christian Humer # Date 1423653224 -3600 # Node ID f4792a54417091e1aaebb4c2bd3e63d93926276b # Parent bf166845c7d8db9f1a6b216d72f92da43e2ebc18 Truffle-DSL: implement new assumptions semantics. diff -r bf166845c7d8 -r f4792a544170 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/AssumptionsTest.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/AssumptionsTest.java Wed Feb 11 12:13:44 2015 +0100 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/AssumptionsTest.java Wed Feb 11 12:13:44 2015 +0100 @@ -22,120 +22,236 @@ */ package com.oracle.truffle.api.dsl.test; +import static com.oracle.truffle.api.dsl.test.TestHelper.*; +import static org.junit.Assert.*; + +import java.util.*; + import org.junit.*; import com.oracle.truffle.api.*; import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.dsl.test.AssumptionsTestFactory.DerivedAssumptionNodeFactory; -import com.oracle.truffle.api.dsl.test.AssumptionsTestFactory.DerivedAssumptionRedeclaredNodeFactory; -import com.oracle.truffle.api.dsl.test.AssumptionsTestFactory.MultipleAssumptionsNodeFactory; -import com.oracle.truffle.api.dsl.test.AssumptionsTestFactory.SingleAssumptionNodeFactory; -import com.oracle.truffle.api.dsl.test.TypeSystemTest.TestRootNode; +import com.oracle.truffle.api.dsl.test.AssumptionsTestFactory.AssumptionArrayTestFactory; +import com.oracle.truffle.api.dsl.test.AssumptionsTestFactory.CacheAssumptionTestFactory; +import com.oracle.truffle.api.dsl.test.AssumptionsTestFactory.FieldTestFactory; +import com.oracle.truffle.api.dsl.test.AssumptionsTestFactory.MethodTestFactory; +import com.oracle.truffle.api.dsl.test.AssumptionsTestFactory.NodeFieldTest2Factory; +import com.oracle.truffle.api.dsl.test.AssumptionsTestFactory.StaticFieldTestFactory; import com.oracle.truffle.api.dsl.test.TypeSystemTest.ValueNode; public class AssumptionsTest { @Test - public void testSingleAssumption() { + public void testField() { + CallTarget root = createCallTarget(FieldTestFactory.getInstance()); + FieldTest node = getNode(root); + assertEquals(42, root.call(42)); + assertEquals(42, root.call(42)); + node.field.invalidate(); + try { + root.call(45); + fail(); + } catch (UnsupportedSpecializationException e) { + } + } + + @NodeChild + static class FieldTest extends ValueNode { + + protected final Assumption field = Truffle.getRuntime().createAssumption(); + + @Specialization(assumptions = "field") + static int do1(int value) { + return value; + } + } + + @Test + public void testNodeField() { Assumption assumption = Truffle.getRuntime().createAssumption(); - TestRootNode root = TestHelper.createRoot(SingleAssumptionNodeFactory.getInstance(), assumption); + CallTarget root = createCallTarget(NodeFieldTest2Factory.getInstance(), assumption); + assertEquals(42, root.call(42)); + assertEquals(42, root.call(42)); + assumption.invalidate(); + try { + root.call(45); + fail(); + } catch (UnsupportedSpecializationException e) { + } + } + + @NodeChild + @NodeField(name = "field", type = Assumption.class) + static class NodeFieldTest2 extends ValueNode { - Assert.assertEquals(42, TestHelper.executeWith(root)); - assumption.invalidate(); - Assert.assertEquals("42", TestHelper.executeWith(root)); + @Specialization(assumptions = "field") + static int do1(int value) { + return value; + } + } + + @Test + public void testStaticField() { + CallTarget root = createCallTarget(StaticFieldTestFactory.getInstance()); + assertEquals(42, root.call(42)); + assertEquals(42, root.call(42)); + StaticFieldTest.FIELD.invalidate(); + try { + root.call(45); + fail(); + } catch (UnsupportedSpecializationException e) { + } + } + + @NodeChild + static class StaticFieldTest extends ValueNode { + + static final Assumption FIELD = Truffle.getRuntime().createAssumption(); + + @Specialization(assumptions = "FIELD") + static int do1(int value) { + return value; + } + } + + @Test + public void testMethod() { + CallTarget root = createCallTarget(MethodTestFactory.getInstance()); + MethodTest node = getNode(root); + assertEquals(42, root.call(42)); + assertEquals(42, root.call(42)); + node.hiddenAssumption.invalidate(); + try { + root.call(45); + fail(); + } catch (UnsupportedSpecializationException e) { + } } - @NodeAssumptions("assumption") - abstract static class SingleAssumptionNode extends ValueNode { + @NodeChild + static class MethodTest extends ValueNode { - @Specialization(assumptions = "assumption") - int do2() { - return 42; + private final Assumption hiddenAssumption = Truffle.getRuntime().createAssumption(); + + @Specialization(assumptions = "getAssumption()") + static int do1(int value) { + return value; } - @Fallback - Object doFallBack() { - return "42"; + Assumption getAssumption() { + return hiddenAssumption; + } + } + + @Test + public void testCacheAssumption() { + CallTarget root = createCallTarget(CacheAssumptionTestFactory.getInstance()); + CacheAssumptionTest node = getNode(root); + assertEquals("do1", root.call(42)); + assertEquals("do1", root.call(43)); + assertEquals("do1", root.call(44)); + node.assumptions.get(42).invalidate(); + node.assumptions.put(42, null); // clear 42 + node.assumptions.get(43).invalidate(); + node.assumptions.get(44).invalidate(); + assertEquals("do1", root.call(42)); // recreates 42 + assertEquals("do2", root.call(43)); // invalid 43 -> remove -> insert do2 + assertEquals("do2", root.call(46)); // no more lines can be created. + } + + @Test + public void testCacheAssumptionLimit() { + CallTarget root = createCallTarget(CacheAssumptionTestFactory.getInstance()); + assertEquals("do1", root.call(42)); + assertEquals("do1", root.call(43)); + assertEquals("do1", root.call(44)); + assertEquals("do2", root.call(45)); + assertEquals("do1", root.call(43)); + assertEquals("do1", root.call(44)); + } + + @NodeChild + @SuppressWarnings("unused") + static class CacheAssumptionTest extends ValueNode { + + private final Map assumptions = new HashMap<>(); + + @Specialization(guards = "value == cachedValue", assumptions = "getAssumption(cachedValue)") + static String do1(int value, @Cached("value") int cachedValue) { + return "do1"; + } + + @Specialization + static String do2(int value) { + return "do2"; + } + + Assumption getAssumption(int value) { + Assumption assumption = assumptions.get(value); + if (assumption == null) { + assumption = Truffle.getRuntime().createAssumption(); + assumptions.put(value, assumption); + } + return assumption; + } + } + + @Test + public void testAssumptionArrays() { + CallTarget root = createCallTarget(AssumptionArrayTestFactory.getInstance()); + AssumptionArrayTest node = getNode(root); + + Assumption a1 = Truffle.getRuntime().createAssumption(); + Assumption a2 = Truffle.getRuntime().createAssumption(); + + node.assumptions = new Assumption[]{a1, a2}; + + assertEquals("do1", root.call(42)); + + a2.invalidate(); + + assertEquals("do2", root.call(42)); + } + + @NodeChild + @SuppressWarnings("unused") + static class AssumptionArrayTest extends ValueNode { + + Assumption[] assumptions; + + @Specialization(assumptions = "assumptions") + static String do1(int value) { + return "do1"; + } + + @Specialization + static String do2(int value) { + return "do2"; } } - @Test - public void testMultipleAssumption() { - Assumption assumption1 = Truffle.getRuntime().createAssumption(); - Assumption assumption2 = Truffle.getRuntime().createAssumption(); - TestRootNode root = TestHelper.createRoot(MultipleAssumptionsNodeFactory.getInstance(), assumption1, assumption2); - - Assert.assertEquals(42, TestHelper.executeWith(root)); - assumption2.invalidate(); - Assert.assertEquals("41", TestHelper.executeWith(root)); - assumption1.invalidate(); - Assert.assertEquals("42", TestHelper.executeWith(root)); - } - - @NodeAssumptions({"assumption1", "assumption2"}) - abstract static class MultipleAssumptionsNode extends ValueNode { - - @Specialization(assumptions = {"assumption1", "assumption2"}) - int doInt() { - return 42; - } - - @Specialization(assumptions = "assumption1") - Object doObject() { - return "41"; - } - - @Fallback - Object doFallBack() { - return "42"; + @NodeChild + static class ErrorIncompatibleReturnType extends ValueNode { + @ExpectError("Incompatible return type int. Assumptions must be assignable to Assumption or Assumption[].") + @Specialization(assumptions = "3") + static int do1(int value) { + return value; } } - @Test - public void testDerivedAssumption() { - Assumption additionalAssumption = Truffle.getRuntime().createAssumption(); - Assumption assumption = Truffle.getRuntime().createAssumption(); - TestRootNode root = TestHelper.createRoot(DerivedAssumptionNodeFactory.getInstance(), assumption, additionalAssumption); + @NodeChild + static class ErrorBoundDynamicValue extends ValueNode { - Assert.assertEquals(42, TestHelper.executeWith(root)); - assumption.invalidate(); - Assert.assertEquals(43, TestHelper.executeWith(root)); - additionalAssumption.invalidate(); - Assert.assertEquals("42", TestHelper.executeWith(root)); - } - - @NodeAssumptions({"additionalAssumption"}) - abstract static class DerivedAssumptionNode extends SingleAssumptionNode { - - @Specialization(assumptions = "additionalAssumption") - int doIntDerived() { - return 43; + @ExpectError("Assumption expressions must not bind dynamic parameter values.") + @Specialization(assumptions = "createAssumption(value)") + static int do1(int value) { + return value; } - } - - @Test - public void testDerivedAssumptionRedeclared() { - Assumption additionalAssumption = Truffle.getRuntime().createAssumption(); - Assumption assumption = Truffle.getRuntime().createAssumption(); - TestRootNode root = TestHelper.createRoot(DerivedAssumptionRedeclaredNodeFactory.getInstance(), additionalAssumption, assumption); - - Assert.assertEquals(42, TestHelper.executeWith(root)); - assumption.invalidate(); - Assert.assertEquals(43, TestHelper.executeWith(root)); - additionalAssumption.invalidate(); - Assert.assertEquals("42", TestHelper.executeWith(root)); - } - - @NodeAssumptions({"additionalAssumption", "assumption"}) - abstract static class DerivedAssumptionRedeclaredNode extends SingleAssumptionNode { - - @Specialization(assumptions = "additionalAssumption") - int doIntDerived() { - return 43; + Assumption createAssumption(int value) { + return Truffle.getRuntime().createAssumption(String.valueOf(value)); } - } } diff -r bf166845c7d8 -r f4792a544170 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ContainsTest.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ContainsTest.java Wed Feb 11 12:13:44 2015 +0100 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ContainsTest.java Wed Feb 11 12:13:44 2015 +0100 @@ -142,7 +142,6 @@ return a > 0; } - @Implies("isGreaterZero(a)") static boolean isOne(int a) { return a == 1; } @@ -190,7 +189,6 @@ @NodeChild("a") abstract static class Contains4 extends ValueNode { - @Implies("isGreaterEqualZero") static boolean isOne(int a) { return a == 1; } @@ -433,7 +431,6 @@ abstract static class ContainsGuard5 extends ValueNode { - @Implies("g2") boolean g1() { return true; } @@ -455,7 +452,6 @@ abstract static class ContainsGuard6 extends ValueNode { - @Implies("!g2") boolean g1() { return true; } @@ -496,48 +492,6 @@ } } - @NodeAssumptions("a1") - abstract static class ContainsAssumption1 extends ValueNode { - - @Specialization(assumptions = "a1") - Object f0() { - return null; - } - - @Specialization(contains = "f0") - Object f1() { - return null; - } - } - - @NodeAssumptions({"a1", "a2"}) - abstract static class ContainsAssumption4 extends ValueNode { - - @Specialization(assumptions = {"a1", "a2"}) - Object f0() { - return null; - } - - @Specialization(contains = "f0", assumptions = "a1") - Object f1() { - return null; - } - } - - @NodeAssumptions({"a1", "a2"}) - abstract static class ContainsAssumption5 extends ValueNode { - - @Specialization(assumptions = {"a2", "a1"}) - Object f0() { - return null; - } - - @Specialization(contains = "f0", assumptions = "a1") - Object f1() { - return null; - } - } - abstract static class ContainsThrowable1 extends ValueNode { @Specialization(rewriteOn = RuntimeException.class) diff -r bf166845c7d8 -r f4792a544170 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteMethodTest.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteMethodTest.java Wed Feb 11 12:13:44 2015 +0100 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteMethodTest.java Wed Feb 11 12:13:44 2015 +0100 @@ -319,7 +319,6 @@ @TypeSystemReference(ExecuteMethodTypes.class) @NodeChild(value = "a", type = ChildNoFrame.class) - @ExpectError("Invalid inconsistent frame types [MaterializedFrame, void] found for the declared execute methods.%") abstract static class ExecuteWithFrameError5 extends Node { abstract Object execute(); diff -r bf166845c7d8 -r f4792a544170 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ReachabilityTest.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ReachabilityTest.java Wed Feb 11 12:13:44 2015 +0100 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ReachabilityTest.java Wed Feb 11 12:13:44 2015 +0100 @@ -250,99 +250,6 @@ } - @NodeAssumptions({"a1"}) - static class ReachabilityAssumption1 extends ValueNode { - - @Specialization(assumptions = "a1") - int do2() { - return 1; - } - - @Specialization - int do1() { - return 2; - } - - } - - @NodeAssumptions({"a1"}) - static class ReachabilityAssumption2 extends ValueNode { - - @Specialization(assumptions = "a1") - int do2() { - return 1; - } - - @ExpectError("Specialization is not reachable. It is shadowed by do2().") - @Specialization(assumptions = "a1") - int do1() { - return 2; - } - - } - - @NodeAssumptions({"a1", "a2"}) - static class ReachabilityAssumption3 extends ValueNode { - - @Specialization(assumptions = {"a1", "a2"}) - int do2() { - return 1; - } - - @Specialization(assumptions = "a1") - int do1() { - return 2; - } - - } - - @NodeAssumptions({"a1", "a2"}) - static class ReachabilityAssumption4 extends ValueNode { - - @Specialization(assumptions = "a1") - int do2() { - return 1; - } - - @Specialization(assumptions = "a2") - int do1() { - return 2; - } - - } - - @NodeAssumptions({"a1", "a2"}) - static class ReachabilityAssumption5 extends ValueNode { - - @Specialization - int do2() { - return 1; - } - - @ExpectError("Specialization is not reachable. It is shadowed by do2().") - @Specialization(assumptions = "a2") - int do1() { - return 2; - } - - } - - @NodeAssumptions({"a1", "a2"}) - static class ReachabilityAssumption6 extends ValueNode { - - @Specialization(assumptions = {"a1"}) - int do2() { - return 1; - } - - @ExpectError("Specialization is not reachable. It is shadowed by do2().") - @Specialization(assumptions = {"a1", "a2"}) - int do1() { - return 2; - } - - } - static class ReachabilityThrowable1 extends ValueNode { @Specialization(rewriteOn = RuntimeException.class) diff -r bf166845c7d8 -r f4792a544170 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/SpecializationGroupingTest.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/SpecializationGroupingTest.java Wed Feb 11 12:13:44 2015 +0100 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/SpecializationGroupingTest.java Wed Feb 11 12:13:44 2015 +0100 @@ -28,9 +28,6 @@ import com.oracle.truffle.api.dsl.*; import com.oracle.truffle.api.dsl.test.SpecializationGroupingTestFactory.TestElseConnectionBug1Factory; import com.oracle.truffle.api.dsl.test.SpecializationGroupingTestFactory.TestElseConnectionBug2Factory; -import com.oracle.truffle.api.dsl.test.SpecializationGroupingTestFactory.TestGroupingFactory; -import com.oracle.truffle.api.dsl.test.TypeSystemTest.SimpleTypes; -import com.oracle.truffle.api.dsl.test.TypeSystemTest.TestRootNode; import com.oracle.truffle.api.dsl.test.TypeSystemTest.ValueNode; import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.nodes.*; @@ -43,119 +40,6 @@ public class SpecializationGroupingTest { @Test - public void testGrouping() { - MockAssumption a1 = new MockAssumption(true); - MockAssumption a3 = new MockAssumption(true); - - TestRootNode root = TestHelper.createRoot(TestGroupingFactory.getInstance(), a1, a3); - - SimpleTypes.intCast = 0; - SimpleTypes.intCheck = 0; - TestGrouping.true1 = 0; - TestGrouping.false1 = 0; - TestGrouping.true2 = 0; - TestGrouping.false2 = 0; - TestGrouping.true3 = 0; - - Assert.assertEquals(42, TestHelper.executeWith(root, 21, 21)); - Assert.assertEquals(5, TestGrouping.true1); - Assert.assertEquals(0, TestGrouping.false1); - Assert.assertEquals(5, TestGrouping.true2); - Assert.assertEquals(5, TestGrouping.false2); - Assert.assertEquals(5, TestGrouping.true3); - Assert.assertEquals(10, SimpleTypes.intCheck); - Assert.assertEquals(8, SimpleTypes.intCast); - Assert.assertEquals(4, a1.checked); - Assert.assertEquals(4, a3.checked); - - Assert.assertEquals(42, TestHelper.executeWith(root, 21, 21)); - Assert.assertEquals(6, TestGrouping.true1); - Assert.assertEquals(0, TestGrouping.false1); - Assert.assertEquals(6, TestGrouping.true2); - Assert.assertEquals(6, TestGrouping.false2); - Assert.assertEquals(6, TestGrouping.true3); - - Assert.assertEquals(5, a1.checked); - Assert.assertEquals(5, a3.checked); - Assert.assertEquals(10, SimpleTypes.intCheck); - Assert.assertEquals(8, SimpleTypes.intCast); - - } - - @SuppressWarnings("unused") - @NodeChildren({@NodeChild, @NodeChild}) - @NodeAssumptions({"a1", "a3"}) - public abstract static class TestGrouping extends ValueNode { - - private static int true1; - private static int false1; - private static int true2; - private static int false2; - private static int true3; - - protected boolean true1(int value) { - true1++; - return true; - } - - protected boolean false1(int value, int value2) { - false1++; - return false; - } - - protected boolean true2(int value) { - true2++; - return true; - } - - protected boolean false2(int value) { - false2++; - return false; - } - - protected boolean true3(int value) { - true3++; - return true; - } - - @Specialization - public int fail(int value1, String value2) { - throw new AssertionError(); - } - - @Specialization(guards = {"true1(value1)", "true2(value1)", "!false2(value1)", "true3(value1)"}, assumptions = {"a1", "a3"}, rewriteOn = RuntimeException.class) - public int throwRewrite(int value1, int value2) { - throw new RuntimeException(); - } - - @Specialization(guards = {"true1(value1)", "true2(value1)", "!false2(value1)", "true3(value1)"}, contains = "throwRewrite", assumptions = {"a1", "a3"}) - public int success(int value1, int value2) { - return value1 + value2; - } - - @Specialization(guards = {"true1(value1)", "true2(value1)", "!false2(value1)", "!true3(value1)"}, assumptions = {"a1", "a3"}) - public int fail5(int value1, int value2) { - throw new AssertionError(); - } - - @Specialization(guards = {"true1(value1)", "true2(value1)", "false2(value1)"}, assumptions = {"a1", "a3"}) - public int fail4(int value1, int value2) { - throw new AssertionError(); - } - - @Specialization(guards = {"true1(value1)", "true2(value1)"}, assumptions = {"a1", "a3"}) - public int fail2break(int value1, int value2) { - throw new AssertionError(); - } - - @Specialization(guards = {"true1(value1)", "false1(value1, value2)"}) - public int fail1(int value1, int value2) { - throw new AssertionError(); - } - - } - - @Test public void testElseConnectionBug1() { CallTarget target = TestHelper.createCallTarget(TestElseConnectionBug1Factory.create(new GenericInt())); Assert.assertEquals(42, target.call()); @@ -232,36 +116,4 @@ } } - private static class MockAssumption implements Assumption { - - int checked; - - private final boolean valid; - - public MockAssumption(boolean valid) { - this.valid = valid; - } - - public void check() throws InvalidAssumptionException { - checked++; - if (!valid) { - throw new InvalidAssumptionException(); - } - } - - public boolean isValid() { - checked++; - return valid; - } - - public void invalidate() { - throw new UnsupportedOperationException(); - } - - public String getName() { - throw new UnsupportedOperationException(); - } - - } - } diff -r bf166845c7d8 -r f4792a544170 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 Wed Feb 11 12:13:44 2015 +0100 +++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/internal/SpecializationNode.java Wed Feb 11 12:13:44 2015 +0100 @@ -25,6 +25,7 @@ package com.oracle.truffle.api.dsl.internal; import java.lang.reflect.*; +import java.util.*; import java.util.concurrent.*; import com.oracle.truffle.api.*; @@ -165,10 +166,43 @@ return node; } + protected final Object removeThis(final CharSequence reason, Frame frame) { + return removeThisImpl(reason).acceptAndExecute(frame); + } + + protected final Object removeThis(final CharSequence reason, Frame frame, Object o1) { + return removeThisImpl(reason).acceptAndExecute(frame, o1); + } + + protected final Object removeThis(final CharSequence reason, Frame frame, Object o1, Object o2) { + return removeThisImpl(reason).acceptAndExecute(frame, o1, o2); + } + + protected final Object removeThis(final CharSequence reason, Frame frame, Object o1, Object o2, Object o3) { + return removeThisImpl(reason).acceptAndExecute(frame, o1, o2, o3); + } + + protected final Object removeThis(final CharSequence reason, Frame frame, Object o1, Object o2, Object o3, Object o4) { + return removeThisImpl(reason).acceptAndExecute(frame, o1, o2, o3, o4); + } + + protected final Object removeThis(final CharSequence reason, Frame frame, Object o1, Object o2, Object o3, Object o4, Object o5) { + return removeThisImpl(reason).acceptAndExecute(frame, o1, o2, o3, o4, o5); + } + + protected final Object removeThis(final CharSequence reason, Frame frame, Object... args) { + return removeThisImpl(reason).acceptAndExecute(frame, args); + } + + private SpecializationNode removeThisImpl(final CharSequence reason) { + this.replace(this.next, reason); + return findEnd().findStart(); + } + protected final SpecializationNode removeSame(final CharSequence reason) { return atomic(new Callable() { public SpecializationNode call() throws Exception { - return removeImpl(SpecializationNode.this, reason); + return removeSameImpl(SpecializationNode.this, reason); } }); } @@ -192,7 +226,7 @@ return findStart().getParent(); } - private SpecializationNode removeImpl(SpecializationNode toRemove, CharSequence reason) { + private SpecializationNode removeSameImpl(SpecializationNode toRemove, CharSequence reason) { SpecializationNode start = findStart(); SpecializationNode current = start; while (current != null) { @@ -470,7 +504,7 @@ appendFields(b, clazz); if (next != null) { - b.append(" -> ").append(next.toString()); + b.append("\n -> ").append(next.toString()); } return b.toString(); } @@ -481,25 +515,69 @@ return; } b.append("("); + String sep = ""; for (Field field : fields) { if (Modifier.isStatic(field.getModifiers())) { continue; } + b.append(sep); String name = field.getName(); if (name.equals("root")) { continue; } b.append(field.getName()); + b.append(" = "); try { field.setAccessible(true); - b.append(field.get(this)); + Object value = field.get(this); + if (value instanceof Object[]) { + b.append(Arrays.toString((Object[]) field.get(this))); + } else { + b.append(field.get(this)); + } } catch (IllegalArgumentException e) { b.append(e.toString()); } catch (IllegalAccessException e) { b.append(e.toString()); } + sep = ", "; } b.append(")"); } + // utilities for generated code + protected static void check(Assumption assumption) throws InvalidAssumptionException { + if (assumption != null) { + assumption.check(); + } + } + + @ExplodeLoop + protected static void check(Assumption[] assumptions) throws InvalidAssumptionException { + if (assumptions != null) { + CompilerAsserts.compilationConstant(assumptions.length); + for (Assumption assumption : assumptions) { + check(assumption); + } + } + } + + protected static boolean isValid(Assumption assumption) { + if (assumption != null) { + return assumption.isValid(); + } + return true; + } + + protected static boolean isValid(Assumption[] assumptions) { + if (assumptions != null) { + for (Assumption assumption : assumptions) { + if (!isValid(assumption)) { + return false; + } + } + } + return true; + } + } diff -r bf166845c7d8 -r f4792a544170 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 Wed Feb 11 12:13:44 2015 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java Wed Feb 11 12:13:44 2015 +0100 @@ -32,7 +32,6 @@ import javax.lang.model.type.*; import javax.lang.model.util.*; -import com.oracle.truffle.api.*; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.*; @@ -74,11 +73,10 @@ this.genericType = typeSystem.getGenericTypeData(); this.options = typeSystem.getOptions(); this.singleSpecializable = isSingleSpecializableImpl(); - this.varArgsThreshold = calculateVarArgsThresHold(); - + this.varArgsThreshold = calculateVarArgsThreshold(); } - private int calculateVarArgsThresHold() { + private int calculateVarArgsThreshold() { TypeMirror specialization = context.getType(SpecializationNode.class); TypeElement specializationType = fromTypeMirror(specialization); @@ -95,6 +93,10 @@ return resolveNodeId(node) + NODE_SUFFIX; } + private static String assumptionName(AssumptionExpression assumption) { + return assumption.getId() + NAME_SUFFIX; + } + private static String resolveNodeId(NodeData node) { String nodeid = node.getNodeId(); if (nodeid.endsWith("Node") && !nodeid.equals("Node")) { @@ -157,18 +159,10 @@ } } - private static String assumptionName(String assumption) { - return assumption + "_"; - } - public CodeTypeElement create() { CodeTypeElement clazz = GeneratorUtils.createClass(node, null, modifiers(FINAL), nodeTypeName(node), node.getTemplateType().asType()); ElementUtils.setVisibility(clazz.getModifiers(), ElementUtils.getVisibility(node.getTemplateType().getModifiers())); - for (String assumption : node.getAssumptions()) { - clazz.add(new CodeVariableElement(modifiers(PRIVATE, FINAL), getType(Assumption.class), assumptionName(assumption))); - } - for (NodeChildData child : node.getChildren()) { clazz.addOptional(createAccessChildMethod(child)); } @@ -757,6 +751,11 @@ return false; } } + + if (!specialization.getAssumptionExpressions().isEmpty()) { + 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 @@ -830,7 +829,7 @@ if (wrappedExecutableType != null) { builder.startReturn().tree(callTemplateMethod(null, wrappedExecutableType, locals)).end(); } else { - builder.tree(createFastPathExecute(builder, specialization, execType.getType(), locals)); + builder.tree(createFastPath(builder, specialization, execType.getType(), locals)); } } else { // create acceptAndExecute @@ -988,7 +987,8 @@ continue; } } - builder.string(parameter.getLocalName()); + + builder.defaultValue(parameter.getType()); } builder.end(); return builder.build(); @@ -1036,6 +1036,35 @@ if (node.isFrameUsedByAnyGuard()) { builder.tree(createTransferToInterpreterAndInvalidate()); } + + boolean hasAssumptions = !specialization.getAssumptionExpressions().isEmpty(); + if (hasAssumptions) { + for (AssumptionExpression assumption : specialization.getAssumptionExpressions()) { + CodeTree assumptions = DSLExpressionGenerator.write(assumption.getExpression(), accessParent(null), + castBoundTypes(bindExpressionValues(assumption.getExpression(), specialization, currentValues))); + String name = assumptionName(assumption); + // needs specialization index for assumption to make unique + String varName = name + specialization.getIndex(); + TypeMirror type = assumption.getExpression().getResolvedType(); + builder.declaration(type, varName, assumptions); + currentValues.set(name, new LocalVariable(null, type, varName, null)); + } + + builder.startIf(); + String sep = ""; + for (AssumptionExpression assumption : specialization.getAssumptionExpressions()) { + LocalVariable assumptionVar = currentValues.get(assumptionName(assumption)); + if (assumptionVar == null) { + throw new AssertionError("assumption var not resolved"); + } + builder.string(sep); + builder.startCall("isValid").tree(assumptionVar.createReference()).end(); + sep = " && "; + } + builder.end(); + builder.startBlock(); + } + for (SpecializationData otherSpeciailzation : node.getSpecializations()) { if (otherSpeciailzation == specialization) { continue; @@ -1052,7 +1081,6 @@ if (specialization.hasMultipleInstances()) { builder.declaration(getType(SpecializationNode.class), "s", create); - DSLExpression limitExpression = specialization.getLimitExpression(); CodeTree limitExpressionTree; if (limitExpression == null) { @@ -1065,11 +1093,14 @@ builder.startIf().string("countSame(s) < ").tree(limitExpressionTree).end().startBlock(); builder.statement("return s"); builder.end(); - } else { builder.startReturn().tree(create).end(); } + if (hasAssumptions) { + builder.end(); + } + if (mayBeExcluded(specialization)) { CodeTreeBuilder checkHasSeenBuilder = builder.create(); checkHasSeenBuilder.startIf().string("!").tree(accessParent(excludedFieldName(specialization))).end().startBlock(); @@ -1112,7 +1143,7 @@ return true; } - if ((!fastPath || forType.isGeneric()) && !group.getAssumptions().isEmpty()) { + if (!fastPath && specialization != null && !specialization.getAssumptionExpressions().isEmpty()) { return true; } @@ -1193,7 +1224,13 @@ } builder.tree(variable.createReference()); } - + for (AssumptionExpression assumption : specialization.getAssumptionExpressions()) { + LocalVariable variable = currentValues.get(assumptionName(assumption)); + if (variable == null) { + throw new AssertionError("Could not bind assumption value " + assumption.getId() + ": " + currentValues); + } + builder.tree(variable.createReference()); + } } builder.end(); @@ -1287,6 +1324,13 @@ builder.startStatement().string("this.").string(name).string(" = ").string(name).end(); } + for (AssumptionExpression assumption : specialization.getAssumptionExpressions()) { + String name = assumptionName(assumption); + TypeMirror type = assumption.getExpression().getResolvedType(); + 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()) { @@ -1346,9 +1390,12 @@ return builder.build(); } - private static CodeTree createCallDelegate(String methodName, TypeData forType, LocalContext currentValues) { + private static CodeTree createCallDelegate(String methodName, String reason, TypeData forType, LocalContext currentValues) { CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); builder.startCall(methodName); + if (reason != null) { + builder.doubleQuote(reason); + } currentValues.addReferencesTo(builder, FRAME_VALUE); builder.end(); @@ -1389,7 +1436,7 @@ LocalContext currentLocals = LocalContext.load(this, evaluatedArguments, varArgsThreshold); if (specialization != null) { - currentLocals.loadFastPathCachedValues(specialization); + currentLocals.loadFastPathState(specialization); } CodeExecutableElement executable = currentLocals.createMethod(modifiers(PUBLIC), type.getPrimitiveType(), TypeSystemNodeFactory.executeName(forType), FRAME_VALUE); @@ -1400,12 +1447,12 @@ } CodeTreeBuilder builder = executable.createBuilder(); - builder.tree(createFastPathExecute(builder, specialization, type, currentLocals)); + builder.tree(createFastPath(builder, specialization, type, currentLocals)); return executable; } - private CodeTree createFastPathExecute(CodeTreeBuilder parent, SpecializationData specialization, TypeData type, LocalContext currentLocals) { + private CodeTree createFastPath(CodeTreeBuilder parent, SpecializationData specialization, TypeData type, LocalContext currentLocals) { final CodeTreeBuilder builder = parent.create(); for (NodeExecutionData execution : node.getChildExecutions()) { @@ -1426,11 +1473,11 @@ LocalContext originalValues = currentLocals.copy(); if (specialization == null) { - builder.startReturn().tree(createCallDelegate("acceptAndExecute", type, currentLocals)).end(); + builder.startReturn().tree(createCallDelegate("acceptAndExecute", null, type, currentLocals)).end(); } else if (specialization.isPolymorphic()) { builder.tree(createCallNext(type, currentLocals)); } else if (specialization.isUninitialized()) { - builder.startReturn().tree(createCallDelegate("uninitialized", type, currentLocals)).end(); + builder.startReturn().tree(createCallDelegate("uninitialized", null, type, currentLocals)).end(); } else { final TypeData finalType = type; SpecializationGroup group = SpecializationGroup.create(specialization); @@ -1495,6 +1542,27 @@ ifCount++; } CodeTreeBuilder execute = builder.create(); + + if (!specialization.getAssumptionExpressions().isEmpty()) { + builder.startTryBlock(); + for (AssumptionExpression assumption : specialization.getAssumptionExpressions()) { + LocalVariable assumptionVar = currentValues.get(assumptionName(assumption)); + if (assumptionVar == null) { + throw new AssertionError("Could not resolve assumption var " + currentValues); + } + builder.startStatement().startCall("check").tree(assumptionVar.createReference()).end().end(); + } + builder.end().startCatchBlock(getType(InvalidAssumptionException.class), "ae"); + builder.startReturn(); + List assumptionIds = new ArrayList<>(); + for (AssumptionExpression assumption : specialization.getAssumptionExpressions()) { + assumptionIds.add(assumption.getId()); + } + builder.tree(createCallDelegate("removeThis", String.format("Assumption %s invalidated", assumptionIds), forType, currentValues)); + builder.end(); + builder.end(); + } + execute.startReturn(); if (specialization.getMethod() == null) { execute.startCall("unsupported"); @@ -1525,7 +1593,7 @@ } SpecializationData specialization = group.getSpecialization(); - CodeTree[] checkAndCast = createTypeCheckCastAndCaches(specialization, group.getTypeGuards(), castGuards, currentValues, execution); + CodeTree[] checkAndCast = createTypeCheckAndLocals(specialization, group.getTypeGuards(), castGuards, currentValues, execution); CodeTree check = checkAndCast[0]; CodeTree cast = checkAndCast[1]; @@ -1537,14 +1605,6 @@ CodeTree methodGuards = methodGuardAndAssertions[0]; CodeTree guardAssertions = methodGuardAndAssertions[1]; - if (!group.getAssumptions().isEmpty()) { - if (execution.isFastPath() && !forType.isGeneric()) { - cast = appendAssumptionFastPath(cast, group.getAssumptions(), forType, currentValues); - } else { - methodGuards = appendAssumptionSlowPath(methodGuards, group.getAssumptions()); - } - } - int ifCount = 0; if (!check.isEmpty()) { builder.startIf(); @@ -1583,33 +1643,6 @@ return builder.build(); } - private CodeTree appendAssumptionSlowPath(CodeTree methodGuards, List assumptions) { - CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); - - builder.tree(methodGuards); - String connect = methodGuards.isEmpty() ? "" : " && "; - for (String assumption : assumptions) { - builder.string(connect); - builder.startCall(accessParent(assumptionName(assumption)), "isValid").end(); - connect = " && "; - } - - return builder.build(); - } - - private CodeTree appendAssumptionFastPath(CodeTree casts, List assumptions, TypeData forType, LocalContext currentValues) { - CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); - builder.tree(casts); - builder.startTryBlock(); - for (String assumption : assumptions) { - builder.startStatement().startCall(accessParent(assumptionName(assumption)), "check").end().end(); - } - builder.end().startCatchBlock(getType(InvalidAssumptionException.class), "ae"); - builder.tree(createCallNext(forType, currentValues)); - builder.end(); - return builder.build(); - } - private static boolean isReachableGroup(SpecializationGroup group, int ifCount) { if (ifCount != 0) { return true; @@ -1623,7 +1656,7 @@ * Hacky else case. In this case the specialization is not reachable due to previous else * branch. This is only true if the minimum state is not checked. */ - if (previous.getGuards().size() == 1 && previous.getTypeGuards().isEmpty() && previous.getAssumptions().isEmpty() && + if (previous.getGuards().size() == 1 && previous.getTypeGuards().isEmpty() && (previous.getParent() == null || previous.getMaxSpecializationIndex() != previous.getParent().getMaxSpecializationIndex())) { return false; } @@ -2124,10 +2157,10 @@ return bindings; } - private CodeTree[] createTypeCheckCastAndCaches(SpecializationData specialization, List typeGuards, Set castGuards, LocalContext currentValues, + private CodeTree[] createTypeCheckAndLocals(SpecializationData specialization, List typeGuards, Set castGuards, LocalContext currentValues, SpecializationExecution specializationExecution) { CodeTreeBuilder checksBuilder = CodeTreeBuilder.createBuilder(); - CodeTreeBuilder castsAndCaches = CodeTreeBuilder.createBuilder(); + CodeTreeBuilder localsBuilder = CodeTreeBuilder.createBuilder(); for (TypeGuard typeGuard : typeGuards) { int signatureIndex = typeGuard.getSignatureIndex(); LocalVariable value = currentValues.getValue(signatureIndex); @@ -2188,7 +2221,7 @@ if (castGuards == null || castGuards.contains(typeGuard)) { LocalVariable castVariable = currentValues.getValue(execution).nextName().newType(typeGuard.getType()).accessWith(null); currentValues.setValue(execution, castVariable); - castsAndCaches.tree(castVariable.createDeclaration(castBuilder.build())); + localsBuilder.tree(castVariable.createDeclaration(castBuilder.build())); } checksBuilder.tree(checkBuilder.build()); @@ -2202,12 +2235,12 @@ // multiple specializations might use the same name String varName = name + specialization.getIndex(); TypeMirror type = cache.getParameter().getType(); - castsAndCaches.declaration(type, varName, initializer); + localsBuilder.declaration(type, varName, initializer); currentValues.set(name, new LocalVariable(null, type, varName, null)); } } - return new CodeTree[]{checksBuilder.build(), castsAndCaches.build()}; + return new CodeTree[]{checksBuilder.build(), localsBuilder.build()}; } public static final class LocalContext { @@ -2219,12 +2252,18 @@ this.factory = factory; } - public void loadFastPathCachedValues(SpecializationData specialization) { + public void loadFastPathState(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))); } + + for (AssumptionExpression assumption : specialization.getAssumptionExpressions()) { + String name = assumptionName(assumption); + TypeMirror type = assumption.getExpression().getResolvedType(); + set(name, new LocalVariable(null, type, name, CodeTreeBuilder.singleString("this." + name))); + } } public CodeExecutableElement createMethod(Set modifiers, TypeMirror returnType, String name, String... optionalArguments) { @@ -2425,6 +2464,11 @@ return values.get(shortCircuitName(execution)); } + @Override + public String toString() { + return "LocalContext [values=" + values + "]"; + } + } public static final class LocalVariable { diff -r bf166845c7d8 -r f4792a544170 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/AssumptionExpression.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/AssumptionExpression.java Wed Feb 11 12:13:44 2015 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/AssumptionExpression.java Wed Feb 11 12:13:44 2015 +0100 @@ -31,10 +31,16 @@ private final TemplateMethod source; private final DSLExpression expression; + private final String id; - public AssumptionExpression(TemplateMethod source, DSLExpression expression) { + public AssumptionExpression(TemplateMethod source, DSLExpression expression, String id) { this.source = source; this.expression = expression; + this.id = id; + } + + public String getId() { + return id; } @Override diff -r bf166845c7d8 -r f4792a544170 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeData.java Wed Feb 11 12:13:44 2015 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeData.java Wed Feb 11 12:13:44 2015 +0100 @@ -42,7 +42,6 @@ private final List children; private final List childExecutions; private final List fields; - private final List assumptions; private ParameterSpec instanceParameterSpec; @@ -64,7 +63,6 @@ this.fields = new ArrayList<>(); this.children = new ArrayList<>(); this.childExecutions = new ArrayList<>(); - this.assumptions = new ArrayList<>(); this.thisExecution = new NodeExecutionData(new NodeChildData(null, null, "this", getNodeType(), getNodeType(), null, Cardinality.ONE), -1, false); this.thisExecution.getChild().setNode(this); this.generateFactory = generateFactory; @@ -217,10 +215,6 @@ return getTemplateType().asType(); } - public List getAssumptions() { - return assumptions; - } - public boolean needsFactory() { if (specializations == null) { return false; @@ -427,7 +421,6 @@ dumpProperty(builder, indent, "fields", getChildren()); dumpProperty(builder, indent, "executableTypes", getExecutableTypes()); dumpProperty(builder, indent, "specializations", getSpecializations()); - dumpProperty(builder, indent, "assumptions", getAssumptions()); dumpProperty(builder, indent, "casts", getCasts()); dumpProperty(builder, indent, "messages", collectMessages()); if (getEnclosingNodes().size() > 0) { diff -r bf166845c7d8 -r f4792a544170 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 Wed Feb 11 12:13:44 2015 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/SpecializationData.java Wed Feb 11 12:13:44 2015 +0100 @@ -46,7 +46,6 @@ private List caches = Collections.emptyList(); private List assumptionExpressions = Collections.emptyList(); private List shortCircuits; - private List assumptions = Collections.emptyList(); private final Set contains = new TreeSet<>(); private final Set containsNames = new TreeSet<>(); private final Set excludedBy = new TreeSet<>(); @@ -159,6 +158,9 @@ if (caches != null) { sinks.addAll(caches); } + if (assumptionExpressions != null) { + sinks.addAll(assumptionExpressions); + } return sinks; } @@ -169,7 +171,7 @@ if (!getGuards().isEmpty()) { return true; } - if (!getAssumptions().isEmpty()) { + if (!getAssumptionExpressions().isEmpty()) { return true; } @@ -260,14 +262,6 @@ return shortCircuits; } - public List getAssumptions() { - return assumptions; - } - - public void setAssumptions(List assumptions) { - this.assumptions = assumptions; - } - public SpecializationData findNextSpecialization() { List specializations = node.getSpecializations(); for (int i = 0; i < specializations.size() - 1; i++) { @@ -317,9 +311,7 @@ } } } - return false; - } public boolean isReachableAfter(SpecializationData prev) { @@ -349,10 +341,10 @@ } } - for (String prevAssumption : prev.getAssumptions()) { - if (!getAssumptions().contains(prevAssumption)) { - return true; - } + if (!prev.getAssumptionExpressions().isEmpty()) { + // TODO: chumer: we could at least check reachability after trivial assumptions + // not sure if this is worth it. + return true; } Iterator prevGuards = prev.getGuards().iterator(); diff -r bf166845c7d8 -r f4792a544170 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 Wed Feb 11 12:13:44 2015 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java Wed Feb 11 12:13:44 2015 +0100 @@ -30,12 +30,14 @@ import javax.lang.model.util.*; import javax.tools.Diagnostic.Kind; +import com.oracle.truffle.api.*; import com.oracle.truffle.api.dsl.*; import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.dsl.processor.*; 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.CodeTypeMirror.ArrayCodeTypeMirror; import com.oracle.truffle.dsl.processor.java.model.*; import com.oracle.truffle.dsl.processor.model.*; import com.oracle.truffle.dsl.processor.model.NodeChildData.Cardinality; @@ -136,8 +138,10 @@ } NodeData node = parseNodeData(templateType, lookupTypes); + if (node.hasErrors()) { + return node; + } - node.getAssumptions().addAll(parseAssumptions(lookupTypes)); node.getFields().addAll(parseFields(lookupTypes, members)); node.getChildren().addAll(parseChildren(lookupTypes, members)); node.getChildExecutions().addAll(parseExecutions(node.getChildren(), members)); @@ -275,24 +279,6 @@ } - private List parseAssumptions(List typeHierarchy) { - List assumptionsList = new ArrayList<>(); - for (int i = typeHierarchy.size() - 1; i >= 0; i--) { - TypeElement type = typeHierarchy.get(i); - AnnotationMirror assumptions = ElementUtils.findAnnotationMirror(context.getEnvironment(), type, NodeAssumptions.class); - if (assumptions != null) { - List assumptionStrings = ElementUtils.getAnnotationValueList(String.class, assumptions, "value"); - for (String string : assumptionStrings) { - if (assumptionsList.contains(string)) { - assumptionsList.remove(string); - } - assumptionsList.add(string); - } - } - } - return assumptionsList; - } - private List parseFields(List typeHierarchy, List elements) { Set names = new HashSet<>(); @@ -562,16 +548,11 @@ Parameter frame = execute.getFrame(); TypeMirror resolvedFrameType; - if (frame == null) { - resolvedFrameType = node.getTypeSystem().getVoidType().getPrimitiveType(); - } else { + if (frame != null) { resolvedFrameType = frame.getType(); - } - - if (frameType == null) { - frameType = resolvedFrameType; - } else { - if (!ElementUtils.typeEquals(frameType, resolvedFrameType)) { + if (frameType == null) { + frameType = resolvedFrameType; + } else if (!ElementUtils.typeEquals(frameType, resolvedFrameType)) { // found inconsistent frame types inconsistentFrameTypes.add(ElementUtils.getSimpleName(frameType)); inconsistentFrameTypes.add(ElementUtils.getSimpleName(resolvedFrameType)); @@ -584,6 +565,10 @@ Collections.sort(inconsistentFrameTypesList); node.addError("Invalid inconsistent frame types %s found for the declared execute methods. The frame type must be identical for all execute methods.", inconsistentFrameTypesList); } + if (frameType == null) { + frameType = context.getType(void.class); + } + node.setFrameType(frameType); int totalGenericCount = 0; @@ -979,9 +964,39 @@ continue; } initializeLimit(specialization, resolver); + initializeAssumptions(specialization, resolver); } } + private void initializeAssumptions(SpecializationData specialization, DSLExpressionResolver resolver) { + final DeclaredType assumptionType = context.getDeclaredType(Assumption.class); + final TypeMirror assumptionArrayType = new ArrayCodeTypeMirror(assumptionType); + final List assumptionDefinitions = ElementUtils.getAnnotationValueList(String.class, specialization.getMarkerAnnotation(), "assumptions"); + List assumptionExpressions = new ArrayList<>(); + int assumptionId = 0; + for (String assumption : assumptionDefinitions) { + AssumptionExpression assumptionExpression; + DSLExpression expression = null; + try { + expression = DSLExpression.parse(assumption); + expression.accept(resolver); + assumptionExpression = new AssumptionExpression(specialization, expression, "assumption" + assumptionId); + if (!ElementUtils.isAssignable(expression.getResolvedType(), assumptionType) && !ElementUtils.isAssignable(expression.getResolvedType(), assumptionArrayType)) { + assumptionExpression.addError("Incompatible return type %s. Assumptions must be assignable to %s or %s.", ElementUtils.getSimpleName(expression.getResolvedType()), + ElementUtils.getSimpleName(assumptionType), ElementUtils.getSimpleName(assumptionArrayType)); + } + if (specialization.isDynamicParameterBound(expression)) { + specialization.addError("Assumption expressions must not bind dynamic parameter values."); + } + } catch (InvalidExpressionException e) { + assumptionExpression = new AssumptionExpression(specialization, null, "assumption" + assumptionId); + assumptionExpression.addError("Error parsing expression '%s': %s", assumption, e.getMessage()); + } + assumptionExpressions.add(assumptionExpression); + } + specialization.setAssumptionExpressions(assumptionExpressions); + } + private void initializeLimit(SpecializationData specialization, DSLExpressionResolver resolver) { AnnotationValue annotationValue = ElementUtils.getAnnotationValue(specialization.getMessageAnnotation(), "limit"); diff -r bf166845c7d8 -r f4792a544170 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 Wed Feb 11 12:13:44 2015 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationGroup.java Wed Feb 11 12:13:44 2015 +0100 @@ -33,7 +33,6 @@ */ public final class SpecializationGroup { - private final List assumptions; private final List typeGuards; private final List guards; @@ -45,12 +44,10 @@ private SpecializationGroup(SpecializationData data) { this.node = data.getNode(); - this.assumptions = new ArrayList<>(); this.typeGuards = new ArrayList<>(); this.guards = new ArrayList<>(); this.specialization = data; - this.assumptions.addAll(data.getAssumptions()); TypeSignature sig = data.getTypeSignature(); for (int i = 1; i < sig.size(); i++) { typeGuards.add(new TypeGuard(sig.get(i), i - 1)); @@ -58,9 +55,8 @@ this.guards.addAll(data.getGuards()); } - public SpecializationGroup(List children, List assumptionMatches, List typeGuardsMatches, List guardMatches) { + public SpecializationGroup(List children, List typeGuardsMatches, List guardMatches) { assert !children.isEmpty() : "children must not be empty"; - this.assumptions = assumptionMatches; this.typeGuards = typeGuardsMatches; this.guards = guardMatches; this.node = children.get(0).node; @@ -78,7 +74,7 @@ } public List findElseConnectableGuards() { - if (!getTypeGuards().isEmpty() || !getAssumptions().isEmpty()) { + if (!getTypeGuards().isEmpty()) { return Collections.emptyList(); } @@ -133,10 +129,6 @@ return parent; } - public List getAssumptions() { - return assumptions; - } - public List getTypeGuards() { return typeGuards; } @@ -161,23 +153,12 @@ return null; } - List assumptionMatches = new ArrayList<>(); List typeGuardsMatches = new ArrayList<>(); List guardMatches = new ArrayList<>(); SpecializationGroup first = groups.get(0); List others = groups.subList(1, groups.size()); - outer: for (String assumption : first.assumptions) { - for (SpecializationGroup other : others) { - if (!other.assumptions.contains(assumption)) { - // assumptions can be combined unordered - continue outer; - } - } - assumptionMatches.add(assumption); - } - outer: for (TypeGuard typeGuard : first.typeGuards) { for (SpecializationGroup other : others) { if (!other.typeGuards.contains(typeGuard)) { @@ -207,18 +188,17 @@ // TODO we need to be smarter here with bound parameters. } - if (assumptionMatches.isEmpty() && typeGuardsMatches.isEmpty() && guardMatches.isEmpty()) { + if (typeGuardsMatches.isEmpty() && guardMatches.isEmpty()) { return null; } for (SpecializationGroup group : groups) { - group.assumptions.removeAll(assumptionMatches); group.typeGuards.removeAll(typeGuardsMatches); group.guards.removeAll(guardMatches); } List newChildren = new ArrayList<>(groups); - return new SpecializationGroup(newChildren, assumptionMatches, typeGuardsMatches, guardMatches); + return new SpecializationGroup(newChildren, typeGuardsMatches, guardMatches); } public static SpecializationGroup create(SpecializationData specialization) { @@ -230,12 +210,12 @@ for (SpecializationData specialization : specializations) { groups.add(new SpecializationGroup(specialization)); } - return new SpecializationGroup(createCombinationalGroups(groups), Collections. emptyList(), Collections. emptyList(), Collections. emptyList()); + return new SpecializationGroup(createCombinationalGroups(groups), Collections. emptyList(), Collections. emptyList()); } @Override public String toString() { - return "SpecializationGroup [assumptions=" + assumptions + ", typeGuards=" + typeGuards + ", guards=" + guards + "]"; + return "SpecializationGroup [typeGuards=" + typeGuards + ", guards=" + guards + "]"; } private static List createCombinationalGroups(List groups) { diff -r bf166845c7d8 -r f4792a544170 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 Wed Feb 11 12:13:44 2015 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationMethodParser.java Wed Feb 11 12:13:44 2015 +0100 @@ -109,15 +109,6 @@ } - List assumptionDefs = ElementUtils.getAnnotationValueList(String.class, specialization.getMarkerAnnotation(), "assumptions"); - specialization.setAssumptions(assumptionDefs); - - for (String assumption : assumptionDefs) { - if (!getNode().getAssumptions().contains(assumption)) { - specialization.addError("Undeclared assumption '%s' used. Use @NodeAssumptions to declare them.", assumption); - } - } - return specialization; } }