changeset 19289:62c43fcf5be2

Truffle-DSL: implement @Cached and fixes for the new guard expression syntax.
author Christian Humer <christian.humer@gmail.com>
date Tue, 03 Feb 2015 15:07:07 +0100
parents 3a37116ef37f
children bf166845c7d8
files graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/CachedTest.java graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/LimitTest.java graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/MethodGuardsTest.java graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TestHelper.java graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/internal/SpecializationNode.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/expression/DSLExpression.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/expression/DSLExpressionResolver.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/expression/Expression.atg graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/expression/Parser.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/expression/Scanner.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/DSLExpressionGenerator.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/AnnotatedParameterSpec.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/CacheExpression.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/MessageContainer.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/MethodSpec.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeFieldData.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/Parameter.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ParameterSpec.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/SpecializationData.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TemplateMethod.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/CreateCastParser.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/MethodSpecParser.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationGroup.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationMethodParser.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TemplateMethodParser.java
diffstat 28 files changed, 1862 insertions(+), 701 deletions(-) [+]
line wrap: on
line diff
--- /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;
+        }
+
+    }
+
+}
--- /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;
+        }
+    }
+
+}
--- 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<Guard1> 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<Guard2> 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";
+        }
+
+    }
+
 }
--- 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<? extends ValueNode> 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 extends ValueNode> T getNode(CallTarget target) {
+        return ((TestRootNode<T>) ((RootCallTarget) target).getRootNode()).getNode();
+    }
+
     static <E> Object executeWith(TestRootNode<? extends ValueNode> node, Object... values) {
         return createCallTarget(node).call(values);
     }
--- 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;
         }
     }
 
--- 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<Variable> findBoundVariables() {
-        final List<Variable> variables = new ArrayList<>();
+    public final Set<VariableElement> findBoundVariableElements() {
+        final Set<VariableElement> 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<Variable> findBoundVariables() {
+        final Set<Variable> 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() {
--- 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<String> IDENTITY_OPERATORS = Arrays.asList("==", "!=");
     private static final String CONSTRUCTOR_KEYWORD = "new";
 
-    private List<VariableElement> variables;
-    private List<ExecutableElement> methods;
+    private final List<VariableElement> variables = new ArrayList<>();
+    private final List<ExecutableElement> methods = new ArrayList<>();
     private final ProcessorContext context;
 
+    private DSLExpressionResolver(ProcessorContext context) {
+        this.context = context;
+    }
+
     public DSLExpressionResolver(ProcessorContext context, List<? extends Element> lookupElements) {
-        this.context = context;
-        this.variables = variablesIn(lookupElements, false);
-        this.methods = methodsIn(lookupElements);
+        this(context);
+        lookup(lookupElements);
     }
 
-    private static List<ExecutableElement> methodsIn(List<? extends Element> lookupElements) {
-        List<ExecutableElement> methods = new ArrayList<>();
+    public DSLExpressionResolver copy(List<? extends Element> prefixElements) {
+        DSLExpressionResolver resolver = new DSLExpressionResolver(context);
+        lookup(prefixElements);
+        resolver.variables.addAll(variables);
+        resolver.methods.addAll(methods);
+        return resolver;
+    }
+
+    private void lookup(List<? extends Element> lookupElements) {
+        variablesIn(variables, lookupElements, false);
+        methodsIn(lookupElements);
+    }
+
+    private void methodsIn(List<? extends Element> 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<VariableElement> variablesIn(List<? extends Element> lookupElements, boolean publicOnly) {
-        List<VariableElement> variables = new ArrayList<>();
+    private static void variablesIn(List<VariableElement> variables, List<? extends Element> 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.<VariableElement> asList(new CodeVariableElement(context.getType(int.class), "length"));
             } else {
--- 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<out DSLExpression result>
 =
+LogicFactor<out result>
+.
+
+
+LogicFactor<out DSLExpression  result>
+=
+ComparisonFactor<out result>
+[
+    ("||")                                      (. Token op = t; .)
+    ComparisonFactor<out DSLExpression  right>  (.  result = new Binary(op.val, result, right); .)
+]
+.
+
+ComparisonFactor<out DSLExpression  result>
+=
 NegateFactor<out result>
+[
+    ("<" | "<=" | ">" | ">=" | "==" | "!=" )    (. Token op = t; .)
+    NegateFactor<out DSLExpression  right>      (.  result = new Binary(op.val, result, right); .)
+]
 .
 
+
 NegateFactor<out DSLExpression  result>
 =                                               (. boolean negated = false; .)
 [
     "!"                                         (. negated = true; .)
 ]                                        
-    LogicFactor<out result>                     (. result = negated ? new Negate(result) : result;.)
-.
-
-
-LogicFactor<out DSLExpression  result>
-=
-Factor<out result>
-[
-    ("<" | "<=" | ">" | ">=" | "==" | "!=" )    (. Token op = t; .)
-    Factor<out DSLExpression  right>            (.  result = new Binary(op.val, result, right); .)
-]
+    Factor<out result>                          (. result = negated ? new Negate(result) : result;.)
 .
 
 
--- 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<DSLExpression> 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<DSLExpression> 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;
--- 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;}
 
             }
         }
--- 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<Variable, CodeTree> bindings) {
         DSLExpressionGenerator writer = new DSLExpressionGenerator(root, bindings);
         expression.accept(writer);
-        return writer.pop();
+        return combine(string("("), writer.pop(), string(")"));
     }
 
 }
--- 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<SpecializationData> 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<SpecializationData> 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<SpecializationData> 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<SpecializationData, CodeTypeElement> 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<GuardExpression> ignoreGuards) {
         for (TypeGuard guard : group.getTypeGuards()) {
             if (currentValues.getValue(guard.getSignatureIndex()) == null) {
                 // not evaluated
@@ -1053,9 +1092,23 @@
             }
         }
 
-        List<GuardExpression> expressions = new ArrayList<>(group.getGuards());
-        expressions.removeAll(group.findElseConnectableGuards());
-        if (!expressions.isEmpty()) {
+        List<GuardExpression> guards = new ArrayList<>(group.getGuards());
+        List<GuardExpression> elseConnectable = group.findElseConnectableGuards();
+        guards.removeAll(elseConnectable);
+        if (ignoreGuards != null) {
+            guards.removeAll(ignoreGuards);
+        }
+        SpecializationData specialization = group.getSpecialization();
+        if (specialization != null && fastPath) {
+            for (ListIterator<GuardExpression> 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<SpecializationGroup> 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<GuardExpression> elseGuardExpressions = group.findElseConnectableGuards();
         List<GuardExpression> 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<Variable, LocalVariable> 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<Variable, LocalVariable> 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<GuardExpression> guardExpressions, SpecializationData specialization, LocalContext currentValues) {
-        CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
+    private CodeTree[] createMethodGuardCheck(List<GuardExpression> 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<Variable, LocalVariable> bindings = bindLocalValues(expression, specialization, currentValues);
-            Map<Variable, CodeTree> 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<Variable, CodeTree> 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<Variable, LocalVariable> bindLocalValues(DSLExpression expression, SpecializationData specialization, LocalContext currentValues) throws AssertionError {
+    private static Map<Variable, CodeTree> castBoundTypes(Map<Variable, LocalVariable> bindings) {
+        Map<Variable, CodeTree> 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<Variable, LocalVariable> bindExpressionValues(DSLExpression expression, SpecializationData specialization, LocalContext currentValues) throws AssertionError {
         Map<Variable, LocalVariable> bindings = new HashMap<>();
 
-        List<Variable> boundVariables = expression.findBoundVariables();
+        Set<Variable> 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<TypeGuard> typeGuards, Set<TypeGuard> castGuards, LocalContext currentValues, SpecializationExecution specializationExecution) {
+    private CodeTree[] createTypeCheckCastAndCaches(SpecializationData specialization, List<TypeGuard> typeGuards, Set<TypeGuard> 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<Modifier> modifiers, TypeMirror returnType, String name, String... optionalArguments) {
             CodeExecutableElement method = new CodeExecutableElement(modifiers, returnType, name);
             addParametersTo(method, optionalArguments);
--- 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");
+        }
+    }
 }
--- /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.<TypeMirror> 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;
+    }
+
+}
--- 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();
--- 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<String> 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<String> expectedTexts = ElementUtils.getAnnotationValueList(String.class, mirror, "value");
                 boolean found = false;
--- 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<ParameterSpec> optional = new ArrayList<>();
     private final List<ParameterSpec> required = new ArrayList<>();
+    private final List<ParameterSpec> annotations = new ArrayList<>();
 
     private boolean ignoreAdditionalParameters;
     private boolean ignoreAdditionalSpecifications;
@@ -69,6 +70,10 @@
         return spec;
     }
 
+    public List<ParameterSpec> getAnnotations() {
+        return annotations;
+    }
+
     public ParameterSpec getReturnType() {
         return returnType;
     }
--- 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() {
--- 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();
     }
 }
--- 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
--- 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<SpecializationThrowsData> exceptions) {
         super(template);
@@ -65,15 +68,33 @@
         }
     }
 
+    public boolean isDynamicParameterBound(DSLExpression expression) {
+        Set<VariableElement> 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<Parameter> getDynamicParameters() {
+        List<Parameter> uncachedParameters = new ArrayList<>(getParameters());
+        for (CacheExpression cacheExpression : getCaches()) {
+            uncachedParameters.remove(cacheExpression.getParameter());
+        }
+        return uncachedParameters;
+    }
+
     @Override
     protected List<MessageContainer> findChildContainers() {
         List<MessageContainer> 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<Parameter> currentSignature = getSignatureParameters().iterator();
-        Iterator<Parameter> 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<GuardExpression> 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<VariableElement> 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;
+    }
+
 }
--- 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<Parameter> getRequiredParameters() {
-        List<Parameter> requiredParameters = new ArrayList<>();
-        for (Parameter parameter : getParameters()) {
-            if (getSpecification().getRequired().contains(parameter.getSpecification())) {
-                requiredParameters.add(parameter);
-            }
-        }
-        return requiredParameters;
-    }
-
     public Iterable<Parameter> getSignatureParameters() {
         return new FilteredIterable<>(getParameters(), new Predicate<Parameter>() {
             public boolean evaluate(Parameter value) {
--- 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;
                 }
--- 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<TypeMirror> 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<TypeMirror> parameterTypes) {
+                    List<? extends VariableElement> 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.<Parameter> 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<Parameter> parseParameters(MethodSpec spec, List<TypeMirror> parameterTypes, boolean varArgs) {
+    private List<Parameter> parseParameters(MethodSpec spec, List<? extends VariableElement> parameterTypes, boolean varArgs) {
         List<Parameter> parsedRequired = null;
         int offset = 0;
         for (; offset <= parameterTypes.size(); offset++) {
-            List<TypeMirror> parameters = new ArrayList<>();
+            List<VariableElement> 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<TypeMirror> potentialOptionals = parameterTypes.subList(0, offset);
+        List<? extends VariableElement> potentialOptionals = parameterTypes.subList(0, offset);
         List<Parameter> parsedOptionals = parseParametersOptional(spec, potentialOptionals);
         if (parsedOptionals == null) {
             return null;
@@ -178,7 +166,7 @@
         return finalParameters;
     }
 
-    private List<Parameter> parseParametersOptional(MethodSpec spec, List<TypeMirror> types) {
+    private List<Parameter> parseParametersOptional(MethodSpec spec, List<? extends VariableElement> types) {
         List<Parameter> 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<Parameter> parseParametersRequired(MethodSpec spec, List<TypeMirror> types, boolean typeVarArgs) {
+    private List<Parameter> parseParametersRequired(MethodSpec spec, List<VariableElement> types, boolean typeVarArgs) {
         List<Parameter> parsedParams = new ArrayList<>();
         List<ParameterSpec> 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<ParameterSpec> 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<TypeMirror> types, int typeIndex, boolean varArgs) {
+    private static VariableElement nextActualType(List<VariableElement> 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);
         }
     }
 
--- 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<? extends ExecutableElement> 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<? extends Element> 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<Element> 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<TypeElement> 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<TypeMirror> 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<? extends Element> 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<SpecializationData> 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<? extends Element> elements, NodeData node) {
         List<Element> members = filterNotAccessibleElements(node.getTemplateType(), elements);
 
-        final TypeMirror booleanType = context.getType(boolean.class);
+        List<VariableElement> fields = new ArrayList<>();
+        for (NodeFieldData field : node.getFields()) {
+            fields.add(field.getVariable());
+        }
 
         for (SpecializationData specialization : node.getSpecializations()) {
             if (specialization.getMethod() == null) {
                 continue;
             }
 
-            List<Element> specializationMembers = new ArrayList<>();
+            List<Element> 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<CacheExpression> 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<String> guardDefinitions = ElementUtils.getAnnotationValueList(String.class, specialization.getMarkerAnnotation(), "guards");
-            List<GuardExpression> 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<VariableElement> 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<String> guardDefinitions = ElementUtils.getAnnotationValueList(String.class, specialization.getMarkerAnnotation(), "guards");
+        List<GuardExpression> 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<Element> filterNotAccessibleElements(TypeElement templateType, List<? extends Element> elements) {
         String packageName = ElementUtils.getPackageName(templateType);
         List<Element> 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<TypeMirror> parameterTypes = new ArrayList<>();
+        List<VariableElement> 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++;
             }
--- 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<SpecializationGroup> childs) {
         if (!children.isEmpty()) {
             children.clear();
@@ -381,4 +363,16 @@
         }
     }
 
+    public SpecializationGroup getPrevious() {
+        if (getParent() == null) {
+            return null;
+        }
+
+        List<SpecializationGroup> parentChildren = getParent().getChildren();
+        int index = parentChildren.indexOf(this);
+        if (index <= 0) {
+            return null;
+        }
+        return parentChildren.get(index - 1);
+    }
 }
--- 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
--- 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<TypeMirror> parameterTypes) {
+    public final E create(String id, int naturalOrder, ExecutableElement methodMetadata, AnnotationMirror mirror, TypeMirror returnType, List<VariableElement> parameterTypes) {
         TemplateMethod method = parser.parseImpl(createSpecification(methodMetadata, mirror), naturalOrder, id, methodMetadata, mirror, returnType, parameterTypes);
         if (method != null) {
             return create(method, method.hasErrors());