changeset 11205:13d0d29aa15c

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