changeset 7387:64f4195d0ecf

Merge.
author Christian Haeubl <haeubl@ssw.jku.at>
date Wed, 19 Dec 2012 10:01:08 +0100
parents 707e9cca11de (current diff) 346336325337 (diff)
children 599ea4fcdb6d
files graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java
diffstat 99 files changed, 5310 insertions(+), 395 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/DeoptimizationAction.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/DeoptimizationAction.java	Wed Dec 19 10:01:08 2012 +0100
@@ -28,6 +28,9 @@
 public enum DeoptimizationAction {
     /**
      * Do not invalidate the machine code.
+     * This is typically used when deoptimizing at a point where it's highly likely
+     * nothing will change the likelihood of the deoptimization happening again.
+     * For example, a compiled array allocation where the size is negative.
      */
     None,
 
@@ -43,6 +46,9 @@
 
     /**
      * Invalidate the machine code and immediately schedule a recompilation.
+     * This is typically used when deoptimizing to resolve an unresolved symbol in
+     * which case extra profiling is not required to determine that the deoptimization
+     * will not re-occur.
      */
     InvalidateRecompile,
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Wed Dec 19 10:01:08 2012 +0100
@@ -26,7 +26,7 @@
 import java.util.*;
 import java.util.concurrent.*;
 
-import junit.framework.*;
+import org.junit.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
@@ -162,8 +162,37 @@
 
     private static int compilationId = 0;
 
+    /**
+     * Compares two given objects for {@linkplain Assert#assertEquals(Object, Object) equality}.
+     * Does a deep copy equality comparison if {@code expected} is an array.
+     */
     protected void assertEquals(Object expected, Object actual) {
-        Assert.assertEquals(expected, actual);
+        if (expected != null && expected.getClass().isArray()) {
+            Assert.assertTrue(expected != null);
+            Assert.assertTrue(actual != null);
+            Assert.assertEquals(expected.getClass(), actual.getClass());
+            if (expected instanceof int[]) {
+                Assert.assertArrayEquals((int[]) expected, (int[]) actual);
+            } else if (expected instanceof byte[]) {
+                Assert.assertArrayEquals((byte[]) expected, (byte[]) actual);
+            } else if (expected instanceof char[]) {
+                Assert.assertArrayEquals((char[]) expected, (char[]) actual);
+            } else if (expected instanceof short[]) {
+                Assert.assertArrayEquals((short[]) expected, (short[]) actual);
+            } else if (expected instanceof float[]) {
+                Assert.assertArrayEquals((float[]) expected, (float[]) actual, 0.0f);
+            } else if (expected instanceof long[]) {
+                Assert.assertArrayEquals((long[]) expected, (long[]) actual);
+            } else if (expected instanceof double[]) {
+                Assert.assertArrayEquals((double[]) expected, (double[]) actual, 0.0d);
+            } else if (expected instanceof Object[]) {
+                Assert.assertArrayEquals((Object[]) expected, (Object[]) actual);
+            } else {
+                Assert.fail("non-array value encountered: " + expected);
+            }
+        } else {
+            Assert.assertEquals(expected, actual);
+        }
     }
 
     protected void testN(int n, final String name, final Object... args) {
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Wed Dec 19 10:01:08 2012 +0100
@@ -369,7 +369,7 @@
                 NodeList<Node> list = getNodeList(node, offsets[index]);
                 return list.get(subIndex);
             }
-            return null;
+            throw new NoSuchElementException();
         }
 
         @Override
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeUsagesList.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeUsagesList.java	Wed Dec 19 10:01:08 2012 +0100
@@ -146,16 +146,6 @@
         }
     }
 
-    boolean replaceFirst(Node node, Node other) {
-        for (int i = 0; i < size; i++) {
-            if (nodes[i] == node) {
-                nodes[i] = other;
-                return true;
-            }
-        }
-        return false;
-    }
-
     @Override
     public String toString() {
         StringBuilder str = new StringBuilder();
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/FilteredNodeIterable.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/FilteredNodeIterable.java	Wed Dec 19 10:01:08 2012 +0100
@@ -53,7 +53,7 @@
     }
     @Override
     public FilteredNodeIterable<T> nonNull() {
-        this.predicate = this.predicate.or(NodePredicates.isNotNull());
+        this.predicate = this.predicate.and(NodePredicates.isNotNull());
         return this;
     }
     @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/ArrayCopyIntrinsificationTest.java	Wed Dec 19 10:01:08 2012 +0100
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2011, 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.graal.hotspot;
+
+import static org.junit.Assert.*;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+import org.junit.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.test.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.hotspot.snippets.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.PhasePlan.PhasePosition;
+
+
+/**
+ * Tests intrinsification of {@link System#arraycopy(Object, int, Object, int, int)}.
+ */
+public class ArrayCopyIntrinsificationTest extends GraalCompilerTest {
+
+    @Override
+    protected void editPhasePlan(ResolvedJavaMethod method, StructuredGraph graph, PhasePlan phasePlan) {
+        phasePlan.addPhase(PhasePosition.HIGH_LEVEL, new IntrinsifyArrayCopyPhase(runtime, new Assumptions(false)));
+    }
+
+    @Override
+    protected InstalledCode getCode(ResolvedJavaMethod method, StructuredGraph graph) {
+        int nodeCount = graph.getNodeCount();
+        InstalledCode result = super.getCode(method, graph);
+        boolean graphWasProcessed = nodeCount != graph.getNodeCount();
+        if (graphWasProcessed) {
+            if (mustIntrinsify) {
+                for (Node node: graph.getNodes()) {
+                    if (node instanceof Invoke) {
+                        Invoke invoke = (Invoke) node;
+                        Assert.assertTrue(invoke.callTarget() instanceof DirectCallTargetNode);
+                        DirectCallTargetNode directCall = (DirectCallTargetNode) invoke.callTarget();
+                        Assert.assertTrue(directCall.target() instanceof JavaMethod);
+                        JavaMethod callee = (JavaMethod) directCall.target();
+                        Assert.assertTrue(callee.getName().equals("<init>"));
+                        Assert.assertTrue(runtime.lookupJavaType(ArrayIndexOutOfBoundsException.class).equals(callee.getDeclaringClass()) ||
+                                          runtime.lookupJavaType(NullPointerException.class).equals(callee.getDeclaringClass()));
+                    }
+                }
+            } else {
+                boolean found = false;
+                for (Node node: graph.getNodes()) {
+                    if (node instanceof Invoke) {
+                        Invoke invoke = (Invoke) node;
+                        DirectCallTargetNode directCall = (DirectCallTargetNode) invoke.callTarget();
+                        JavaMethod callee = (JavaMethod) directCall.target();
+                        if (callee.getDeclaringClass().equals(runtime.lookupJavaType(System.class)) && callee.getName().equals("arraycopy")) {
+                            found = true;
+                        } else {
+                            fail("found invoke to some method other than arraycopy: " + callee);
+                        }
+                    }
+                }
+                Assert.assertTrue("did not find invoke to arraycopy", found);
+            }
+        }
+        return result;
+    }
+
+    boolean mustIntrinsify = true;
+
+    @Test
+    public void test0() {
+        mustIntrinsify = false; // a generic call to arraycopy will not be intrinsified
+        // Array store checks
+        test("genericArraycopy", new Object(), 0, new Object[0], 0, 0);
+        test("genericArraycopy", new Object[0], 0, new Object(), 0, 0);
+    }
+
+    @Test
+    public void test1() {
+        String name = "intArraycopy";
+        int[] src = {234, 5345, 756, 23, 8, 345, 873, 440};
+        // Null checks
+        test(name, null, 0, src, 0, 0);
+        test(name, src, 0, null, 0, 0);
+        // Bounds checks
+        test(name, src, 0, src, 0, -1);
+        test(name, src, 0, src, 0, src.length + 1);
+    }
+
+    @Test
+    public void testByte() {
+        byte[] src = {-1, 0, 1, 2, 3, 4};
+        testHelper("byteArraycopy", src);
+    }
+
+    @Test
+    public void testChar() {
+        char[] src = "some string of chars".toCharArray();
+        testHelper("charArraycopy", src);
+    }
+
+    @Test
+    public void testShort() {
+        short[] src = {234, 5345, 756, 23, 8, 345, 873, 440};
+        testHelper("shortArraycopy", src);
+    }
+
+    @Test
+    public void testInt() {
+        int[] src = {234, 5345, 756, 23, 8, 345, 873, 440};
+        testHelper("intArraycopy", src);
+    }
+
+    @Test
+    public void testFloat() {
+        float[] src = {234, 5345, 756, 23, 8, 345, 873, 440};
+        testHelper("floatArraycopy", src);
+    }
+
+    @Test
+    public void testLong() {
+        long[] src = {234, 5345, 756, 23, 8, 345, 873, 440};
+        testHelper("longArraycopy", src);
+    }
+
+    @Test
+    public void testDouble() {
+        double[] src = {234, 5345, 756, 23, 8, 345, 873, 440};
+        testHelper("doubleArraycopy", src);
+    }
+
+    @Test
+    public void testObject() {
+        Object[] src = {"one", "two", "three", new ArrayList<>(), new HashMap<>()};
+        testHelper("objectArraycopy", src);
+    }
+
+    private static Object newArray(Object proto, int length) {
+        assert proto != null;
+        assert proto.getClass().isArray();
+        return Array.newInstance(proto.getClass().getComponentType(), length);
+    }
+
+    private void testHelper(String name, Object src) {
+        int srcLength = Array.getLength(src);
+
+        // Complete array copy
+        test(name, src, 0, newArray(src, srcLength), 0, srcLength);
+
+        for (int length : new int[] {0, 1, srcLength - 1, srcLength}) {
+            // Partial array copying
+            test(name, src, 0, newArray(src, length), 0, length);
+            test(name, src, srcLength - length, newArray(src, length), 0, length);
+            test(name, src, 0, newArray(src, srcLength), 0, length);
+        }
+    }
+
+    public static Object genericArraycopy(Object src, int srcPos, Object dst, int dstPos, int length) {
+        System.arraycopy(src, srcPos, dst, dstPos, length);
+        return dst;
+    }
+
+    public static Object[] objectArraycopy(Object[] src, int srcPos, Object[] dst, int dstPos, int length) {
+        System.arraycopy(src, srcPos, dst, dstPos, length);
+        return dst;
+    }
+
+    public static boolean[] booleanArraycopy(boolean[] src, int srcPos, boolean[] dst, int dstPos, int length) {
+        System.arraycopy(src, srcPos, dst, dstPos, length);
+        return dst;
+    }
+
+    public static byte[] byteArraycopy(byte[] src, int srcPos, byte[] dst, int dstPos, int length) {
+        System.arraycopy(src, srcPos, dst, dstPos, length);
+        return dst;
+    }
+
+    public static char[] charArraycopy(char[] src, int srcPos, char[] dst, int dstPos, int length) {
+        System.arraycopy(src, srcPos, dst, dstPos, length);
+        return dst;
+    }
+
+    public static short[] shortArraycopy(short[] src, int srcPos, short[] dst, int dstPos, int length) {
+        System.arraycopy(src, srcPos, dst, dstPos, length);
+        return dst;
+    }
+
+    public static int[] intArraycopy(int[] src, int srcPos, int[] dst, int dstPos, int length) {
+        System.arraycopy(src, srcPos, dst, dstPos, length);
+        return dst;
+    }
+
+    public static float[] floatArraycopy(float[] src, int srcPos, float[] dst, int dstPos, int length) {
+        System.arraycopy(src, srcPos, dst, dstPos, length);
+        return dst;
+    }
+
+    public static long[] longArraycopy(long[] src, int srcPos, long[] dst, int dstPos, int length) {
+        System.arraycopy(src, srcPos, dst, dstPos, length);
+        return dst;
+    }
+
+    public static double[] doubleArraycopy(double[] src, int srcPos, double[] dst, int dstPos, int length) {
+        System.arraycopy(src, srcPos, dst, dstPos, length);
+        return dst;
+    }
+
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Wed Dec 19 10:01:08 2012 +0100
@@ -676,6 +676,8 @@
             checkcastSnippets.lower((CheckCastDynamicNode) n);
         } else if (n instanceof InstanceOfNode) {
             instanceofSnippets.lower((InstanceOfNode) n, tool);
+        } else if (n instanceof InstanceOfDynamicNode) {
+            instanceofSnippets.lower((InstanceOfDynamicNode) n, tool);
         } else if (n instanceof NewInstanceNode) {
             newObjectSnippets.lower((NewInstanceNode) n, tool);
         } else if (n instanceof NewArrayNode) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/OnStackReplacementPhase.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/OnStackReplacementPhase.java	Wed Dec 19 10:01:08 2012 +0100
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.hotspot.phases;
 
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.code.RuntimeCallTarget.*;
 import com.oracle.graal.api.meta.*;
@@ -89,7 +91,7 @@
         } while (true);
 
 
-        LocalNode buffer = graph.unique(new LocalNode(0, StampFactory.forKind(Kind.Long)));
+        LocalNode buffer = graph.unique(new LocalNode(0, StampFactory.forKind(wordKind())));
         RuntimeCallNode migrationEnd = graph.add(new RuntimeCallNode(OSR_MIGRATION_END, buffer));
         FrameState osrState = osr.stateAfter();
         migrationEnd.setStateAfter(osrState);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ArrayCopySnippets.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ArrayCopySnippets.java	Wed Dec 19 10:01:08 2012 +0100
@@ -21,8 +21,11 @@
  * questions.
  */
 package com.oracle.graal.hotspot.snippets;
+import static com.oracle.graal.api.code.DeoptimizationAction.*;
+import static com.oracle.graal.api.meta.DeoptimizationReason.*;
 import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*;
 
+import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.nodes.*;
@@ -42,7 +45,6 @@
     private static final Kind VECTOR_KIND = Kind.Long;
     private static final long VECTOR_SIZE = arrayIndexScale(Kind.Long);
 
-    @Snippet
     public static void vectorizedCopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter("baseKind") Kind baseKind) {
         checkInputs(src, srcPos, dest, destPos, length);
         int header = arrayBaseOffset(baseKind);
@@ -71,13 +73,12 @@
         }
     }
 
-    @Snippet
     public static void checkInputs(Object src, int srcPos, Object dest, int destPos, int length) {
         if (src == null || dest == null) {
             throw new NullPointerException();
         }
         if (srcPos < 0 || destPos < 0 || length < 0 || srcPos + length > ArrayLengthNode.arrayLength(src) || destPos + length > ArrayLengthNode.arrayLength(dest)) {
-            throw new IndexOutOfBoundsException();
+            throw new ArrayIndexOutOfBoundsException();
         }
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java	Wed Dec 19 10:01:08 2012 +0100
@@ -33,7 +33,6 @@
 import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
@@ -99,7 +98,7 @@
             return object;
         }
         Word objectHub = loadHub(object);
-        if (loadWordFromWord(objectHub, superCheckOffset) != hub) {
+        if (objectHub.readWord(superCheckOffset) != hub) {
             displayMiss.inc();
             DeoptimizeNode.deopt(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.ClassCastException);
         }
@@ -157,12 +156,12 @@
     }
 
     static Word loadWordElement(Word metaspaceArray, int index) {
-        return loadWordFromWord(metaspaceArray, metaspaceArrayBaseOffset() + index * wordSize());
+        return metaspaceArray.readWord(metaspaceArrayBaseOffset() + index * wordSize());
     }
 
     static boolean checkSecondarySubType(Word t, Word s) {
         // if (S.cache == T) return true
-        if (loadWordFromWord(s, secondarySuperCacheOffset()) == t) {
+        if (s.readWord(secondarySuperCacheOffset()) == t) {
             cacheHit.inc();
             return true;
         }
@@ -174,8 +173,8 @@
         }
 
         // if (S.scan_s_s_array(T)) { S.cache = T; return true; }
-        Word secondarySupers = loadWordFromWord(s, secondarySupersOffset());
-        int length = loadIntFromWord(secondarySupers, metaspaceArrayLengthOffset());
+        Word secondarySupers = s.readWord(secondarySupersOffset());
+        int length = secondarySupers.readInt(metaspaceArrayLengthOffset());
         for (int i = 0; i < length; i++) {
             if (t == loadWordElement(secondarySupers, i)) {
                 DirectObjectStoreNode.storeWord(s, secondarySuperCacheOffset(), 0, t);
@@ -189,11 +188,11 @@
 
     static boolean checkUnknownSubType(Word t, Word s) {
         // int off = T.offset
-        int superCheckOffset = UnsafeLoadNode.load(t, 0, superCheckOffsetOffset(), Kind.Int);
+        int superCheckOffset = t.readInt(superCheckOffsetOffset());
         boolean primary = superCheckOffset != secondarySuperCacheOffset();
 
         // if (T = S[off]) return true
-        if (loadWordFromWord(s, superCheckOffset) == t) {
+        if (s.readWord(superCheckOffset) == t) {
             if (primary) {
                 cacheHit.inc();
             } else {
@@ -215,8 +214,8 @@
         }
 
         // if (S.scan_s_s_array(T)) { S.cache = T; return true; }
-        Word secondarySupers = loadWordFromWord(s, secondarySupersOffset());
-        int length = loadIntFromWord(secondarySupers, metaspaceArrayLengthOffset());
+        Word secondarySupers = s.readWord(secondarySupersOffset());
+        int length = secondarySupers.readInt(metaspaceArrayLengthOffset());
         for (int i = 0; i < length; i++) {
             if (t == loadWordElement(secondarySupers, i)) {
                 DirectObjectStoreNode.storeWord(s, secondarySuperCacheOffset(), 0, t);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ClassSnippets.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ClassSnippets.java	Wed Dec 19 10:01:08 2012 +0100
@@ -23,9 +23,11 @@
 package com.oracle.graal.hotspot.snippets;
 
 import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*;
+import static com.oracle.graal.nodes.extended.UnsafeCastNode.*;
 
 import java.lang.reflect.*;
 
+import com.oracle.graal.nodes.*;
 import com.oracle.graal.snippets.*;
 import com.oracle.graal.snippets.ClassSubstitution.MethodSubstitution;
 
@@ -41,7 +43,7 @@
             // Class for primitive type
             return Modifier.ABSTRACT | Modifier.FINAL | Modifier.PUBLIC;
         } else {
-            return loadIntFromWord(klass, klassModifierFlagsOffset());
+            return klass.readInt(klassModifierFlagsOffset());
         }
     }
 
@@ -51,7 +53,7 @@
         if (klass == Word.zero()) {
             return false;
         } else {
-            int accessFlags = loadIntFromWord(klass, klassAccessFlagsOffset());
+            int accessFlags = klass.readInt(klassAccessFlagsOffset());
             return (accessFlags & Modifier.INTERFACE) != 0;
         }
     }
@@ -62,7 +64,7 @@
         if (klass == Word.zero()) {
             return false;
         } else {
-            int layoutHelper = loadIntFromWord(klass, klassLayoutHelperOffset());
+            int layoutHelper = klass.readInt(klassLayoutHelperOffset());
             return (layoutHelper & arrayKlassLayoutHelperIdentifier()) != 0;
         }
     }
@@ -77,17 +79,17 @@
     public static Class<?> getSuperclass(final Class<?> thisObj) {
         Word klass = loadWordFromObject(thisObj, klassOffset());
         if (klass != Word.zero()) {
-            int accessFlags = loadIntFromWord(klass, klassAccessFlagsOffset());
+            int accessFlags = klass.readInt(klassAccessFlagsOffset());
             if ((accessFlags & Modifier.INTERFACE) == 0) {
-                int layoutHelper = loadIntFromWord(klass, klassLayoutHelperOffset());
+                int layoutHelper = klass.readInt(klassLayoutHelperOffset());
                 if ((layoutHelper & arrayKlassLayoutHelperIdentifier()) != 0) {
                     return Object.class;
                 } else {
-                    Word superKlass = loadWordFromWord(klass, klassSuperKlassOffset());
+                    Word superKlass = klass.readWord(klassSuperKlassOffset());
                     if (superKlass == Word.zero()) {
                         return null;
                     } else {
-                        return (Class<?>) loadObjectFromWord(superKlass, classMirrorOffset());
+                        return unsafeCast(superKlass.readObject(classMirrorOffset()), Class.class, true, true);
                     }
                 }
             }
@@ -99,11 +101,17 @@
     public static Class<?> getComponentType(final Class<?> thisObj) {
         Word klass = loadWordFromObject(thisObj, klassOffset());
         if (klass != Word.zero()) {
-            int layoutHelper = loadIntFromWord(klass, klassLayoutHelperOffset());
+            int layoutHelper = klass.readInt(klassLayoutHelperOffset());
             if ((layoutHelper & arrayKlassLayoutHelperIdentifier()) != 0) {
-                return (Class<?>) loadObjectFromWord(klass, arrayKlassComponentMirrorOffset());
+                return unsafeCast(klass.readObject(arrayKlassComponentMirrorOffset()), Class.class, true, true);
             }
         }
         return null;
     }
+
+    @MethodSubstitution(isStatic = false)
+    public static boolean isInstance(final Class<?> thisObj, Object obj) {
+        return MaterializeNode.isInstance(thisObj, obj);
+    }
+
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/HotSpotSnippetUtils.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/HotSpotSnippetUtils.java	Wed Dec 19 10:01:08 2012 +0100
@@ -285,36 +285,16 @@
         return HotSpotSnippetUtils.registerAsWord(threadRegister());
     }
 
-    public static int loadIntFromWord(Word address, int offset) {
-        Integer value = UnsafeLoadNode.load(address, 0, offset, Kind.Int);
-        return value;
-    }
-
-    public static Word loadWordFromWord(Word address, int offset) {
-        return loadWordFromWordIntrinsic(address, 0, offset, wordKind());
-    }
-
-    static Object loadObjectFromWord(Word address, int offset) {
-        return UnsafeLoadNode.load(address, 0, offset, Kind.Object);
-    }
-
     public static Word loadWordFromObject(Object object, int offset) {
         return loadWordFromObjectIntrinsic(object, 0, offset, wordKind());
     }
 
-    public static Object readFinalObject(Word base, @ConstantNodeParameter int displacement) {
-        return ReadNode.read(base, displacement, LocationNode.FINAL_LOCATION, Kind.Object);
-    }
-
     @NodeIntrinsic(value = RegisterNode.class, setStampFromReturnType = true)
     public static native Word registerAsWord(@ConstantNodeParameter Register register);
 
     @NodeIntrinsic(value = UnsafeLoadNode.class, setStampFromReturnType = true)
     private static native Word loadWordFromObjectIntrinsic(Object object, @ConstantNodeParameter int displacement, long offset, @ConstantNodeParameter Kind wordKind);
 
-    @NodeIntrinsic(value = UnsafeLoadNode.class, setStampFromReturnType = true)
-    private static native Word loadWordFromWordIntrinsic(Word address, @ConstantNodeParameter int displacement, long offset, @ConstantNodeParameter Kind wordKind);
-
     @NodeIntrinsic(value = LoadHubNode.class, setStampFromReturnType = true)
     static native Word loadHubIntrinsic(Object object, @ConstantNodeParameter Kind word);
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/InstanceOfSnippets.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/InstanceOfSnippets.java	Wed Dec 19 10:01:08 2012 +0100
@@ -93,7 +93,7 @@
             return falseValue;
         }
         Word objectHub = loadHub(object);
-        if (loadWordFromWord(objectHub, superCheckOffset) != hub) {
+        if (objectHub.readWord(superCheckOffset) != hub) {
             displayMiss.inc();
             return falseValue;
         }
@@ -134,7 +134,7 @@
 
     static boolean checkSecondarySubType(Word t, Word s) {
         // if (S.cache == T) return true
-        if (loadWordFromWord(s, secondarySuperCacheOffset()) == t) {
+        if (s.readWord(secondarySuperCacheOffset()) == t) {
             cacheHit.inc();
             return true;
         }
@@ -146,8 +146,8 @@
         }
 
         // if (S.scan_s_s_array(T)) { S.cache = T; return true; }
-        Word secondarySupers = loadWordFromWord(s, secondarySupersOffset());
-        int length = loadIntFromWord(secondarySupers, metaspaceArrayLengthOffset());
+        Word secondarySupers = s.readWord(secondarySupersOffset());
+        int length = secondarySupers.readInt(metaspaceArrayLengthOffset());
         for (int i = 0; i < length; i++) {
             if (t == loadWordElement(secondarySupers, i)) {
                 DirectObjectStoreNode.storeObject(s, secondarySuperCacheOffset(), 0, t);
@@ -159,45 +159,83 @@
         return false;
     }
 
+    /**
+     * Type test used when the type being tested against is not known at compile time.
+     */
+    @Snippet
+    public static Object instanceofDynamic(
+                    @Parameter("mirror") Class mirror,
+                    @Parameter("object") Object object,
+                    @Parameter("trueValue") Object trueValue,
+                    @Parameter("falseValue") Object falseValue,
+                    @ConstantParameter("checkNull") boolean checkNull) {
+        if (checkNull && object == null) {
+            isNull.inc();
+            return falseValue;
+        }
+
+        Word hub = loadWordFromObject(mirror, klassOffset());
+        Word objectHub = loadHub(object);
+        if (!checkUnknownSubType(hub, objectHub)) {
+            return falseValue;
+        }
+        return trueValue;
+    }
+
     public static class Templates extends InstanceOfSnippetsTemplates<InstanceOfSnippets> {
 
         private final ResolvedJavaMethod instanceofExact;
         private final ResolvedJavaMethod instanceofPrimary;
         private final ResolvedJavaMethod instanceofSecondary;
+        private final ResolvedJavaMethod instanceofDynamic;
 
         public Templates(CodeCacheProvider runtime, Assumptions assumptions, TargetDescription target) {
             super(runtime, assumptions, target, InstanceOfSnippets.class);
             instanceofExact = snippet("instanceofExact", Object.class, Word.class, Object.class, Object.class, boolean.class);
             instanceofPrimary = snippet("instanceofPrimary", Word.class, Object.class, Object.class, Object.class, boolean.class, int.class);
             instanceofSecondary = snippet("instanceofSecondary", Word.class, Object.class, Object.class, Object.class, Word[].class, boolean.class);
+            instanceofDynamic = snippet("instanceofDynamic", Class.class, Object.class, Object.class, Object.class, boolean.class);
         }
 
         @Override
         protected KeyAndArguments getKeyAndArguments(InstanceOfUsageReplacer replacer, LoweringTool tool) {
-            InstanceOfNode instanceOf = replacer.instanceOf;
-            ValueNode trueValue = replacer.trueValue;
-            ValueNode falseValue = replacer.falseValue;
-            ValueNode object = instanceOf.object();
-            TypeCheckHints hintInfo = new TypeCheckHints(instanceOf.type(), instanceOf.profile(), tool.assumptions(), GraalOptions.InstanceOfMinHintHitProbability, GraalOptions.InstanceOfMaxHints);
-            final HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) instanceOf.type();
-            ConstantNode hub = ConstantNode.forConstant(type.klass(), runtime, instanceOf.graph());
-            boolean checkNull = !object.stamp().nonNull();
-            Arguments arguments;
-            Key key;
-            if (hintInfo.exact) {
-                ConstantNode[] hints = createHints(hintInfo, runtime, hub.graph());
-                assert hints.length == 1;
-                key = new Key(instanceofExact).add("checkNull", checkNull);
-                arguments = arguments("object", object).add("exactHub", hints[0]).add("trueValue", trueValue).add("falseValue", falseValue);
-            } else if (type.isPrimaryType()) {
-                key = new Key(instanceofPrimary).add("checkNull", checkNull).add("superCheckOffset", type.superCheckOffset());
-                arguments = arguments("hub", hub).add("object", object).add("trueValue", trueValue).add("falseValue", falseValue);
+            if (replacer.instanceOf instanceof InstanceOfNode) {
+                InstanceOfNode instanceOf = (InstanceOfNode) replacer.instanceOf;
+                ValueNode trueValue = replacer.trueValue;
+                ValueNode falseValue = replacer.falseValue;
+                ValueNode object = instanceOf.object();
+                TypeCheckHints hintInfo = new TypeCheckHints(instanceOf.type(), instanceOf.profile(), tool.assumptions(), GraalOptions.InstanceOfMinHintHitProbability, GraalOptions.InstanceOfMaxHints);
+                final HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) instanceOf.type();
+                ConstantNode hub = ConstantNode.forConstant(type.klass(), runtime, instanceOf.graph());
+                boolean checkNull = !object.stamp().nonNull();
+                Arguments arguments;
+                Key key;
+                if (hintInfo.exact) {
+                    ConstantNode[] hints = createHints(hintInfo, runtime, hub.graph());
+                    assert hints.length == 1;
+                    key = new Key(instanceofExact).add("checkNull", checkNull);
+                    arguments = arguments("object", object).add("exactHub", hints[0]).add("trueValue", trueValue).add("falseValue", falseValue);
+                } else if (type.isPrimaryType()) {
+                    key = new Key(instanceofPrimary).add("checkNull", checkNull).add("superCheckOffset", type.superCheckOffset());
+                    arguments = arguments("hub", hub).add("object", object).add("trueValue", trueValue).add("falseValue", falseValue);
+                } else {
+                    ConstantNode[] hints = createHints(hintInfo, runtime, hub.graph());
+                    key = new Key(instanceofSecondary).add("hints", Varargs.vargargs(new Word[hints.length], StampFactory.forKind(wordKind()))).add("checkNull", checkNull);
+                    arguments = arguments("hub", hub).add("object", object).add("hints", hints).add("trueValue", trueValue).add("falseValue", falseValue);
+                }
+                return new KeyAndArguments(key, arguments);
             } else {
-                ConstantNode[] hints = createHints(hintInfo, runtime, hub.graph());
-                key = new Key(instanceofSecondary).add("hints", Varargs.vargargs(new Word[hints.length], StampFactory.forKind(wordKind()))).add("checkNull", checkNull);
-                arguments = arguments("hub", hub).add("object", object).add("hints", hints).add("trueValue", trueValue).add("falseValue", falseValue);
+                assert replacer.instanceOf instanceof InstanceOfDynamicNode;
+                InstanceOfDynamicNode instanceOf = (InstanceOfDynamicNode) replacer.instanceOf;
+                ValueNode trueValue = replacer.trueValue;
+                ValueNode falseValue = replacer.falseValue;
+                ValueNode object = instanceOf.object();
+                ValueNode mirror = instanceOf.mirror();
+                boolean checkNull = !object.stamp().nonNull();
+                Key key = new Key(instanceofDynamic).add("checkNull", checkNull);
+                Arguments arguments = arguments("mirror", mirror).add("object", object).add("trueValue", trueValue).add("falseValue", falseValue);
+                return new KeyAndArguments(key, arguments);
             }
-            return new KeyAndArguments(key, arguments);
         }
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/MonitorSnippets.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/MonitorSnippets.java	Wed Dec 19 10:01:08 2012 +0100
@@ -40,7 +40,6 @@
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.spi.*;
@@ -107,7 +106,7 @@
                 // The bias pattern is present in the object's mark word. Need to check
                 // whether the bias owner and the epoch are both still current.
                 Word hub = loadHub(object);
-                final Word prototypeMarkWord = loadWordFromWord(hub, prototypeMarkWordOffset());
+                final Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset());
                 final Word thread = thread();
                 final Word tmp = prototypeMarkWord.or(thread).xor(mark).and(~ageMaskInPlace());
                 trace(trace, "prototypeMarkWord: 0x%016lx\n", prototypeMarkWord.toLong());
@@ -293,7 +292,7 @@
         final Word lock = CurrentLockNode.currentLock();
 
         // Load displaced mark
-        final Word displacedMark = loadWordFromWord(lock, lockDisplacedMarkOffset());
+        final Word displacedMark = lock.readWord(lockDisplacedMarkOffset());
         trace(trace, "    displacedMark: 0x%016lx\n", displacedMark.toLong());
 
         if (displacedMark == Word.zero()) {
@@ -360,7 +359,7 @@
     private static void incCounter() {
         if (CHECK_BALANCED_MONITORS) {
             final Word counter = MonitorCounterNode.counter();
-            final int count = UnsafeLoadNode.load(counter, 0, 0, Kind.Int);
+            final int count = counter.readInt(0);
             DirectObjectStoreNode.storeInt(counter, 0, 0, count + 1);
         }
     }
@@ -368,7 +367,7 @@
     private static void decCounter() {
         if (CHECK_BALANCED_MONITORS) {
             final Word counter = MonitorCounterNode.counter();
-            final int count = UnsafeLoadNode.load(counter, 0, 0, Kind.Int);
+            final int count = counter.readInt(0);
             DirectObjectStoreNode.storeInt(counter, 0, 0, count - 1);
         }
     }
@@ -382,7 +381,7 @@
     @Snippet
     private static void checkCounter(String errMsg) {
         final Word counter = MonitorCounterNode.counter();
-        final int count = UnsafeLoadNode.load(counter, 0, 0, Kind.Int);
+        final int count = counter.readInt(0);
         if (count != 0) {
             vmError(errMsg, count);
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/NewObjectSnippets.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/NewObjectSnippets.java	Wed Dec 19 10:01:08 2012 +0100
@@ -59,8 +59,8 @@
     @Snippet
     public static Word allocate(@Parameter("size") int size) {
         Word thread = thread();
-        Word top = loadWordFromWord(thread, threadTlabTopOffset());
-        Word end = loadWordFromWord(thread, threadTlabEndOffset());
+        Word top = thread.readWord(threadTlabTopOffset());
+        Word end = thread.readWord(threadTlabEndOffset());
         Word newTop = top.plus(size);
         // this check might lead to problems if the TLAB is within 16GB of the address space end (checked in c++ code)
         if (newTop.belowOrEqual(end)) {
@@ -187,7 +187,7 @@
      * Formats some allocated memory with an object header zeroes out the rest.
      */
     private static void formatObject(Word hub, int size, Word memory, Word compileTimePrototypeMarkWord, boolean fillContents) {
-        Word prototypeMarkWord = useBiasedLocking() ? loadWordFromWord(hub, prototypeMarkWordOffset()) : compileTimePrototypeMarkWord;
+        Word prototypeMarkWord = useBiasedLocking() ? hub.readWord(prototypeMarkWordOffset()) : compileTimePrototypeMarkWord;
         storeWord(memory, 0, markOffset(), prototypeMarkWord);
         storeWord(memory, 0, hubOffset(), hub);
         if (fillContents) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectSnippets.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectSnippets.java	Wed Dec 19 10:01:08 2012 +0100
@@ -23,6 +23,7 @@
 package com.oracle.graal.hotspot.snippets;
 
 import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*;
+import static com.oracle.graal.nodes.extended.UnsafeCastNode.*;
 
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.snippets.*;
@@ -36,7 +37,7 @@
     @MethodSubstitution(isStatic = false)
     public static Class<?> getClass(final Object thisObj) {
         Word hub = loadHub(thisObj);
-        return (Class<?>) readFinalObject(hub, classMirrorOffset());
+        return unsafeCast(hub.readFinalObject(classMirrorOffset()), Class.class, true, true);
     }
 
     @MethodSubstitution(isStatic = false)
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ThreadSnippets.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ThreadSnippets.java	Wed Dec 19 10:01:08 2012 +0100
@@ -40,10 +40,10 @@
     @MethodSubstitution(isStatic = false)
     private static boolean isInterrupted(final Thread thisObject, boolean clearInterrupted) {
         Word rawThread = HotSpotCurrentRawThreadNode.get();
-        Thread thread = (Thread) loadObjectFromWord(rawThread, threadObjectOffset());
+        Thread thread = (Thread) rawThread.readObject(threadObjectOffset());
         if (thisObject == thread) {
-            Word osThread = loadWordFromWord(rawThread, osThreadOffset());
-            boolean interrupted = loadIntFromWord(osThread, osThreadInterruptedOffset()) != 0;
+            Word osThread = rawThread.readWord(osThreadOffset());
+            boolean interrupted = osThread.readInt(osThreadInterruptedOffset()) != 0;
             if (!interrupted || !clearInterrupted) {
                 return interrupted;
             }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java	Wed Dec 19 10:01:08 2012 +0100
@@ -70,7 +70,7 @@
                     @Parameter("length") int length,
                     @ConstantParameter("intArrayHub") Word intArrayHub,
                     @ConstantParameter("log") boolean log) {
-        int layoutHelper = loadIntFromWord(hub, layoutHelperOffset());
+        int layoutHelper = hub.readInt(layoutHelperOffset());
         int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask();
         int headerSize = (layoutHelper >> layoutHelperHeaderSizeShift()) & layoutHelperHeaderSizeMask();
         int elementKind = (layoutHelper >> layoutHelperElementTypeShift()) & layoutHelperElementTypeMask();
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java	Wed Dec 19 10:01:08 2012 +0100
@@ -68,12 +68,12 @@
                     @Parameter("hub") Word hub,
                     @ConstantParameter("intArrayHub") Word intArrayHub,
                     @ConstantParameter("log") boolean log) {
-        int sizeInBytes = loadIntFromWord(hub, klassInstanceSizeOffset());
+        int sizeInBytes = hub.readInt(klassInstanceSizeOffset());
         if (!forceSlowPath() && inlineContiguousAllocationSupported()) {
-            if (loadIntFromWord(hub, klassStateOffset()) == klassStateFullyInitialized()) {
+            if (hub.readInt(klassStateOffset()) == klassStateFullyInitialized()) {
                 Word memory = refillAllocate(intArrayHub, sizeInBytes, log);
                 if (memory != Word.zero()) {
-                    Word prototypeMarkWord = loadWordFromWord(hub, prototypeMarkWordOffset());
+                    Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset());
                     storeWord(memory, 0, markOffset(), prototypeMarkWord);
                     storeWord(memory, 0, hubOffset(), hub);
                     for (int offset = 2 * wordSize(); offset < sizeInBytes; offset += wordSize()) {
@@ -100,8 +100,8 @@
         int alignmentReserveInBytes = tlabAlignmentReserveInHeapWords() * wordSize();
 
         Word thread = thread();
-        Word top = loadWordFromWord(thread, threadTlabTopOffset());
-        Word end = loadWordFromWord(thread, threadTlabEndOffset());
+        Word top = thread.readWord(threadTlabTopOffset());
+        Word end = thread.readWord(threadTlabEndOffset());
 
         // calculate amount of free space
         Word tlabFreeSpaceInBytes = end.minus(top);
@@ -116,14 +116,14 @@
 
         // Retain TLAB and allocate object in shared space if
         // the amount free in the TLAB is too large to discard.
-        Word refillWasteLimit = loadWordFromWord(thread, tlabRefillWasteLimitOffset());
+        Word refillWasteLimit = thread.readWord(tlabRefillWasteLimitOffset());
         if (tlabFreeSpaceInWords.belowOrEqual(refillWasteLimit)) {
             if (tlabStats()) {
                 // increment number of refills
-                storeInt(thread, 0, tlabNumberOfRefillsOffset(), loadIntFromWord(thread, tlabNumberOfRefillsOffset()) + 1);
-                log(log, "thread: %p -- number_of_refills %d\n", thread.toLong(), loadIntFromWord(thread, tlabNumberOfRefillsOffset()));
+                storeInt(thread, 0, tlabNumberOfRefillsOffset(), thread.readInt(tlabNumberOfRefillsOffset()) + 1);
+                log(log, "thread: %p -- number_of_refills %d\n", thread.toLong(), thread.readInt(tlabNumberOfRefillsOffset()));
                 // accumulate wastage
-                Word wastage = loadWordFromWord(thread, tlabFastRefillWasteOffset()).plus(tlabFreeSpaceInWords);
+                Word wastage = thread.readWord(tlabFastRefillWasteOffset()).plus(tlabFreeSpaceInWords);
                 log(log, "thread: %p -- accumulated wastage %d\n", thread.toLong(), wastage.toLong());
                 storeWord(thread, 0, tlabFastRefillWasteOffset(), wastage);
             }
@@ -137,13 +137,13 @@
                 int length = ((alignmentReserveInBytes - headerSize) >>> 2) + tlabFreeSpaceInInts;
                 NewObjectSnippets.formatArray(intArrayHub, -1, length, headerSize, top, intArrayMarkWord, false);
 
-                Word allocated = loadWordFromWord(thread, threadAllocatedBytesOffset());
-                allocated = allocated.plus(top.minus(loadWordFromWord(thread, threadTlabStartOffset())));
+                Word allocated = thread.readWord(threadAllocatedBytesOffset());
+                allocated = allocated.plus(top.minus(thread.readWord(threadTlabStartOffset())));
                 storeWord(thread, 0, threadAllocatedBytesOffset(), allocated);
             }
 
             // refill the TLAB with an eden allocation
-            Word tlabRefillSizeInWords = loadWordFromWord(thread, threadTlabSizeOffset());
+            Word tlabRefillSizeInWords = thread.readWord(threadTlabSizeOffset());
             Word tlabRefillSizeInBytes = Word.fromLong(tlabRefillSizeInWords.toLong() * wordSize());
             // allocate new TLAB, address returned in top
             top = edenAllocate(tlabRefillSizeInBytes, log);
@@ -165,7 +165,7 @@
             log(log, "refillTLAB: retaining TLAB - newRefillWasteLimit=%p\n", newRefillWasteLimit.toLong());
 
             if (tlabStats()) {
-                storeInt(thread, 0, tlabSlowAllocationsOffset(), loadIntFromWord(thread, tlabSlowAllocationsOffset()) + 1);
+                storeInt(thread, 0, tlabSlowAllocationsOffset(), thread.readInt(tlabSlowAllocationsOffset()) + 1);
             }
 
             return edenAllocate(Word.fromInt(sizeInBytes), log);
@@ -184,13 +184,13 @@
         Word heapEndAddress = Word.fromLong(heapEndAddress());
 
         while (true) {
-            Word heapTop = loadWordFromWord(heapTopAddress, 0);
+            Word heapTop = heapTopAddress.readWord(0);
             Word newHeapTop = heapTop.plus(sizeInBytes);
             if (newHeapTop.belowOrEqual(heapTop)) {
                 return Word.zero();
             }
 
-            Word heapEnd = loadWordFromWord(heapEndAddress, 0);
+            Word heapEnd = heapEndAddress.readWord(0);
             if (newHeapTop.above(heapEnd)) {
                 return Word.zero();
             }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java	Wed Dec 19 10:01:08 2012 +0100
@@ -63,7 +63,7 @@
         int inFalseBranch = loop.nodesInLoopFrom(ifNode.falseSuccessor(), postDom).cardinality();
         int loopTotal = loop.size();
         int netDiff = loopTotal - (inTrueBranch + inFalseBranch);
-        double uncertainty = (0.5 - Math.abs(ifNode.probability(IfNode.TRUE_EDGE) - 0.5)) * 2;
+        double uncertainty = (0.5 - Math.abs(ifNode.probability(ifNode.trueSuccessor()) - 0.5)) * 2;
         int maxDiff = GraalOptions.LoopUnswitchMaxIncrease + (int) (GraalOptions.LoopUnswitchUncertaintyBoost * loop.loopBegin().loopFrequency() * uncertainty);
         Debug.log("shouldUnswitch(%s, %s) : delta=%d, max=%d, %.2f%% inside of if", loop, ifNode, netDiff, maxDiff, (double) (inTrueBranch + inFalseBranch) / loopTotal * 100);
         return netDiff <= maxDiff;
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java	Wed Dec 19 10:01:08 2012 +0100
@@ -96,7 +96,7 @@
         StructuredGraph graph = (StructuredGraph) ifNode.graph();
         BeginNode tempBegin = graph.add(new BeginNode());
         originalLoop.entryPoint().replaceAtPredecessor(tempBegin);
-        double takenProbability = ifNode.probability(ifNode.blockSuccessorIndex(ifNode.trueSuccessor()));
+        double takenProbability = ifNode.probability(ifNode.trueSuccessor());
         IfNode newIf = graph.add(new IfNode(ifNode.condition(), duplicateLoop.entryPoint(), originalLoop.entryPoint(), takenProbability, ifNode.leafGraphId()));
         tempBegin.setNext(newIf);
         ifNode.setCondition(graph.unique(ConstantNode.forBoolean(false, graph)));
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformLowPhase.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformLowPhase.java	Wed Dec 19 10:01:08 2012 +0100
@@ -53,7 +53,7 @@
                         if (LoopPolicies.shouldTryUnswitch(loop)) {
                             IfNode ifNode = LoopTransformations.findUnswitchableIf(loop);
                             if (ifNode != null && LoopPolicies.shouldUnswitch(loop, ifNode)) {
-                                Debug.log("Unswitching %s at %s [%f - %f]", loop, ifNode, ifNode.probability(0), ifNode.probability(1));
+                                Debug.log("Unswitching %s at %s [%f - %f]", loop, ifNode, ifNode.probability(ifNode.trueSuccessor()), ifNode.probability(ifNode.falseSuccessor()));
                                 LoopTransformations.unswitch(loop, ifNode);
                                 UNSWITCHED.increment();
                                 Debug.dump(graph, "After unswitch %s", loop);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ControlSplitNode.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ControlSplitNode.java	Wed Dec 19 10:01:08 2012 +0100
@@ -22,62 +22,16 @@
  */
 package com.oracle.graal.nodes;
 
-import java.util.*;
-
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.nodes.type.*;
 
 /**
  * The {@code ControlSplitNode} is a base class for all instructions that split the control flow (ie. have more than one successor).
  */
 public abstract class ControlSplitNode extends FixedNode {
-    @Successor private final NodeSuccessorList<BeginNode> blockSuccessors;
-    protected double[] branchProbability;
 
-    public BeginNode blockSuccessor(int index) {
-        return blockSuccessors.get(index);
-    }
-
-    public void setBlockSuccessor(int index, BeginNode x) {
-        blockSuccessors.set(index, x);
-    }
-
-    public int blockSuccessorCount() {
-        return blockSuccessors.size();
-    }
-
-    public ControlSplitNode(Stamp stamp, BeginNode[] blockSuccessors, double[] branchProbability) {
+    public ControlSplitNode(Stamp stamp) {
         super(stamp);
-        assert branchProbability.length == blockSuccessors.length;
-        this.blockSuccessors = new NodeSuccessorList<>(this, blockSuccessors);
-        this.branchProbability = branchProbability;
     }
 
-    public double probability(int successorIndex) {
-        return branchProbability[successorIndex];
-    }
-
-    public void setProbability(int successorIndex, double x) {
-        branchProbability[successorIndex] = x;
-    }
-
-    public NodeIterable<BeginNode> blockSuccessors() {
-        return blockSuccessors;
-    }
-
-    public int blockSuccessorIndex(BeginNode successor) {
-        int idx = blockSuccessors.indexOf(successor);
-        if (idx < 0) {
-            throw new IllegalArgumentException();
-        }
-        return idx;
-    }
-
-    @Override
-    public ControlSplitNode clone(Graph into) {
-        ControlSplitNode csn = (ControlSplitNode) super.clone(into);
-        csn.branchProbability = Arrays.copyOf(branchProbability, branchProbability.length);
-        return csn;
-    }
+    public abstract double probability(BeginNode successor);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Wed Dec 19 10:01:08 2012 +0100
@@ -298,10 +298,6 @@
         return values.get(localsSize + stackSize + i);
     }
 
-    public MergeNode block() {
-        return usages().filter(MergeNode.class).first();
-    }
-
     public NodeIterable<FrameState> innerFrameStates() {
         return usages().filter(FrameState.class);
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Wed Dec 19 10:01:08 2012 +0100
@@ -38,11 +38,11 @@
  * comparison.
  */
 public final class IfNode extends ControlSplitNode implements Simplifiable, LIRLowerable, Negatable {
-    public static final int TRUE_EDGE = 0;
-    public static final int FALSE_EDGE = 1;
     private final long leafGraphId;
-
+    @Successor private BeginNode trueSuccessor;
+    @Successor private BeginNode falseSuccessor;
     @Input private BooleanNode condition;
+    private double takenProbability;
 
     public BooleanNode condition() {
         return condition;
@@ -54,9 +54,17 @@
     }
 
     public IfNode(BooleanNode condition, FixedNode trueSuccessor, FixedNode falseSuccessor, double takenProbability, long leafGraphId) {
-        super(StampFactory.forVoid(), new BeginNode[] {BeginNode.begin(trueSuccessor), BeginNode.begin(falseSuccessor)}, new double[] {takenProbability, 1 - takenProbability});
+        this(condition, BeginNode.begin(trueSuccessor), BeginNode.begin(falseSuccessor), takenProbability, leafGraphId);
+    }
+
+    public IfNode(BooleanNode condition, BeginNode trueSuccessor, BeginNode falseSuccessor, double takenProbability, long leafGraphId) {
+        super(StampFactory.forVoid());
         this.condition = condition;
+        this.falseSuccessor = falseSuccessor;
+        this.takenProbability = takenProbability;
         this.leafGraphId = leafGraphId;
+        this.trueSuccessor = trueSuccessor;
+
     }
 
     public long leafGraphId() {
@@ -69,7 +77,7 @@
      * @return the true successor
      */
     public BeginNode trueSuccessor() {
-        return blockSuccessor(0);
+        return trueSuccessor;
     }
 
     /**
@@ -78,15 +86,17 @@
      * @return the false successor
      */
     public BeginNode falseSuccessor() {
-        return blockSuccessor(1);
+        return falseSuccessor;
     }
 
     public void setTrueSuccessor(BeginNode node) {
-        setBlockSuccessor(0, node);
+        updatePredecessor(trueSuccessor, node);
+        trueSuccessor = node;
     }
 
     public void setFalseSuccessor(BeginNode node) {
-        setBlockSuccessor(1, node);
+        updatePredecessor(falseSuccessor, node);
+        falseSuccessor = node;
     }
 
     /**
@@ -96,7 +106,24 @@
      * @return the corresponding successor
      */
     public BeginNode successor(boolean istrue) {
-        return blockSuccessor(istrue ? 0 : 1);
+        return istrue ? trueSuccessor : falseSuccessor;
+    }
+
+    @Override
+    public Negatable negate() {
+        BeginNode trueSucc = trueSuccessor();
+        BeginNode falseSucc = falseSuccessor();
+        setTrueSuccessor(null);
+        setFalseSuccessor(null);
+        setTrueSuccessor(falseSucc);
+        setFalseSuccessor(trueSucc);
+        takenProbability = 1 - takenProbability;
+        return this;
+    }
+
+    @Override
+    public double probability(BeginNode successor) {
+        return successor == trueSuccessor ? takenProbability : 1 - takenProbability;
     }
 
     @Override
@@ -119,11 +146,11 @@
             if (c.asConstant().asBoolean()) {
                 tool.deleteBranch(falseSuccessor());
                 tool.addToWorkList(trueSuccessor());
-                ((StructuredGraph) graph()).removeSplit(this, TRUE_EDGE);
+                ((StructuredGraph) graph()).removeSplit(this, trueSuccessor());
             } else {
                 tool.deleteBranch(trueSuccessor());
                 tool.addToWorkList(falseSuccessor());
-                ((StructuredGraph) graph()).removeSplit(this, FALSE_EDGE);
+                ((StructuredGraph) graph()).removeSplit(this, falseSuccessor());
             }
         } else if (trueSuccessor().guards().isEmpty() && falseSuccessor().guards().isEmpty()) {
             if (removeOrMaterializeIf(tool)) {
@@ -154,7 +181,7 @@
                     PhiNode singlePhi = phis.next();
                     if (!phis.hasNext()) {
                         // one phi at the merge of an otherwise empty if construct: try to convert into a MaterializeNode
-                        boolean inverted = trueEnd == merge.forwardEndAt(FALSE_EDGE);
+                        boolean inverted = trueEnd == merge.forwardEndAt(1);
                         ValueNode trueValue = singlePhi.valueAt(inverted ? 1 : 0);
                         ValueNode falseValue = singlePhi.valueAt(inverted ? 0 : 1);
                         if (trueValue.kind() != falseValue.kind()) {
@@ -276,8 +303,8 @@
         List<EndNode> trueEnds = new ArrayList<>(mergePredecessors.size());
         Map<EndNode, ValueNode> phiValues = new HashMap<>(mergePredecessors.size());
 
-        BeginNode falseSuccessor = falseSuccessor();
-        BeginNode trueSuccessor = trueSuccessor();
+        BeginNode oldFalseSuccessor = falseSuccessor();
+        BeginNode oldTrueSuccessor = trueSuccessor();
 
         setFalseSuccessor(null);
         setTrueSuccessor(null);
@@ -294,8 +321,8 @@
         }
         assert !ends.hasNext();
 
-        connectEnds(falseEnds, phiValues, falseSuccessor, merge, tool);
-        connectEnds(trueEnds, phiValues, trueSuccessor, merge, tool);
+        connectEnds(falseEnds, phiValues, oldFalseSuccessor, merge, tool);
+        connectEnds(trueEnds, phiValues, oldTrueSuccessor, merge, tool);
 
         GraphUtil.killCFG(merge);
 
@@ -382,20 +409,20 @@
     }
 
     private void removeEmptyIf(SimplifierTool tool) {
-        BeginNode trueSuccessor = trueSuccessor();
-        BeginNode falseSuccessor = falseSuccessor();
-        assert trueSuccessor.next() instanceof EndNode && falseSuccessor.next() instanceof EndNode;
+        BeginNode originalTrueSuccessor = trueSuccessor();
+        BeginNode originalFalseSuccessor = falseSuccessor();
+        assert originalTrueSuccessor.next() instanceof EndNode && originalFalseSuccessor.next() instanceof EndNode;
 
-        EndNode trueEnd = (EndNode) trueSuccessor.next();
-        EndNode falseEnd = (EndNode) falseSuccessor.next();
+        EndNode trueEnd = (EndNode) originalTrueSuccessor.next();
+        EndNode falseEnd = (EndNode) originalFalseSuccessor.next();
         assert trueEnd.merge() == falseEnd.merge();
 
         FixedWithNextNode pred = (FixedWithNextNode) predecessor();
         MergeNode merge = trueEnd.merge();
         merge.prepareDelete(pred);
         assert merge.usages().isEmpty();
-        trueSuccessor.prepareDelete();
-        falseSuccessor.prepareDelete();
+        originalTrueSuccessor.prepareDelete();
+        originalFalseSuccessor.prepareDelete();
 
         FixedNode next = merge.next();
         merge.setNext(null);
@@ -403,25 +430,11 @@
         setFalseSuccessor(null);
         pred.setNext(next);
         safeDelete();
-        trueSuccessor.safeDelete();
-        falseSuccessor.safeDelete();
+        originalTrueSuccessor.safeDelete();
+        originalFalseSuccessor.safeDelete();
         merge.safeDelete();
         trueEnd.safeDelete();
         falseEnd.safeDelete();
         tool.addToWorkList(next);
     }
-
-    @Override
-    public Negatable negate() {
-        BeginNode trueSucc = trueSuccessor();
-        BeginNode falseSucc = falseSuccessor();
-        setTrueSuccessor(null);
-        setFalseSuccessor(null);
-        setTrueSuccessor(falseSucc);
-        setFalseSuccessor(trueSucc);
-        double prop = branchProbability[TRUE_EDGE];
-        branchProbability[TRUE_EDGE] = branchProbability[FALSE_EDGE];
-        branchProbability[FALSE_EDGE] = prop;
-        return this;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Wed Dec 19 10:01:08 2012 +0100
@@ -33,9 +33,8 @@
 
 @NodeInfo(nameTemplate = "Invoke!#{p#targetMethod/s}")
 public class InvokeWithExceptionNode extends ControlSplitNode implements Node.IterableNodeType, Invoke, MemoryCheckpoint, LIRLowerable {
-    public static final int NORMAL_EDGE = 0;
-    public static final int EXCEPTION_EDGE = 1;
-
+    @Successor private BeginNode next;
+    @Successor private DispatchBeginNode exceptionEdge;
     @Input private final CallTargetNode callTarget;
     @Input private FrameState stateAfter;
     private final int bci;
@@ -44,7 +43,8 @@
     private final long leafGraphId;
 
     public InvokeWithExceptionNode(CallTargetNode callTarget, DispatchBeginNode exceptionEdge, int bci, long leafGraphId) {
-        super(callTarget.returnStamp(), new BeginNode[]{null, exceptionEdge}, new double[]{1.0, 0.0});
+        super(callTarget.returnStamp());
+        this.exceptionEdge = exceptionEdge;
         this.bci = bci;
         this.callTarget = callTarget;
         this.leafGraphId = leafGraphId;
@@ -53,19 +53,21 @@
     }
 
     public DispatchBeginNode exceptionEdge() {
-        return (DispatchBeginNode) blockSuccessor(EXCEPTION_EDGE);
+        return exceptionEdge;
     }
 
-    public void setExceptionEdge(BeginNode x) {
-        setBlockSuccessor(EXCEPTION_EDGE, x);
+    public void setExceptionEdge(DispatchBeginNode x) {
+        updatePredecessor(exceptionEdge, x);
+        exceptionEdge = x;
     }
 
     public BeginNode next() {
-        return blockSuccessor(NORMAL_EDGE);
+        return next;
     }
 
     public void setNext(BeginNode x) {
-        setBlockSuccessor(NORMAL_EDGE, x);
+        updatePredecessor(next, x);
+        next = x;
     }
 
     public CallTargetNode callTarget() {
@@ -170,9 +172,9 @@
     }
 
     public void killExceptionEdge() {
-        BeginNode exceptionEdge = exceptionEdge();
+        BeginNode edge = exceptionEdge();
         setExceptionEdge(null);
-        GraphUtil.killCFG(exceptionEdge);
+        GraphUtil.killCFG(edge);
     }
 
     @Override
@@ -187,18 +189,24 @@
         }
         if (node == null) {
             assert kind() == Kind.Void && usages().isEmpty();
-            ((StructuredGraph) graph()).removeSplit(this, NORMAL_EDGE);
+            ((StructuredGraph) graph()).removeSplit(this, next());
         } else if (node instanceof DeoptimizeNode) {
             this.replaceAtPredecessor(node);
             this.replaceAtUsages(null);
             GraphUtil.killCFG(this);
             return;
         } else {
-            ((StructuredGraph) graph()).replaceSplit(this, node, NORMAL_EDGE);
+            ((StructuredGraph) graph()).replaceSplit(this, node, next());
         }
         call.safeDelete();
         if (state.usages().isEmpty()) {
             state.safeDelete();
         }
     }
+
+    private static final double EXCEPTION_PROBA = 1e-5;
+    @Override
+    public double probability(BeginNode successor) {
+        return successor == next ? 1 - EXCEPTION_PROBA : EXCEPTION_PROBA;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MaterializeNode.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MaterializeNode.java	Wed Dec 19 10:01:08 2012 +0100
@@ -26,6 +26,7 @@
 
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.java.*;
 
 public final class MaterializeNode extends ConditionalNode {
 
@@ -37,6 +38,10 @@
         super(condition, trueValue, falseValue);
     }
 
+    private MaterializeNode(ValueNode type, ValueNode object) {
+        super(type.graph().add(new InstanceOfDynamicNode(type, object)), ConstantNode.forInt(1, type.graph()), ConstantNode.forInt(0, type.graph()));
+    }
+
     public static MaterializeNode create(BooleanNode condition, ValueNode trueValue, ValueNode falseValue) {
         Graph graph = condition.graph();
         MaterializeNode result = new MaterializeNode(condition, trueValue, falseValue);
@@ -53,4 +58,7 @@
 
     @NodeIntrinsic
     public static native boolean materialize(@ConstantNodeParameter Condition condition, long x, long y);
+
+    @NodeIntrinsic
+    public static native boolean isInstance(Class mirror, Object object);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Wed Dec 19 10:01:08 2012 +0100
@@ -241,39 +241,34 @@
         node.safeDelete();
     }
 
-    public void removeSplit(ControlSplitNode node, int survivingSuccessor) {
+    public void removeSplit(ControlSplitNode node, BeginNode survivingSuccessor) {
         assert node != null;
         assert node.usages().isEmpty();
-        assert survivingSuccessor >= 0 && survivingSuccessor < node.blockSuccessorCount() : "invalid surviving successor " + survivingSuccessor + " for " + node;
-        BeginNode begin = node.blockSuccessor(survivingSuccessor);
-        for (int i = 0; i < node.blockSuccessorCount(); i++) {
-            node.setBlockSuccessor(i, null);
-        }
-        node.replaceAtPredecessor(begin);
+        assert survivingSuccessor != null;
+        node.clearSuccessors();
+        node.replaceAtPredecessor(survivingSuccessor);
         node.safeDelete();
     }
 
-    public void removeSplitPropagate(ControlSplitNode node, int survivingSuccessor) {
+    public void removeSplitPropagate(ControlSplitNode node, BeginNode survivingSuccessor) {
         assert node != null;
         assert node.usages().isEmpty();
-        assert survivingSuccessor >= 0 && survivingSuccessor < node.blockSuccessorCount() : "invalid surviving successor " + survivingSuccessor + " for " + node;
-        BeginNode begin = node.blockSuccessor(survivingSuccessor);
-        for (int i = 0; i < node.blockSuccessorCount(); i++) {
-            BeginNode successor = node.blockSuccessor(i);
-            node.setBlockSuccessor(i, null);
-            if (successor != null && successor != begin && successor.isAlive()) {
-                GraphUtil.killCFG(successor);
+        assert survivingSuccessor != null;
+        for (Node successor : node.successors().snapshot()) {
+            successor.replaceAtPredecessor(null);
+            if (successor != null && successor != survivingSuccessor && successor.isAlive()) {
+                GraphUtil.killCFG((BeginNode) successor);
             }
         }
-        if (begin.isAlive()) {
-            node.replaceAtPredecessor(begin);
+        if (survivingSuccessor.isAlive()) {
+            node.replaceAtPredecessor(survivingSuccessor);
             node.safeDelete();
         } else {
-            assert node.isDeleted() : node + " " + begin;
+            assert node.isDeleted() : node + " " + survivingSuccessor;
         }
     }
 
-    public void replaceSplit(ControlSplitNode node, Node replacement, int survivingSuccessor) {
+    public void replaceSplit(ControlSplitNode node, Node replacement, BeginNode survivingSuccessor) {
         if (replacement instanceof FixedWithNextNode) {
             replaceSplitWithFixed(node, (FixedWithNextNode) replacement, survivingSuccessor);
         } else {
@@ -283,25 +278,19 @@
         }
     }
 
-    public void replaceSplitWithFixed(ControlSplitNode node, FixedWithNextNode replacement, int survivingSuccessor) {
+    public void replaceSplitWithFixed(ControlSplitNode node, FixedWithNextNode replacement, BeginNode survivingSuccessor) {
         assert node != null && replacement != null && node.isAlive() && replacement.isAlive() : "cannot replace " + node + " with " + replacement;
-        assert survivingSuccessor >= 0 && survivingSuccessor < node.blockSuccessorCount() : "invalid surviving successor " + survivingSuccessor + " for " + node;
-        BeginNode begin = node.blockSuccessor(survivingSuccessor);
-        for (int i = 0; i < node.blockSuccessorCount(); i++) {
-            node.setBlockSuccessor(i, null);
-        }
-        replacement.setNext(begin);
+        assert survivingSuccessor != null;
+        node.clearSuccessors();
+        replacement.setNext(survivingSuccessor);
         node.replaceAndDelete(replacement);
     }
 
-    public void replaceSplitWithFloating(ControlSplitNode node, FloatingNode replacement, int survivingSuccessor) {
+    public void replaceSplitWithFloating(ControlSplitNode node, FloatingNode replacement, BeginNode survivingSuccessor) {
         assert node != null && replacement != null && node.isAlive() && replacement.isAlive() : "cannot replace " + node + " with " + replacement;
-        assert survivingSuccessor >= 0 && survivingSuccessor < node.blockSuccessorCount() : "invalid surviving successor " + survivingSuccessor + " for " + node;
-        BeginNode begin = node.blockSuccessor(survivingSuccessor);
-        for (int i = 0; i < node.blockSuccessorCount(); i++) {
-            node.setBlockSuccessor(i, null);
-        }
-        node.replaceAtPredecessor(begin);
+        assert survivingSuccessor != null;
+        node.clearSuccessors();
+        node.replaceAtPredecessor(survivingSuccessor);
         node.replaceAtUsages(replacement);
         node.safeDelete();
     }
@@ -322,7 +311,7 @@
     public void addBeforeFixed(FixedNode node, FixedWithNextNode newNode) {
         assert node != null && newNode != null && node.isAlive() && newNode.isAlive() : "cannot add " + newNode + " before " + node;
         assert node.predecessor() != null && node.predecessor() instanceof FixedWithNextNode : "cannot add " + newNode + " before " + node;
-        assert newNode.next() == null;
+        assert newNode.next() == null : newNode;
         newNode.setProbability(node.probability());
         FixedWithNextNode pred = (FixedWithNextNode) node.predecessor();
         pred.setNext(newNode);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IntegerSwitchNode.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IntegerSwitchNode.java	Wed Dec 19 10:01:08 2012 +0100
@@ -93,7 +93,7 @@
     public void simplify(SimplifierTool tool) {
         if (blockSuccessorCount() == 1) {
             tool.addToWorkList(defaultSuccessor());
-            ((StructuredGraph) graph()).removeSplitPropagate(this, defaultSuccessorIndex());
+            ((StructuredGraph) graph()).removeSplitPropagate(this, defaultSuccessor());
         } else if (value() instanceof ConstantNode) {
             int constant = value().asConstant().asInt();
 
@@ -109,7 +109,7 @@
                 }
             }
             tool.addToWorkList(blockSuccessor(survivingEdge));
-            ((StructuredGraph) graph()).removeSplitPropagate(this, survivingEdge);
+            ((StructuredGraph) graph()).removeSplit(this, blockSuccessor(survivingEdge));
         } else if (value() != null) {
             IntegerStamp stamp = value().integerStamp();
             if (!stamp.isUnrestricted()) {
@@ -121,7 +121,7 @@
                 }
                 if (validKeys == 0) {
                     tool.addToWorkList(defaultSuccessor());
-                    ((StructuredGraph) graph()).removeSplitPropagate(this, defaultSuccessorIndex());
+                    ((StructuredGraph) graph()).removeSplitPropagate(this, defaultSuccessor());
                 } else if (validKeys != keys.length) {
                     ArrayList<BeginNode> newSuccessors = new ArrayList<>(blockSuccessorCount());
                     int[] newKeys = new int[validKeys];
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SwitchNode.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SwitchNode.java	Wed Dec 19 10:01:08 2012 +0100
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.nodes.extended;
 
+import java.util.*;
+
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
@@ -31,10 +33,11 @@
  * The {@code SwitchNode} class is the base of both lookup and table switches.
  */
 public abstract class SwitchNode extends ControlSplitNode {
-
+    @Successor protected final NodeSuccessorList<BeginNode> successors;
+    protected double[] successorProbabilities;
     @Input private ValueNode value;
-    private final double[] keyProbabilities;
-    private final int[] keySuccessors;
+    private double[] keyProbabilities;
+    private int[] keySuccessors;
 
     public ValueNode value() {
         return value;
@@ -46,13 +49,26 @@
      * @param successors the list of successors of this switch
      */
     public SwitchNode(ValueNode value, BeginNode[] successors, double[] successorProbabilities, int[] keySuccessors, double[] keyProbabilities) {
-        super(StampFactory.forVoid(), successors, successorProbabilities);
+        super(StampFactory.forVoid());
+        this.successorProbabilities = successorProbabilities;
         assert keySuccessors.length == keyProbabilities.length;
+        this.successors = new NodeSuccessorList<>(this, successors);
         this.value = value;
         this.keySuccessors = keySuccessors;
         this.keyProbabilities = keyProbabilities;
     }
 
+    @Override
+    public double probability(BeginNode successor) {
+        double sum = 0;
+        for (int i = 0; i < successors.size(); i++) {
+            if (successors.get(i) == successor) {
+                sum += successorProbabilities[i];
+            }
+        }
+        return sum;
+    }
+
     /**
      * The number of distinct keys in this switch.
      */
@@ -74,7 +90,7 @@
      * Returns the successor for the key at the given index.
      */
     public BeginNode keySuccessor(int i) {
-        return blockSuccessor(keySuccessors[i]);
+        return successors.get(keySuccessors[i]);
     }
 
     /**
@@ -91,6 +107,18 @@
         return keySuccessors[keySuccessors.length - 1];
     }
 
+    public BeginNode blockSuccessor(int i) {
+        return successors.get(i);
+    }
+
+    public void setBlockSuccessor(int i, BeginNode s) {
+        successors.set(i, s);
+    }
+
+    public int blockSuccessorCount() {
+        return successors.count();
+    }
+
     /**
      * Gets the successor corresponding to the default (fall through) case.
      * @return the default successor
@@ -99,7 +127,7 @@
         if (defaultSuccessorIndex() == -1) {
             throw new GraalInternalError("unexpected");
         }
-        return defaultSuccessorIndex() == -1 ? null : blockSuccessor(defaultSuccessorIndex());
+        return defaultSuccessorIndex() == -1 ? null : successors.get(defaultSuccessorIndex());
     }
 
     /**
@@ -113,4 +141,13 @@
         }
         return probability;
     }
+
+    @Override
+    public SwitchNode clone(Graph into) {
+        SwitchNode newSwitch = (SwitchNode) super.clone(into);
+        newSwitch.successorProbabilities = Arrays.copyOf(successorProbabilities, successorProbabilities.length);
+        newSwitch.keyProbabilities = Arrays.copyOf(keyProbabilities, keyProbabilities.length);
+        newSwitch.keySuccessors = Arrays.copyOf(keySuccessors, keySuccessors.length);
+        return newSwitch;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java	Wed Dec 19 10:01:08 2012 +0100
@@ -99,7 +99,4 @@
 
     @NodeIntrinsic
     public static native <T> T load(Object object, @ConstantNodeParameter int displacement, long offset, @ConstantNodeParameter Kind kind);
-
-    @NodeIntrinsic
-    public static native Object loadObject(Object object, @ConstantNodeParameter int displacement, long offset, @ConstantNodeParameter boolean nonNull);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java	Wed Dec 19 10:01:08 2012 +0100
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2009, 2011, 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.graal.nodes.java;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+
+/**
+ * The {@code InstanceOfDynamicNode} represents a type check where the type being checked
+ * is not known at compile time.
+ * This is used, for instance, to intrinsify {@link Class#isInstance(Object)}.
+ */
+public final class InstanceOfDynamicNode extends BooleanNode implements Canonicalizable, Lowerable {
+
+    @Input private ValueNode object;
+    @Input private ValueNode mirror;
+
+    /**
+     * Constructs a new InstanceOfNode.
+     *
+     * @param mirror the {@link Class} value representing the target target type of the instanceof check
+     * @param object the object being tested by the instanceof
+     */
+    public InstanceOfDynamicNode(ValueNode mirror, ValueNode object) {
+        super(StampFactory.condition());
+        this.mirror = mirror;
+        this.object = object;
+        assert mirror.kind() == Kind.Object;
+        assert mirror.objectStamp().isExactType();
+        assert mirror.objectStamp().type().getName().equals("Ljava/lang/Class;");
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getRuntime().lower(this, tool);
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool) {
+        assert object() != null : this;
+        if (mirror().isConstant()) {
+            Class clazz = (Class) mirror().asConstant().asObject();
+            ResolvedJavaType t = tool.runtime().lookupJavaType(clazz);
+            return graph().unique(new InstanceOfNode(t, object(), null));
+        }
+        return this;
+    }
+
+    public ValueNode object() {
+        return object;
+    }
+
+    public ValueNode mirror() {
+        return mirror;
+    }
+
+    @Override
+    public boolean verify() {
+        for (Node usage : usages()) {
+            assertTrue(usage instanceof IfNode || usage instanceof ConditionalNode, "unsupported usage: ", usage);
+        }
+        return super.verify();
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java	Wed Dec 19 10:01:08 2012 +0100
@@ -33,7 +33,7 @@
 /**
  * The {@code InstanceOfNode} represents an instanceof test.
  */
-public final class InstanceOfNode extends BooleanNode implements Canonicalizable, Lowerable, LIRLowerable, Virtualizable {
+public final class InstanceOfNode extends BooleanNode implements Canonicalizable, Lowerable, Virtualizable {
 
     @Input private ValueNode object;
     private final ResolvedJavaType type;
@@ -54,10 +54,6 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool gen) {
-    }
-
-    @Override
     public void lower(LoweringTool tool) {
         tool.getRuntime().lower(this, tool);
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeSwitchNode.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeSwitchNode.java	Wed Dec 19 10:01:08 2012 +0100
@@ -91,7 +91,7 @@
                 }
             }
             tool.addToWorkList(blockSuccessor(survivingEdge));
-            ((StructuredGraph) graph()).removeSplitPropagate(this, survivingEdge);
+            ((StructuredGraph) graph()).removeSplit(this, blockSuccessor(survivingEdge));
         }
         if (value() instanceof LoadHubNode) {
             ObjectStamp stamp = ((LoadHubNode) value()).object().objectStamp();
@@ -104,7 +104,7 @@
                 }
                 if (validKeys == 0) {
                     tool.addToWorkList(defaultSuccessor());
-                    ((StructuredGraph) graph()).removeSplitPropagate(this, defaultSuccessorIndex());
+                    ((StructuredGraph) graph()).removeSplitPropagate(this, defaultSuccessor());
                 } else if (validKeys != keys.length) {
                     ArrayList<BeginNode> newSuccessors = new ArrayList<>(blockSuccessorCount());
                     ResolvedJavaType[] newKeys = new ResolvedJavaType[validKeys];
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/ComputeImmediateDominator.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/ComputeImmediateDominator.java	Wed Dec 19 10:01:08 2012 +0100
@@ -104,7 +104,7 @@
             //TTY.println("  Already explored, propagate update");
             propagateUpdate(csInfo);
         } else {
-            if (csInfo.parentCount() == cs.blockSuccessorCount()) { // all paths leading to this CS have been explored
+            if (csInfo.parentCount() == cs.successors().count()) { // all paths leading to this CS have been explored
                 //TTY.println("  All parents explored, Enqueue");
                 toExplore.add(next);
                 speculativeExplore.remove(next);
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ComputeProbabilityPhase.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ComputeProbabilityPhase.java	Wed Dec 19 10:01:08 2012 +0100
@@ -244,7 +244,7 @@
         }
 
         @Override
-        public void afterSplit(FixedNode node) {
+        public void afterSplit(BeginNode node) {
             assert node.predecessor() != null;
             Node pred = node.predecessor();
             if (pred instanceof Invoke) {
@@ -255,13 +255,7 @@
             } else {
                 assert pred instanceof ControlSplitNode;
                 ControlSplitNode x = (ControlSplitNode) pred;
-                double sum = 0;
-                for (int i = 0; i < x.blockSuccessorCount(); i++) {
-                    if (x.blockSuccessor(i) == node) {
-                        sum += x.probability(i);
-                    }
-                }
-                probability *= sum;
+                probability *= x.probability(node);
             }
         }
     }
@@ -316,7 +310,7 @@
         }
 
         @Override
-        public void afterSplit(FixedNode node) {
+        public void afterSplit(BeginNode node) {
             // nothing to do...
         }
     }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java	Wed Dec 19 10:01:08 2012 +0100
@@ -214,7 +214,7 @@
         }
 
         @Override
-        public void afterSplit(FixedNode node) {
+        public void afterSplit(BeginNode node) {
         }
 
         @Override
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertUnreachedToGuardPhase.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertUnreachedToGuardPhase.java	Wed Dec 19 10:01:08 2012 +0100
@@ -49,11 +49,11 @@
                 BeginNode insertGuard = null;
                 BeginNode delete = null;
                 boolean inverted = false;
-                if (ifNode.probability(IfNode.TRUE_EDGE) == 0) {
+                if (ifNode.probability(ifNode.trueSuccessor()) == 0) {
                     insertGuard = ifNode.falseSuccessor();
                     delete = ifNode.trueSuccessor();
                     inverted = true;
-                } else if (ifNode.probability(IfNode.FALSE_EDGE) == 0) {
+                } else if (ifNode.probability(ifNode.falseSuccessor()) == 0) {
                     insertGuard = ifNode.trueSuccessor();
                     delete = ifNode.falseSuccessor();
                 }
@@ -61,7 +61,7 @@
                     GuardNode guard = graph.unique(new GuardNode(ifNode.condition(), BeginNode.prevBegin(ifNode), DeoptimizationReason.UnreachedCode, DeoptimizationAction.InvalidateReprofile, inverted, ifNode.leafGraphId()));
                     graph.addBeforeFixed(ifNode, graph.add(new ValueAnchorNode(guard)));
                     GraphUtil.killCFG(delete);
-                    graph.removeSplit(ifNode, inverted ? IfNode.FALSE_EDGE : IfNode.TRUE_EDGE);
+                    graph.removeSplit(ifNode, inverted ? ifNode.falseSuccessor() : ifNode.trueSuccessor());
                 }
             }
         }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CullFrameStatesPhase.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CullFrameStatesPhase.java	Wed Dec 19 10:01:08 2012 +0100
@@ -87,7 +87,7 @@
         }
 
         @Override
-        public void afterSplit(FixedNode node) {
+        public void afterSplit(BeginNode node) {
         }
 
         @Override
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/EliminatePartiallyRedundantGuardsPhase.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/EliminatePartiallyRedundantGuardsPhase.java	Wed Dec 19 10:01:08 2012 +0100
@@ -149,7 +149,8 @@
 
     private static boolean eliminateAtControlSplit(ControlSplitNode controlSplit) {
         Map<Condition, Collection<GuardNode>> conditionToGuard = new HashMap<>();
-        for (BeginNode begin : controlSplit.blockSuccessors()) {
+        for (Node successor : controlSplit.successors()) {
+            BeginNode begin = (BeginNode) successor;
             for (GuardNode guard : begin.guards()) {
                 if (guard.dependencies().size() != 1) {
                     continue;
@@ -196,7 +197,7 @@
             if (leafGraphId < 0) {
                 continue;
             }
-            if (begins.size() == controlSplit.blockSuccessors().count()) {
+            if (begins.size() == controlSplit.successors().count()) {
                 hits = true;
                 Condition condition = entry.getKey();
                 GuardNode newGuard = controlSplit.graph().unique(new GuardNode(condition.conditionNode, BeginNode.prevBegin(controlSplit), reason, action, condition.negated, leafGraphId));
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java	Wed Dec 19 10:01:08 2012 +0100
@@ -157,7 +157,7 @@
         }
 
         @Override
-        public void afterSplit(FixedNode node) {
+        public void afterSplit(BeginNode node) {
             // nothing
         }
 
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Wed Dec 19 10:01:08 2012 +0100
@@ -576,11 +576,11 @@
                 assert exceptionMerge != null && exceptionObjectPhi != null;
 
                 InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke;
-                BeginNode exceptionEdge = invokeWithException.exceptionEdge();
+                DispatchBeginNode exceptionEdge = invokeWithException.exceptionEdge();
                 ExceptionObjectNode exceptionObject = (ExceptionObjectNode) exceptionEdge.next();
                 FrameState stateAfterException = exceptionObject.stateAfter();
 
-                BeginNode newExceptionEdge = (BeginNode) exceptionEdge.copyWithInputs();
+                DispatchBeginNode newExceptionEdge = (DispatchBeginNode) exceptionEdge.copyWithInputs();
                 ExceptionObjectNode newExceptionObject = (ExceptionObjectNode) exceptionObject.copyWithInputs();
                 // set new state (pop old exception object, push new one)
                 newExceptionObject.setStateAfter(stateAfterException.duplicateModified(stateAfterException.bci, stateAfterException.rethrowException(), Kind.Object, newExceptionObject));
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/MergeableState.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/MergeableState.java	Wed Dec 19 10:01:08 2012 +0100
@@ -31,5 +31,5 @@
     boolean merge(MergeNode merge, List<T> withStates);
     void loopBegin(LoopBeginNode loopBegin);
     void loopEnds(LoopBeginNode loopBegin, List<T> loopEndStates);
-    void afterSplit(FixedNode node);
+    void afterSplit(BeginNode node);
 }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/PostOrderNodeIterator.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/PostOrderNodeIterator.java	Wed Dec 19 10:01:08 2012 +0100
@@ -38,7 +38,7 @@
 public abstract class PostOrderNodeIterator<T extends MergeableState<T>> {
 
     private final NodeBitMap visitedEnds;
-    private final Deque<FixedNode> nodeQueue;
+    private final Deque<BeginNode> nodeQueue;
     private final IdentityHashMap<FixedNode, T> nodeStates;
     private final FixedNode start;
 
@@ -109,13 +109,13 @@
             for (Node node : successors) {
                 if (node != null) {
                     nodeStates.put((FixedNode) node.predecessor(), state);
-                    nodeQueue.addFirst((FixedNode) node);
+                    nodeQueue.addFirst((BeginNode) node);
                 }
             }
         } else {
             for (Node node : x.successors()) {
                 if (node != null) {
-                    nodeQueue.addFirst((FixedNode) node);
+                    nodeQueue.addFirst((BeginNode) node);
                 }
             }
         }
@@ -124,7 +124,7 @@
     private FixedNode nextQueuedNode() {
         int maxIterations = nodeQueue.size();
         while (maxIterations-- > 0) {
-            FixedNode node = nodeQueue.removeFirst();
+            BeginNode node = nodeQueue.removeFirst();
             if (node instanceof MergeNode) {
                 MergeNode merge = (MergeNode) node;
                 state = nodeStates.get(merge.forwardEndAt(0)).clone();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/InstanceOfDynamicTest.java	Wed Dec 19 10:01:08 2012 +0100
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2011, 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.graal.snippets;
+
+import org.junit.*;
+
+import com.oracle.graal.compiler.test.*;
+import com.oracle.graal.nodes.java.*;
+
+/**
+ * Tests for {@link InstanceOfDynamicNode}.
+ */
+public class InstanceOfDynamicTest extends GraalCompilerTest {
+
+    public static int id(int value) {
+        return value;
+    }
+
+    @Test
+    public void test100() {
+        final Object nul = null;
+        test("isStringDynamic", nul);
+        test("isStringDynamic", "object");
+        test("isStringDynamic", Object.class);
+    }
+
+    @Test
+    public void test101() {
+        final Object nul = null;
+        test("isStringIntDynamic", nul);
+        test("isStringIntDynamic", "object");
+        test("isStringIntDynamic", Object.class);
+    }
+
+    @Test
+    public void test103() {
+        test("isInstanceDynamic", String.class, null);
+        test("isInstanceDynamic", String.class, "object");
+        test("isInstanceDynamic", String.class, Object.class);
+    }
+
+    @Test
+    public void test104() {
+        test("isInstanceIntDynamic", String.class, null);
+        test("isInstanceIntDynamic", String.class, "object");
+        test("isInstanceIntDynamic", String.class, Object.class);
+    }
+
+    public static boolean isStringDynamic(Object o) {
+        return String.class.isInstance(o);
+    }
+
+    public static int isStringIntDynamic(Object o) {
+        if (String.class.isInstance(o)) {
+            return o.toString().length();
+        }
+        return o.getClass().getName().length();
+    }
+
+    public static boolean isInstanceDynamic(Class c, Object o) {
+        return c.isInstance(o);
+    }
+
+    public static int isInstanceIntDynamic(Class c, Object o) {
+        if (c.isInstance(o)) {
+            return o.toString().length();
+        }
+        return o.getClass().getName().length();
+    }
+}
--- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/IntrinsificationTest.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/IntrinsificationTest.java	Wed Dec 19 10:01:08 2012 +0100
@@ -65,7 +65,7 @@
     @Test
     public void testClassIntrinsics() {
         test("getModifiersSnippet");
-//        test("isInstanceSnippet");
+        test("isInstanceSnippet");
         test("isInterfaceSnippet");
         test("isArraySnippet");
         test("isPrimitiveSnippet");
@@ -128,7 +128,6 @@
     public void testSystemIntrinsics() {
         test("systemTimeSnippet");
         test("systemIdentityHashCode");
-//        test("arraycopySnippet");
     }
 
     @SuppressWarnings("all")
@@ -140,10 +139,6 @@
     public static int systemIdentityHashCode(Object obj) {
         return System.identityHashCode(obj);
     }
-    @SuppressWarnings("all")
-    public static void arraycopySnippet(int[] src, int srcPos, int[] dest, int destPos, int length) {
-        System.arraycopy(src, srcPos, dest, destPos, length);
-    }
 
 
     @Test
@@ -400,7 +395,7 @@
 
 
     private StructuredGraph test(final String snippet) {
-        return Debug.scope("IntrinsificationTest", new DebugDumpScope(snippet), new Callable<StructuredGraph>() {
+        return Debug.scope("IntrinsificationTest", runtime.lookupJavaMethod(getMethod(snippet)), new Callable<StructuredGraph>() {
             @Override
             public StructuredGraph call() {
                 StructuredGraph graph = parse(snippet);
--- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/NewMultiArrayTest.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/NewMultiArrayTest.java	Wed Dec 19 10:01:08 2012 +0100
@@ -38,32 +38,6 @@
  */
 public class NewMultiArrayTest extends GraalCompilerTest {
 
-    @Override
-    protected void assertEquals(Object expected, Object actual) {
-        Assert.assertTrue(expected != null);
-        Assert.assertTrue(actual != null);
-        super.assertEquals(expected.getClass(), actual.getClass());
-        if (expected instanceof int[]) {
-            Assert.assertArrayEquals((int[]) expected, (int[]) actual);
-        } else if (expected instanceof byte[]) {
-            Assert.assertArrayEquals((byte[]) expected, (byte[]) actual);
-        } else if (expected instanceof char[]) {
-            Assert.assertArrayEquals((char[]) expected, (char[]) actual);
-        } else if (expected instanceof short[]) {
-            Assert.assertArrayEquals((short[]) expected, (short[]) actual);
-        } else if (expected instanceof float[]) {
-            Assert.assertArrayEquals((float[]) expected, (float[]) actual, 0.0f);
-        } else if (expected instanceof long[]) {
-            Assert.assertArrayEquals((long[]) expected, (long[]) actual);
-        } else if (expected instanceof double[]) {
-            Assert.assertArrayEquals((double[]) expected, (double[]) actual, 0.0d);
-        } else if (expected instanceof Object[]) {
-            Assert.assertArrayEquals((Object[]) expected, (Object[]) actual);
-        } else {
-            Assert.fail("non-array value encountered: " + expected);
-        }
-    }
-
     private static int rank(ResolvedJavaType type) {
         String name = type.getName();
         int dims = 0;
--- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/WordTest.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/WordTest.java	Wed Dec 19 10:01:08 2012 +0100
@@ -53,7 +53,7 @@
     @Override
     protected StructuredGraph parse(Method m) {
         ResolvedJavaMethod resolvedMethod = runtime.lookupJavaMethod(m);
-        return installer.makeGraph(resolvedMethod, inliningPolicy.get());
+        return installer.makeGraph(resolvedMethod, inliningPolicy.get(), false);
     }
 
     @Test
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/InstanceOfSnippetsTemplates.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/InstanceOfSnippetsTemplates.java	Wed Dec 19 10:01:08 2012 +0100
@@ -77,7 +77,8 @@
      */
     protected abstract KeyAndArguments getKeyAndArguments(InstanceOfUsageReplacer replacer, LoweringTool tool);
 
-    public void lower(InstanceOfNode instanceOf, LoweringTool tool) {
+    public void lower(FloatingNode instanceOf, LoweringTool tool) {
+        assert instanceOf instanceof InstanceOfNode || instanceOf instanceof InstanceOfDynamicNode;
         List<Node> usages = instanceOf.usages().snapshot();
         int nUsages = usages.size();
 
@@ -107,7 +108,7 @@
      * Gets the specific replacer object used to replace the usage of an instanceof node
      * with the result of an instantiated instanceof snippet.
      */
-    protected InstanceOfUsageReplacer createReplacer(InstanceOfNode instanceOf, LoweringTool tool, int nUsages, Instantiation instantiation, Node usage, final StructuredGraph graph) {
+    protected InstanceOfUsageReplacer createReplacer(FloatingNode instanceOf, LoweringTool tool, int nUsages, Instantiation instantiation, Node usage, final StructuredGraph graph) {
         InstanceOfUsageReplacer replacer;
         if (usage instanceof IfNode) {
             replacer = new IfUsageReplacer(instantiation, ConstantNode.forInt(1, graph), ConstantNode.forInt(0, graph), instanceOf, (IfNode) usage, nUsages == 1, tool);
@@ -175,15 +176,16 @@
     }
 
     /**
-     * Replaces a usage of an {@link InstanceOfNode}.
+     * Replaces a usage of an {@link InstanceOfNode} or {@link InstanceOfDynamicNode}.
      */
     public abstract static class InstanceOfUsageReplacer implements UsageReplacer {
         public final Instantiation instantiation;
-        public final InstanceOfNode instanceOf;
+        public final FloatingNode instanceOf;
         public final ValueNode trueValue;
         public final ValueNode falseValue;
 
-        public InstanceOfUsageReplacer(Instantiation instantiation, InstanceOfNode instanceOf, ValueNode trueValue, ValueNode falseValue) {
+        public InstanceOfUsageReplacer(Instantiation instantiation, FloatingNode instanceOf, ValueNode trueValue, ValueNode falseValue) {
+            assert instanceOf instanceof InstanceOfNode || instanceOf instanceof InstanceOfDynamicNode;
             this.instantiation = instantiation;
             this.instanceOf = instanceOf;
             this.trueValue = trueValue;
@@ -197,7 +199,7 @@
     }
 
     /**
-     * Replaces an {@link IfNode} usage of an {@link InstanceOfNode}.
+     * Replaces an {@link IfNode} usage of an {@link InstanceOfNode} or {@link InstanceOfDynamicNode}.
      */
     public static class IfUsageReplacer extends InstanceOfUsageReplacer {
 
@@ -205,7 +207,7 @@
         private final IfNode usage;
         private final boolean sameBlock;
 
-        public IfUsageReplacer(Instantiation instantiation, ValueNode trueValue, ValueNode falseValue, InstanceOfNode instanceOf, IfNode usage, boolean solitaryUsage, LoweringTool tool) {
+        public IfUsageReplacer(Instantiation instantiation, ValueNode trueValue, ValueNode falseValue, FloatingNode instanceOf, IfNode usage, boolean solitaryUsage, LoweringTool tool) {
             super(instantiation, instanceOf, trueValue, falseValue);
             this.sameBlock = tool.getBlockFor(usage) == tool.getBlockFor(instanceOf);
             this.solitaryUsage = solitaryUsage;
@@ -294,13 +296,13 @@
     }
 
     /**
-     * Replaces a {@link ConditionalNode} usage of an {@link InstanceOfNode}.
+     * Replaces a {@link ConditionalNode} usage of an {@link InstanceOfNode} or {@link InstanceOfDynamicNode}.
      */
     public static class ConditionalUsageReplacer extends InstanceOfUsageReplacer {
 
         public final ConditionalNode usage;
 
-        public ConditionalUsageReplacer(Instantiation instantiation, ValueNode trueValue, ValueNode falseValue, InstanceOfNode instanceOf, ConditionalNode usage) {
+        public ConditionalUsageReplacer(Instantiation instantiation, ValueNode trueValue, ValueNode falseValue, FloatingNode instanceOf, ConditionalNode usage) {
             super(instantiation, instanceOf, trueValue, falseValue);
             this.usage = usage;
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetFrameStateCleanupPhase.java	Wed Dec 19 10:01:08 2012 +0100
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2011, 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.graal.snippets;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.util.*;
+import com.oracle.graal.phases.*;
+
+/**
+ * Removes frame states from {@linkplain StateSplit#hasSideEffect() non-side-effecting} nodes in a snippet.
+ */
+public class SnippetFrameStateCleanupPhase extends Phase {
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        for (Node node : graph.getNodes().filterInterface(StateSplit.class)) {
+            StateSplit stateSplit = (StateSplit) node;
+            FrameState frameState = stateSplit.stateAfter();
+            if (!stateSplit.hasSideEffect()) {
+                if (frameState != null) {
+                    stateSplit.setStateAfter(null);
+                    if (frameState.usages().isEmpty()) {
+                        GraphUtil.killWithUnusedFloatingInputs(frameState);
+                    }
+                }
+            }
+        }
+    }
+}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetInstaller.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetInstaller.java	Wed Dec 19 10:01:08 2012 +0100
@@ -93,7 +93,7 @@
                 }
                 ResolvedJavaMethod snippet = runtime.lookupJavaMethod(method);
                 assert snippet.getCompilerStorage().get(Graph.class) == null : method;
-                StructuredGraph graph = makeGraph(snippet, inliningPolicy(snippet));
+                StructuredGraph graph = makeGraph(snippet, inliningPolicy(snippet), false);
                 //System.out.println("snippet: " + graph);
                 snippet.getCompilerStorage().put(Graph.class, graph);
             }
@@ -131,7 +131,7 @@
                     throw new RuntimeException("Snippet must not be abstract or native");
                 }
                 ResolvedJavaMethod snippet = runtime.lookupJavaMethod(method);
-                StructuredGraph graph = makeGraph(snippet, inliningPolicy(snippet));
+                StructuredGraph graph = makeGraph(snippet, inliningPolicy(snippet), true);
                 //System.out.println("snippet: " + graph);
                 runtime.lookupJavaMethod(originalMethod).getCompilerStorage().put(Graph.class, graph);
             } catch (NoSuchMethodException e) {
@@ -156,14 +156,28 @@
         }
     }
 
-    public StructuredGraph makeGraph(final ResolvedJavaMethod method, final SnippetInliningPolicy policy) {
-        StructuredGraph graph = parseGraph(method, policy);
+    public StructuredGraph makeGraph(final ResolvedJavaMethod method, final SnippetInliningPolicy policy, final boolean isSubstitutionSnippet) {
+        return Debug.scope("BuildSnippetGraph", new Object[] {method}, new Callable<StructuredGraph>() {
+            @Override
+            public StructuredGraph call() throws Exception {
+                StructuredGraph graph = parseGraph(method, policy);
+
+                new SnippetIntrinsificationPhase(runtime, pool, SnippetTemplate.hasConstantParameter(method)).apply(graph);
 
-        new SnippetIntrinsificationPhase(runtime, pool, SnippetTemplate.hasConstantParameter(method)).apply(graph);
+                if (isSubstitutionSnippet) {
+                    // TODO (ds) remove the constraint of only processing substitution snippets
+                    // once issues with the arraycopy snippets have been resolved
+                    new SnippetFrameStateCleanupPhase().apply(graph);
+                    new DeadCodeEliminationPhase().apply(graph);
+                }
 
-        Debug.dump(graph, "%s: Final", method.getName());
+                new InsertStateAfterPlaceholderPhase().apply(graph);
+
+                Debug.dump(graph, "%s: Final", method.getName());
 
-        return graph;
+                return graph;
+            }
+        });
     }
 
     private StructuredGraph parseGraph(final ResolvedJavaMethod method, final SnippetInliningPolicy policy) {
@@ -178,54 +192,47 @@
 
     private StructuredGraph buildGraph(final ResolvedJavaMethod method, final SnippetInliningPolicy policy) {
         final StructuredGraph graph = new StructuredGraph(method);
-        return Debug.scope("BuildSnippetGraph", new Object[] {method, graph}, new Callable<StructuredGraph>() {
-            @Override
-            public StructuredGraph call() throws Exception {
-                GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault();
-                GraphBuilderPhase graphBuilder = new GraphBuilderPhase(runtime, config, OptimisticOptimizations.NONE);
-                graphBuilder.apply(graph);
+        GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault();
+        GraphBuilderPhase graphBuilder = new GraphBuilderPhase(runtime, config, OptimisticOptimizations.NONE);
+        graphBuilder.apply(graph);
 
-                Debug.dump(graph, "%s: %s", method.getName(), GraphBuilderPhase.class.getSimpleName());
+        Debug.dump(graph, "%s: %s", method.getName(), GraphBuilderPhase.class.getSimpleName());
 
-                new SnippetVerificationPhase(runtime).apply(graph);
+        new SnippetVerificationPhase(runtime).apply(graph);
 
-                new SnippetIntrinsificationPhase(runtime, pool, true).apply(graph);
+        new SnippetIntrinsificationPhase(runtime, pool, true).apply(graph);
 
-                for (Invoke invoke : graph.getInvokes()) {
-                    MethodCallTargetNode callTarget = invoke.methodCallTarget();
-                    ResolvedJavaMethod callee = callTarget.targetMethod();
-                    if (policy.shouldInline(callee, method)) {
-                        StructuredGraph targetGraph = parseGraph(callee, policy);
-                        InliningUtil.inline(invoke, targetGraph, true);
-                        Debug.dump(graph, "after inlining %s", callee);
-                        if (GraalOptions.OptCanonicalizer) {
-                            new WordTypeRewriterPhase(target.wordKind).apply(graph);
-                            new CanonicalizerPhase(target, runtime, assumptions).apply(graph);
-                        }
-                    }
-                }
-
-                new SnippetIntrinsificationPhase(runtime, pool, true).apply(graph);
-
-                new WordTypeRewriterPhase(target.wordKind).apply(graph);
-
-                new DeadCodeEliminationPhase().apply(graph);
+        for (Invoke invoke : graph.getInvokes()) {
+            MethodCallTargetNode callTarget = invoke.methodCallTarget();
+            ResolvedJavaMethod callee = callTarget.targetMethod();
+            if (policy.shouldInline(callee, method)) {
+                StructuredGraph targetGraph = parseGraph(callee, policy);
+                InliningUtil.inline(invoke, targetGraph, true);
+                Debug.dump(graph, "after inlining %s", callee);
                 if (GraalOptions.OptCanonicalizer) {
+                    new WordTypeRewriterPhase(target.wordKind).apply(graph);
                     new CanonicalizerPhase(target, runtime, assumptions).apply(graph);
                 }
+            }
+        }
 
-                for (LoopEndNode end : graph.getNodes(LoopEndNode.class)) {
-                    end.disableSafepoint();
-                }
+        new SnippetIntrinsificationPhase(runtime, pool, true).apply(graph);
 
-                new InsertStateAfterPlaceholderPhase().apply(graph);
+        new WordTypeRewriterPhase(target.wordKind).apply(graph);
 
-                if (GraalOptions.ProbabilityAnalysis) {
-                    new DeadCodeEliminationPhase().apply(graph);
-                    new ComputeProbabilityPhase().apply(graph);
-                }
-                return graph;
-            }
-        });
+        new DeadCodeEliminationPhase().apply(graph);
+        if (GraalOptions.OptCanonicalizer) {
+            new CanonicalizerPhase(target, runtime, assumptions).apply(graph);
+        }
+
+        for (LoopEndNode end : graph.getNodes(LoopEndNode.class)) {
+            end.disableSafepoint();
+        }
+
+        if (GraalOptions.ProbabilityAnalysis) {
+            new DeadCodeEliminationPhase().apply(graph);
+            new ComputeProbabilityPhase().apply(graph);
+        }
+        return graph;
     }
 }
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetIntrinsificationPhase.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetIntrinsificationPhase.java	Wed Dec 19 10:01:08 2012 +0100
@@ -221,7 +221,7 @@
                                         InvokeWithExceptionNode invokeWithExceptionNode = (InvokeWithExceptionNode) invokeNode;
 
                                         invokeWithExceptionNode.killExceptionEdge();
-                                        graph.removeSplit(invokeWithExceptionNode, InvokeWithExceptionNode.NORMAL_EDGE);
+                                        graph.removeSplit(invokeWithExceptionNode, invokeWithExceptionNode.next());
                                     } else {
                                         graph.removeFixed((InvokeNode) invokeNode);
                                     }
@@ -381,7 +381,7 @@
                             InvokeWithExceptionNode invokeWithExceptionNode = (InvokeWithExceptionNode) invokeNode;
 
                             invokeWithExceptionNode.killExceptionEdge();
-                            graph.removeSplit(invokeWithExceptionNode, InvokeWithExceptionNode.NORMAL_EDGE);
+                            graph.removeSplit(invokeWithExceptionNode, invokeWithExceptionNode.next());
                         } else {
                             graph.removeFixed((InvokeNode) invokeNode);
                         }
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java	Wed Dec 19 10:01:08 2012 +0100
@@ -208,7 +208,9 @@
                 throw new GraalInternalError(e);
             }
         }
-}
+    }
+
+    private static final Object UNUSED_PARAMETER = "DEAD PARAMETER";
 
     /**
      * Determines if any parameter of a given method is annotated with {@link ConstantParameter}.
@@ -315,8 +317,12 @@
                 Parameter p = parameterAnnotations[i];
                 if (p != null) {
                     LocalNode local = snippetCopy.getLocal(i);
-                    assert local != null;
-                    parameters.put(p.value(), local);
+                    if (local == null) {
+                        // Parameter value was eliminated
+                        parameters.put(p.value(), UNUSED_PARAMETER);
+                    } else {
+                        parameters.put(p.value(), local);
+                    }
                 }
             }
         }
@@ -431,7 +437,9 @@
 
     /**
      * The named parameters of this template that must be bound to values during instantiation.
-     * Each value in this map is either a {@link LocalNode} instance or a {@link LocalNode} array.
+     * For a parameter that is still live after specialization, the value in this map is either
+     * a {@link LocalNode} instance or a {@link LocalNode} array. For an eliminated parameter,
+     * the value is identical to the key.
      */
     private final Map<String, Object> parameters;
 
@@ -477,8 +485,7 @@
                     Constant constant = Constant.forBoxed(kind, argument);
                     replacements.put((LocalNode) parameter, ConstantNode.forConstant(constant, runtime, replaceeGraph));
                 }
-            } else {
-                assert parameter instanceof LocalNode[];
+            } else if (parameter instanceof LocalNode[]) {
                 LocalNode[] locals = (LocalNode[]) parameter;
                 Object array = argument;
                 assert array != null && array.getClass().isArray();
@@ -496,6 +503,8 @@
                         replacements.put(local, element);
                     }
                 }
+            } else {
+                assert parameter == UNUSED_PARAMETER : "unexpected entry for parameter: " + name + " -> " + parameter;
             }
         }
         return replacements;
@@ -673,7 +682,9 @@
             Object value = e.getValue();
             buf.append(sep);
             sep = ", ";
-            if (value instanceof LocalNode) {
+            if (value == UNUSED_PARAMETER)  {
+                buf.append("<unused> ").append(name);
+            } else if (value instanceof LocalNode) {
                 LocalNode local = (LocalNode) value;
                 buf.append(local.kind().getJavaName()).append(' ').append(name);
             } else {
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Word.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Word.java	Wed Dec 19 10:01:08 2012 +0100
@@ -58,6 +58,10 @@
         OR,
         AND,
         XOR,
+        READ_INT,
+        READ_WORD,
+        READ_OBJECT,
+        READ_FINAL_OBJECT,
         BELOW,
         BELOW_EQUAL,
         ABOVE,
@@ -237,4 +241,20 @@
         return new Word(value | other.value, null);
     }
 
+    @Operation(READ_INT)
+    public native int readInt(int offset);
+
+    @Operation(READ_WORD)
+    public native Word readWord(int offset);
+
+    @Operation(READ_OBJECT)
+    public native Object readObject(int offset);
+
+    /**
+     * Reads an object value from a location that is guaranteed not be to modified after this read.
+     *
+     * @param offset the offset from this base address of the location to be read
+     */
+    @Operation(READ_FINAL_OBJECT)
+    public native Object readFinalObject(int offset);
 }
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/WordTypeRewriterPhase.java	Tue Dec 18 15:05:58 2012 +0100
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/WordTypeRewriterPhase.java	Wed Dec 19 10:01:08 2012 +0100
@@ -212,6 +212,18 @@
                         break;
                     }
 
+                    case READ_INT:
+                    case READ_OBJECT:
+                    case READ_WORD: {
+                        replaceRead(graph, arguments, invoke, LocationNode.ANY_LOCATION);
+                        break;
+                    }
+
+                    case READ_FINAL_OBJECT: {
+                        replaceRead(graph, arguments, invoke, LocationNode.FINAL_LOCATION);
+                        break;
+                    }
+
                     default: {
                         throw new GraalInternalError("Unknown opcode: %s", opcode);
                     }
@@ -220,6 +232,17 @@
         }
     }
 
+    protected void replaceRead(StructuredGraph graph, NodeInputList<ValueNode> arguments, Invoke invoke, Object locationIdentity) {
+        assert arguments.size() == 2;
+        ValueNode base = arguments.first();
+        IndexedLocationNode location = IndexedLocationNode.create(locationIdentity, invoke.node().kind(), 0, arguments.last(), graph, false);
+        ReadNode read = graph.add(new ReadNode(base, location, invoke.node().stamp()));
+        graph.addBeforeFixed(invoke.node(), read);
+        // The read must not float outside its block otherwise it may float above an explicit zero check on its base address
+        read.dependencies().add(BeginNode.prevBegin(invoke.node()));
+        replace(invoke, read);
+    }
+
     protected void replace(Invoke invoke, ValueNode value) {
         FixedNode next = invoke.next();
         invoke.setNext(null);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ArgumentsTest.java	Wed Dec 19 10:01:08 2012 +0100
@@ -0,0 +1,100 @@
+/*
+ * 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.test;
+
+import org.junit.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+
+
+/**
+ * <h3>Passing Arguments</h3>
+ *
+ * <p>
+ * A guest language can pass its own custom arguments when invoking a Truffle method by creating a subclass of
+ * {@link Arguments}. When invoking a call target with {@link CallTarget#call(Arguments)}, the arguments can be passed.
+ * A Truffle node can access the arguments passed into the Truffle method by using {@link VirtualFrame#getArguments()}.
+ * </p>
+ *
+ * <p>
+ * The arguments class should only contain fields that are declared as final. This allows the Truffle runtime to improve
+ * optimizations around guest language method calls. Also, the arguments object must never be stored into a field. It
+ * should be created immediately before invoking {@link CallTarget#call(Arguments)} and no longer be accessed
+ * afterwards.
+ * </p>
+ *
+ * <p>
+ * The next part of the Truffle API introduction is at {@link com.oracle.truffle.api.test.FrameTest}.
+ * </p>
+ */
+public class ArgumentsTest {
+
+    @Test
+    public void test() {
+        TruffleRuntime runtime = Truffle.getRuntime();
+        TestRootNode rootNode = new TestRootNode(new TestArgumentNode[]{new TestArgumentNode(0), new TestArgumentNode(1)});
+        CallTarget target = runtime.createCallTarget(rootNode);
+        Object result = target.call(new TestArguments(20, 22));
+        Assert.assertEquals(42, result);
+    }
+
+    class TestArguments extends Arguments {
+        final int[] values;
+        TestArguments(int... values) {
+            this.values = values;
+        }
+    }
+
+    class TestRootNode extends RootNode {
+
+        @Children private TestArgumentNode[] children;
+
+        TestRootNode(TestArgumentNode[] children) {
+            this.children = adoptChildren(children);
+        }
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            int sum = 0;
+            for (int i = 0; i < children.length; ++i) {
+                sum += children[i].execute(frame);
+            }
+            return sum;
+        }
+    }
+
+    class TestArgumentNode extends Node {
+        private final int index;
+
+        TestArgumentNode(int index) {
+            this.index = index;
+        }
+
+        int execute(VirtualFrame frame) {
+            return ((TestArguments) frame.getArguments()).values[index];
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/CallTest.java	Wed Dec 19 10:01:08 2012 +0100
@@ -0,0 +1,85 @@
+/*
+ * 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.test;
+
+import org.junit.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+
+
+/**
+ * <h3>Calling Another Tree</h3>
+ *
+ * <p>
+ * A guest language implementation can create multiple call targets using the {@link TruffleRuntime#createCallTarget(RootNode)} method.
+ * Those call targets can be passed around as normal Java objects and used for calling guest language methods.
+ * </p>
+ *
+ * <p>
+ * The next part of the Truffle API introduction is at {@link com.oracle.truffle.api.test.ArgumentsTest}.
+ * </p>
+ */
+public class CallTest {
+
+    @Test
+    public void test() {
+        TruffleRuntime runtime = Truffle.getRuntime();
+        CallTarget foo = runtime.createCallTarget(new ConstantRootNode(20));
+        CallTarget bar = runtime.createCallTarget(new ConstantRootNode(22));
+        CallTarget main = runtime.createCallTarget(new DualCallNode(foo, bar));
+        Object result = main.call();
+        Assert.assertEquals(42, result);
+    }
+
+    class DualCallNode extends RootNode {
+
+        private final CallTarget firstTarget;
+        private final CallTarget secondTarget;
+
+        DualCallNode(CallTarget firstTarget, CallTarget secondTarget) {
+            this.firstTarget = firstTarget;
+            this.secondTarget = secondTarget;
+        }
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            return ((Integer) firstTarget.call()) + ((Integer) secondTarget.call());
+        }
+    }
+
+    class ConstantRootNode extends RootNode {
+        private final int value;
+
+        public ConstantRootNode(int value) {
+            this.value = value;
+        }
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            return value;
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ChildNodeTest.java	Wed Dec 19 10:01:08 2012 +0100
@@ -0,0 +1,93 @@
+/*
+ * 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.test;
+
+import java.util.*;
+
+import org.junit.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.nodes.Node.Child;
+
+/**
+ * <h3>Creating a Child Node</h3>
+ *
+ * <p>
+ * Child nodes are stored in the class of the parent node in fields that are marked with the {@link Child} annotation.
+ * Before such a field is assigned, {@link Node#adoptChild} must be called. This method automatically establishes a link
+ * from the child to the parent. The {@link Node#getParent()} method allows access to this field. Every node also
+ * provides the ability to iterate over its children using {@link Node#getChildren()}.</p>
+ *
+ * <p>A child node field must be declared private and non-final. It may only be assigned in the constructor of the parent
+ * node. For changing the structure of the tree at run time, the method {@link Node#replace(Node)} must be used (see
+ * {@link ReplaceTest}).
+ * </p>
+ *
+ * <p>
+ * The next part of the Truffle API introduction is at {@link com.oracle.truffle.api.test.ChildrenNodesTest}.
+ * </p>
+ */
+public class ChildNodeTest {
+
+    @Test
+    public void test() {
+        TruffleRuntime runtime = Truffle.getRuntime();
+        TestChildNode leftChild = new TestChildNode();
+        TestChildNode rightChild = new TestChildNode();
+        TestRootNode rootNode = new TestRootNode(leftChild, rightChild);
+        Assert.assertEquals(rootNode, leftChild.getParent());
+        Assert.assertEquals(rootNode, rightChild.getParent());
+        Iterator<Node> iterator = rootNode.getChildren().iterator();
+        Assert.assertEquals(leftChild, iterator.next());
+        Assert.assertEquals(rightChild, iterator.next());
+        Assert.assertFalse(iterator.hasNext());
+        CallTarget target = runtime.createCallTarget(rootNode);
+        Object result = target.call();
+        Assert.assertEquals(42, result);
+    }
+
+    class TestRootNode extends RootNode {
+
+        @Child private TestChildNode left;
+        @Child private TestChildNode right;
+
+        public TestRootNode(TestChildNode left, TestChildNode right) {
+            this.left = adoptChild(left);
+            this.right = adoptChild(right);
+        }
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            return left.execute() + right.execute();
+        }
+    }
+
+    class TestChildNode extends Node {
+
+        public int execute() {
+            return 21;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ChildrenNodesTest.java	Wed Dec 19 10:01:08 2012 +0100
@@ -0,0 +1,91 @@
+/*
+ * 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.test;
+
+import java.util.*;
+
+import org.junit.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * <h3>Creating an Array of Children Nodes</h3>
+ *
+ * <p>
+ * An array of children nodes can be used as a field in a parent node. The field has to be annotated with
+ * {@link com.oracle.truffle.api.nodes.Node.Children} and must be declared private and final. Before assigning the field
+ * in the parent node constructor, {@link Node#adoptChildren} must be called in order to update the parent pointers in
+ * the child nodes. After filling the array with its first values, it must never be changed. It is only possible to call
+ * {@link Node#replace} on a child node.
+ * </p>
+ *
+ * <p>
+ * The next part of the Truffle API introduction is at {@link com.oracle.truffle.api.test.FinalFieldTest}.
+ * </p>
+ */
+public class ChildrenNodesTest {
+
+    @Test
+    public void test() {
+        TruffleRuntime runtime = Truffle.getRuntime();
+        TestChildNode firstChild = new TestChildNode();
+        TestChildNode secondChild = new TestChildNode();
+        TestRootNode rootNode = new TestRootNode(new TestChildNode[]{firstChild, secondChild});
+        Assert.assertEquals(rootNode, firstChild.getParent());
+        Assert.assertEquals(rootNode, secondChild.getParent());
+        Iterator<Node> iterator = rootNode.getChildren().iterator();
+        Assert.assertEquals(firstChild, iterator.next());
+        Assert.assertEquals(secondChild, iterator.next());
+        Assert.assertFalse(iterator.hasNext());
+        CallTarget target = runtime.createCallTarget(rootNode);
+        Object result = target.call();
+        Assert.assertEquals(42, result);
+    }
+
+    class TestRootNode extends RootNode {
+
+        @Children private final TestChildNode[] children;
+
+        public TestRootNode(TestChildNode[] children) {
+            this.children = adoptChildren(children);
+        }
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            int sum = 0;
+            for (int i = 0; i < children.length; ++i) {
+                sum += children[i].execute();
+            }
+            return sum;
+        }
+    }
+
+    class TestChildNode extends Node {
+        public int execute() {
+            return 21;
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FinalFieldTest.java	Wed Dec 19 10:01:08 2012 +0100
@@ -0,0 +1,92 @@
+/*
+ * 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.test;
+
+import org.junit.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * <h3>Using Final Fields in Node Classes</h3>
+ *
+ * <p>
+ * The usage of final fields in node classes is highly encouraged. It is beneficial for performance to declare every
+ * field that is not pointing to a child node as final. This gives the Truffle runtime an increased opportunity to
+ * optimize this node.
+ * </p>
+ *
+ * <p>
+ * If a node has a value which may change at run time, but will rarely do so, it is recommended to speculate on the
+ * field being final. This involves starting executing with a node where this field is final and only if this
+ * turns out to be no longer the case, the node is replaced with an alternative implementation of the operation (see
+ * {@link ReplaceTest}).
+ * </p>
+ *
+ * <p>
+ * The next part of the Truffle API introduction is at {@link com.oracle.truffle.api.test.ReplaceTest}.
+ * </p>
+ */
+public class FinalFieldTest {
+
+    @Test
+    public void test() {
+        TruffleRuntime runtime = Truffle.getRuntime();
+        TestRootNode rootNode = new TestRootNode(new TestChildNode[]{new TestChildNode(20), new TestChildNode(22)});
+        CallTarget target = runtime.createCallTarget(rootNode);
+        Object result = target.call();
+        Assert.assertEquals(42, result);
+    }
+
+    class TestRootNode extends RootNode {
+
+        @Children TestChildNode[] children;
+
+        public TestRootNode(TestChildNode[] children) {
+            this.children = adoptChildren(children);
+        }
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            int sum = 0;
+            for (int i = 0; i < children.length; ++i) {
+                sum += children[i].execute();
+            }
+            return sum;
+        }
+    }
+
+    class TestChildNode extends Node {
+        private final int value;
+
+        public TestChildNode(int value) {
+            this.value = value;
+        }
+
+        public int execute() {
+            return value;
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameSlotTypeSpecializationTest.java	Wed Dec 19 10:01:08 2012 +0100
@@ -0,0 +1,178 @@
+/*
+ * 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.test;
+
+import org.junit.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+
+
+/**
+ * <h3>Specializing Frame Slot Types</h3>
+ *
+ * <p>
+ * Dynamically typed languages can speculate on the type of a frame slot and only fall back at run time to a more
+ * generic type if necessary. The new type of a frame slot can be set using the {@link FrameSlot#setType(Class)} method.
+ * It is the responsibility of the language implementor to update the content of currently active frames (using
+ * {@link Frame#updateToLatestVersion()}). Also, nodes that depend a specific type of a frame slot must be replaced.
+ * Such node can register a listener that implements {@link FrameSlotTypeListener} using
+ * {@link FrameSlot#registerOneShotTypeListener(FrameSlotTypeListener)}. The event of a type change on the frame slot
+ * will fire only once for the next upcoming change.
+ * </p>
+ *
+ * <p>
+ * The next part of the Truffle API introduction is at {@link com.oracle.truffle.api.test.ReturnTypeSpecializationTest}.
+ * </p>
+ */
+public class FrameSlotTypeSpecializationTest {
+
+    @Test
+    public void test() {
+        TruffleRuntime runtime = Truffle.getRuntime();
+        FrameDescriptor frameDescriptor = new FrameDescriptor();
+        FrameSlot slot = frameDescriptor.addFrameSlot("localVar", Integer.class);
+        TestRootNode rootNode = new TestRootNode(new IntAssignLocal(slot, new StringTestChildNode()), new IntReadLocal(slot));
+        CallTarget target = runtime.createCallTarget(rootNode, frameDescriptor);
+        Assert.assertEquals(Integer.class, slot.getType());
+        Object result = target.call();
+        Assert.assertEquals("42", result);
+        Assert.assertEquals(Object.class, slot.getType());
+    }
+
+    class TestRootNode extends RootNode {
+
+        @Child TestChildNode left;
+        @Child TestChildNode right;
+
+        public TestRootNode(TestChildNode left, TestChildNode right) {
+            this.left = adoptChild(left);
+            this.right = adoptChild(right);
+        }
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            left.execute(frame);
+            return right.execute(frame);
+        }
+    }
+
+    abstract class TestChildNode extends Node {
+        abstract Object execute(VirtualFrame frame);
+    }
+
+    abstract class FrameSlotNode extends TestChildNode {
+        protected final FrameSlot slot;
+
+        public FrameSlotNode(FrameSlot slot) {
+            this.slot = slot;
+        }
+    }
+
+    class StringTestChildNode extends TestChildNode {
+
+        @Override
+        Object execute(VirtualFrame frame) {
+            return "42";
+        }
+
+    }
+
+    class IntAssignLocal extends FrameSlotNode implements FrameSlotTypeListener {
+        @Child private TestChildNode value;
+
+        IntAssignLocal(FrameSlot slot, TestChildNode value) {
+            super(slot);
+            this.value = adoptChild(value);
+            slot.registerOneShotTypeListener(this);
+        }
+
+        @Override
+        Object execute(VirtualFrame frame) {
+            Object o = value.execute(frame);
+            if (o instanceof Integer) {
+                frame.setInt(slot, (Integer) o);
+            } else {
+                slot.setType(Object.class);
+                frame.updateToLatestVersion();
+                frame.setObject(slot, o);
+            }
+            return null;
+        }
+
+        @Override
+        public void typeChanged(FrameSlot changedSlot, Class< ? > oldType) {
+            if (changedSlot.getType() == Object.class) {
+                this.replace(new ObjectAssignLocal(changedSlot, value));
+            }
+        }
+    }
+
+    class ObjectAssignLocal extends FrameSlotNode {
+        @Child private TestChildNode value;
+
+        ObjectAssignLocal(FrameSlot slot, TestChildNode value) {
+            super(slot);
+            this.value = adoptChild(value);
+        }
+
+        @Override
+        Object execute(VirtualFrame frame) {
+            Object o = value.execute(frame);
+            frame.setObject(slot, o);
+            return null;
+        }
+    }
+
+    class IntReadLocal extends FrameSlotNode implements FrameSlotTypeListener {
+        IntReadLocal(FrameSlot slot) {
+            super(slot);
+            slot.registerOneShotTypeListener(this);
+        }
+
+        @Override
+        Object execute(VirtualFrame frame) {
+            return frame.getInt(slot);
+        }
+
+        @Override
+        public void typeChanged(FrameSlot changedSlot, Class< ? > oldType) {
+            if (changedSlot.getType() == Object.class) {
+                this.replace(new ObjectReadLocal(changedSlot));
+            }
+        }
+    }
+
+    class ObjectReadLocal extends FrameSlotNode {
+        ObjectReadLocal(FrameSlot slot) {
+            super(slot);
+        }
+
+        @Override
+        Object execute(VirtualFrame frame) {
+            return frame.getObject(slot);
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameTest.java	Wed Dec 19 10:01:08 2012 +0100
@@ -0,0 +1,122 @@
+/*
+ * 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.test;
+
+import org.junit.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * <h3>Storing Values in Frame Slots</h3>
+ *
+ * <p>
+ * The frame is the preferred data structure for passing values between nodes. It can in particular be used for storing
+ * the values of local variables of the guest language. The {@link FrameDescriptor} represents the current structure of
+ * the frame. The method {@link FrameDescriptor#addFrameSlot(String, Class)} can be used to create predefined frame
+ * slots. The setter and getter methods in the {@link Frame} class can be used to access the current value of a
+ * particular frame slot.
+ * </p>
+ *
+ * <p>
+ * There are five primitive types for slots available: {@link java.lang.Boolean}, @{link java.lang.Integer},
+ * {@link java.lang.Long}, {@link java.lang.Float}, and {@link java.lang.Double}. It is encouraged to use those types
+ * whenever possible. Dynamically typed languages can speculate on the type of a value fitting into a primitive (see
+ * {@link FrameSlotTypeSpecializationTest}). When a frame slot is of one of those particular primitive types, its value
+ * may only be accessed with the repectively typed getter method ({@link Frame#getBoolean}, {@link Frame#getInt},
+ * {@link Frame#getLong}, {@link Frame#getFloat}, or {@link Frame#getDouble}) or setter method ({@link Frame#setBoolean},
+ * {@link Frame#setInt}, {@link Frame#setLong}, {@link Frame#setFloat}, or {@link Frame#setDouble}) in the
+ * {@link Frame} class.
+ * </p>
+ *
+ * <p>
+ * The next part of the Truffle API introduction is at
+ * {@link com.oracle.truffle.api.test.FrameSlotTypeSpecializationTest}.
+ * </p>
+ */
+public class FrameTest {
+
+    @Test
+    public void test() {
+        TruffleRuntime runtime = Truffle.getRuntime();
+        FrameDescriptor frameDescriptor = new FrameDescriptor();
+        FrameSlot slot = frameDescriptor.addFrameSlot("localVar", Integer.class);
+        TestRootNode rootNode = new TestRootNode(new AssignLocal(slot), new ReadLocal(slot));
+        CallTarget target = runtime.createCallTarget(rootNode, frameDescriptor);
+        Object result = target.call();
+        Assert.assertEquals(42, result);
+    }
+
+    class TestRootNode extends RootNode {
+
+        @Child TestChildNode left;
+        @Child TestChildNode right;
+
+        public TestRootNode(TestChildNode left, TestChildNode right) {
+            this.left = adoptChild(left);
+            this.right = adoptChild(right);
+        }
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            return left.execute(frame) + right.execute(frame);
+        }
+    }
+
+    abstract class TestChildNode extends Node {
+        abstract int execute(VirtualFrame frame);
+    }
+
+    abstract class FrameSlotNode extends TestChildNode {
+        protected final FrameSlot slot;
+
+        public FrameSlotNode(FrameSlot slot) {
+            this.slot = slot;
+        }
+    }
+
+    class AssignLocal extends FrameSlotNode {
+        AssignLocal(FrameSlot slot) {
+            super(slot);
+        }
+
+        @Override
+        int execute(VirtualFrame frame) {
+            frame.setInt(slot, 42);
+            return 0;
+        }
+    }
+
+    class ReadLocal extends FrameSlotNode {
+        ReadLocal(FrameSlot slot) {
+            super(slot);
+        }
+
+        @Override
+        int execute(VirtualFrame frame) {
+            return frame.getInt(slot);
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReplaceTest.java	Wed Dec 19 10:01:08 2012 +0100
@@ -0,0 +1,133 @@
+/*
+ * 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.test;
+
+import static org.junit.Assert.*;
+
+import java.util.*;
+
+import org.junit.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+
+
+/**
+ * <h3>Replacing Nodes at Run Time</h3>
+ *
+ * <p>
+ * The structure of the Truffle tree can be changed at run time by replacing nodes using the {@link Node#replace(Node)}
+ * method. This method will automatically change the child pointer in the parent of the node and replace it with a
+ * pointer to the new node.
+ * </p>
+ *
+ * <p>
+ * Replacing nodes is a costly operation, so it should not happen too often. The convention is that the implementation
+ * of the Truffle nodes should ensure that there are maximal a small (and constant) number of node replacements per
+ * Truffle node.
+ * </p>
+ *
+ * <p>
+ * The next part of the Truffle API introduction is at {@link com.oracle.truffle.api.test.CallTest}.
+ * </p>
+ */
+public class ReplaceTest {
+
+    @Test
+    public void test() {
+        TruffleRuntime runtime = Truffle.getRuntime();
+        UnresolvedNode leftChild = new UnresolvedNode("20");
+        UnresolvedNode rightChild = new UnresolvedNode("22");
+        TestRootNode rootNode = new TestRootNode(new ValueNode[]{leftChild, rightChild});
+        assertEquals(rootNode, leftChild.getParent());
+        assertEquals(rootNode, rightChild.getParent());
+        Iterator<Node> iterator = rootNode.getChildren().iterator();
+        Assert.assertEquals(leftChild, iterator.next());
+        Assert.assertEquals(rightChild, iterator.next());
+        Assert.assertFalse(iterator.hasNext());
+        CallTarget target = runtime.createCallTarget(rootNode);
+        Object result = target.call();
+        assertEquals(42, result);
+        assertEquals(42, target.call());
+        iterator = rootNode.getChildren().iterator();
+        Assert.assertEquals(ResolvedNode.class, iterator.next().getClass());
+        Assert.assertEquals(ResolvedNode.class, iterator.next().getClass());
+        Assert.assertFalse(iterator.hasNext());
+        iterator = rootNode.getChildren().iterator();
+        Assert.assertEquals(rootNode, iterator.next().getParent());
+        Assert.assertEquals(rootNode, iterator.next().getParent());
+        Assert.assertFalse(iterator.hasNext());
+    }
+
+    class TestRootNode extends RootNode {
+
+        @Children private ValueNode[] children;
+
+        public TestRootNode(ValueNode[] children) {
+            this.children = adoptChildren(children);
+        }
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            int sum = 0;
+            for (int i = 0; i < children.length; ++i) {
+                sum += children[i].execute();
+            }
+            return sum;
+        }
+    }
+
+    abstract class ValueNode extends Node {
+        abstract int execute();
+    }
+
+    class UnresolvedNode extends ValueNode {
+        private final String value;
+
+        public UnresolvedNode(String value) {
+            this.value = value;
+        }
+
+        @Override
+        int execute() {
+            int intValue = Integer.parseInt(value);
+            ResolvedNode newNode = this.replace(new ResolvedNode(intValue));
+            return newNode.execute();
+        }
+    }
+
+    class ResolvedNode extends ValueNode {
+        private final int value;
+
+        ResolvedNode(int value) {
+            this.value = value;
+        }
+
+        @Override
+        int execute() {
+            return value;
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReturnTypeSpecializationTest.java	Wed Dec 19 10:01:08 2012 +0100
@@ -0,0 +1,184 @@
+/*
+ * 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.test;
+
+import org.junit.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * <h3>Specializing Return Types</h3>
+ *
+ * <p>
+ * In order to avoid boxing and/or type casts on the return value of a node, the return value the method for executing a
+ * node can have a specific type and need not be of type {@link java.lang.Object}. For dynamically typed languages, this
+ * return type is something that should be speculated on. When the speculation fails and the child node cannot return
+ * the appropriate type of value, it can use an {@link UnexpectedResultException} to still pass the result to the
+ * caller. In such a case, the caller must rewrite itself to a more general version in oder to avoid future failures of
+ * this kind.
+ * </p>
+ */
+public class ReturnTypeSpecializationTest {
+
+    @Test
+    public void test() {
+        TruffleRuntime runtime = Truffle.getRuntime();
+        FrameDescriptor frameDescriptor = new FrameDescriptor();
+        FrameSlot slot = frameDescriptor.addFrameSlot("localVar", Integer.class);
+        TestRootNode rootNode = new TestRootNode(new IntAssignLocal(slot, new StringTestChildNode()), new IntReadLocal(slot));
+        CallTarget target = runtime.createCallTarget(rootNode, frameDescriptor);
+        Assert.assertEquals(Integer.class, slot.getType());
+        Object result = target.call();
+        Assert.assertEquals("42", result);
+        Assert.assertEquals(Object.class, slot.getType());
+    }
+
+    class TestRootNode extends RootNode {
+
+        @Child TestChildNode left;
+        @Child TestChildNode right;
+
+        public TestRootNode(TestChildNode left, TestChildNode right) {
+            this.left = adoptChild(left);
+            this.right = adoptChild(right);
+        }
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            left.execute(frame);
+            return right.execute(frame);
+        }
+    }
+
+    abstract class TestChildNode extends Node {
+        abstract Object execute(VirtualFrame frame);
+
+        int executeInt(VirtualFrame frame) throws UnexpectedResultException {
+            Object result = execute(frame);
+            if (result instanceof Integer) {
+                return (Integer) result;
+            }
+            throw new UnexpectedResultException(result);
+        }
+    }
+
+    abstract class FrameSlotNode extends TestChildNode {
+        protected final FrameSlot slot;
+
+        public FrameSlotNode(FrameSlot slot) {
+            this.slot = slot;
+        }
+    }
+
+    class StringTestChildNode extends TestChildNode {
+
+        @Override
+        Object execute(VirtualFrame frame) {
+            return "42";
+        }
+
+    }
+
+    class IntAssignLocal extends FrameSlotNode implements FrameSlotTypeListener {
+        @Child private TestChildNode value;
+
+        IntAssignLocal(FrameSlot slot, TestChildNode value) {
+            super(slot);
+            this.value = adoptChild(value);
+            slot.registerOneShotTypeListener(this);
+        }
+
+        @Override
+        Object execute(VirtualFrame frame) {
+            try {
+                frame.setInt(slot, value.executeInt(frame));
+            } catch (UnexpectedResultException e) {
+                slot.setType(Object.class);
+                frame.updateToLatestVersion();
+                frame.setObject(slot, e.getResult());
+            }
+            return null;
+        }
+
+        @Override
+        public void typeChanged(FrameSlot changedSlot, Class< ? > oldType) {
+            if (changedSlot.getType() == Object.class) {
+                this.replace(new ObjectAssignLocal(changedSlot, value));
+            }
+        }
+    }
+
+    class ObjectAssignLocal extends FrameSlotNode {
+        @Child private TestChildNode value;
+
+        ObjectAssignLocal(FrameSlot slot, TestChildNode value) {
+            super(slot);
+            this.value = adoptChild(value);
+        }
+
+        @Override
+        Object execute(VirtualFrame frame) {
+            Object o = value.execute(frame);
+            frame.setObject(slot, o);
+            return null;
+        }
+    }
+
+    class IntReadLocal extends FrameSlotNode implements FrameSlotTypeListener {
+        IntReadLocal(FrameSlot slot) {
+            super(slot);
+            slot.registerOneShotTypeListener(this);
+        }
+
+        @Override
+        Object execute(VirtualFrame frame) {
+            return executeInt(frame);
+        }
+
+        @Override
+        int executeInt(VirtualFrame frame) {
+            return frame.getInt(slot);
+        }
+
+        @Override
+        public void typeChanged(FrameSlot changedSlot, Class< ? > oldType) {
+            if (changedSlot.getType() == Object.class) {
+                this.replace(new ObjectReadLocal(changedSlot));
+            }
+        }
+    }
+
+    class ObjectReadLocal extends FrameSlotNode {
+        ObjectReadLocal(FrameSlot slot) {
+            super(slot);
+        }
+
+        @Override
+        Object execute(VirtualFrame frame) {
+            return frame.getObject(slot);
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/RootNodeTest.java	Wed Dec 19 10:01:08 2012 +0100
@@ -0,0 +1,65 @@
+/*
+ * 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.test;
+
+import org.junit.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * <h3>Creating a Root Node</h3>
+ *
+ * <p>
+ * A Truffle root node is the entry point into a Truffle tree that represents a guest language method. It contains a
+ * {@link RootNode#execute(VirtualFrame)} method that can return a {@link java.lang.Object} value as the result of the
+ * guest language method invocation. This method must however never be called directly. Instead, the Truffle runtime
+ * must be used to create a {@link CallTarget} object from a root node using the
+ * {@link TruffleRuntime#createCallTarget(RootNode)} method. This call target object can then be executed using the
+ * {@link CallTarget#call()} method or one of its overloads.
+ * </p>
+ *
+ * <p>
+ * The next part of the Truffle API introduction is at {@link com.oracle.truffle.api.test.ChildNodeTest}.
+ * </p>
+ */
+public class RootNodeTest {
+
+    @Test
+    public void test() {
+        TruffleRuntime runtime = Truffle.getRuntime();
+        TestRootNode rootNode = new TestRootNode();
+        CallTarget target = runtime.createCallTarget(rootNode);
+        Object result = target.call();
+        Assert.assertEquals(42, result);
+    }
+
+    class TestRootNode extends RootNode {
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            return 42;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/TruffleRuntimeTest.java	Wed Dec 19 10:01:08 2012 +0100
@@ -0,0 +1,51 @@
+/*
+ * 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.test;
+
+import org.junit.*;
+
+import com.oracle.truffle.api.*;
+
+/**
+ * <h3>Accessing the Truffle Runtime</h3>
+ *
+ * <p>
+ * The Truffle runtime can be accessed at any point in time globally using the static method
+ * {@link Truffle#getRuntime()}. This method is guaranteed to return a non-null Truffle runtime object with an
+ * identifying name. A Java Virtual Machine implementation can chose to replace the default implementation of the
+ * {@link TruffleRuntime} interface with its own implementation for providing improved performance.
+ * </p>
+ *
+ * <p>
+ * The next part of the Truffle API introduction is at {@link com.oracle.truffle.api.test.RootNodeTest}.
+ * </p>
+ */
+public class TruffleRuntimeTest {
+
+    @Test
+    public void test() {
+        TruffleRuntime runtime = Truffle.getRuntime();
+        Assert.assertNotNull(runtime);
+        Assert.assertNotNull(runtime.getName());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/package-info.java	Wed Dec 19 10:01:08 2012 +0100
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+/**
+ * <p>This package contains basic tests of the Truffle API and serves at the same
+ * time as an introduction to the Truffle API for language implementors. Every test gives an example on how to use the construct explained in the class description.</p>
+ *
+ * <p>
+ * Truffle is a language implementation framework. A guest language method is represented as a tree of executable nodes.
+ * The framework provides mechanisms for those trees to call each other. Additionally it contains dedicated data structures for storing data local to a tree invocation.
+ * </p>
+ *
+ * <p>
+ * This introduction to Truffle contains items in the following recommended order:
+ *
+ * <ul>
+ * <li>How to get access to the Truffle runtime? {@link com.oracle.truffle.api.test.TruffleRuntimeTest}</li>
+ * <li>How to create a root node? {@link com.oracle.truffle.api.test.RootNodeTest}</li>
+ * <li>How to create a child node and link it with its parent? {@link com.oracle.truffle.api.test.ChildNodeTest}</li>
+ * <li>How to create an array of child nodes? {@link com.oracle.truffle.api.test.ChildrenNodesTest}</li>
+ * <li>Why are final fields in node classes important? {@link com.oracle.truffle.api.test.FinalFieldTest}</li>
+ * <li>How to replace one node with another node and what for? {@link com.oracle.truffle.api.test.ReplaceTest}</li>
+ * <li>How to let one Truffle tree invoke another one? {@link com.oracle.truffle.api.test.CallTest}</li>
+ * <li>How to pass arguments when executing a tree? {@link com.oracle.truffle.api.test.ArgumentsTest}</li>
+ * <li>How to use frames and frame slots to store values local to an activation? {@link com.oracle.truffle.api.test.FrameTest}</li>
+ * <li>How to use type specialization and speculation for frame slots? {@link com.oracle.truffle.api.test.FrameSlotTypeSpecializationTest}</li>
+ * <li>How to use type specialization and speculation for node return values? {@link com.oracle.truffle.api.test.ReturnTypeSpecializationTest}</li>
+ * </ul>
+ *
+ * </p>
+ *
+ */
+package com.oracle.truffle.api.test;
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/Arguments.java	Wed Dec 19 10:01:08 2012 +0100
@@ -0,0 +1,46 @@
+/*
+ * 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;
+
+/**
+ * Base class for arguments passed to guest language methods via the
+ * {@link CallTarget#call(com.oracle.truffle.api.frame.PackedFrame, Arguments)} method. A guest language create a
+ * subclass with immutable fields representing the arguments passed to a guest language method. The {@link Arguments}
+ * object must be created immediately before a method call and it must not be stored in a field or cast to
+ * {@link java.lang.Object}.
+ */
+public class Arguments {
+
+    /**
+     * Constant that can be used as an argument to
+     * {@link CallTarget#call(com.oracle.truffle.api.frame.PackedFrame, Arguments)} in case no arguments should be
+     * supplied.
+     */
+    public static final Arguments EMPTY_ARGUMENTS = new Arguments();
+
+    /**
+     * Constructs an empty {@link Arguments} instance. Guest languages should create a subclass to specify their own arguments.
+     */
+    protected Arguments() {
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CallTarget.java	Wed Dec 19 10:01:08 2012 +0100
@@ -0,0 +1,66 @@
+/*
+ * 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;
+
+import com.oracle.truffle.api.frame.*;
+
+/**
+ * Represents the target of a call. Instances of this interface can be created using the
+ * {@link TruffleRuntime#createCallTarget(com.oracle.truffle.api.nodes.RootNode, FrameDescriptor)} method.
+ */
+public abstract class CallTarget {
+
+    /**
+     * Calls this target as a root method and without arguments.
+     * @return the return result of the call
+     */
+    public final Object call() {
+        return call(null, Arguments.EMPTY_ARGUMENTS);
+    }
+
+    /**
+     * Calls this target with a caller frame and no arguments.
+     * @param caller the caller frame
+     * @return the return result of the call
+     */
+    public final Object call(PackedFrame caller) {
+        return call(caller, Arguments.EMPTY_ARGUMENTS);
+    }
+
+    /**
+     * Calls this target as a root method passing arguments.
+     * @param arguments the arguments that should be passed to the callee
+     * @return the return result of the call
+     */
+    public final Object call(Arguments arguments) {
+        return call(null, arguments);
+    }
+
+    /**
+     * Calls this target passing a caller frame and arguments.
+     * @param caller the caller frame
+     * @param arguments the arguments that should be passed to the callee
+     * @return the return result of the call
+     */
+    public abstract Object call(PackedFrame caller, Arguments arguments);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/Truffle.java	Wed Dec 19 10:01:08 2012 +0100
@@ -0,0 +1,47 @@
+/*
+ * 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;
+
+import com.oracle.truffle.api.impl.*;
+
+/**
+ * Class for obtaining the Truffle runtime singleton object of this virtual machine.
+ */
+public class Truffle {
+
+    private static TruffleRuntime runtime;
+
+    private static native TruffleRuntime initializeRuntime();
+
+    public static TruffleRuntime getRuntime() {
+        return runtime;
+    }
+
+    static {
+        try {
+            runtime = initializeRuntime();
+        } catch (UnsatisfiedLinkError e) {
+            runtime = new DefaultTruffleRuntime();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleRuntime.java	Wed Dec 19 10:01:08 2012 +0100
@@ -0,0 +1,52 @@
+/*
+ * 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;
+
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * Interface representing a Truffle runtime object. The runtime is responsible for creating call targets and performing optimizations for them.
+ */
+public interface TruffleRuntime {
+    /**
+     * Name describing this runtime implementation for debugging purposes.
+     * @return the name as a String
+     */
+    String getName();
+
+    /**
+     * Creates a new call target for a given root node.
+     * @param rootNode the root node whose {@link RootNode#execute(com.oracle.truffle.api.frame.VirtualFrame)} method represents the entry point
+     * @return the new call target object
+     */
+    CallTarget createCallTarget(RootNode rootNode);
+
+    /**
+     * Creates a new call target for a given root node and a given frame descriptor.
+     * @param rootNode the root node whose {@link RootNode#execute(com.oracle.truffle.api.frame.VirtualFrame)} method represents the entry point
+     * @param frameDescriptor the descriptor used for creating a new frame at each invocation
+     * @return the new call target object
+     */
+    CallTarget createCallTarget(RootNode rootNode, FrameDescriptor frameDescriptor);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/DefaultTypeConversion.java	Wed Dec 19 10:01:08 2012 +0100
@@ -0,0 +1,49 @@
+/*
+ * 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.frame;
+
+/**
+ * Default type conversion semantics where a conversion is without changing any data.
+ */
+public final class DefaultTypeConversion implements TypeConversion {
+
+    private static DefaultTypeConversion instance = new DefaultTypeConversion();
+
+    public static TypeConversion getInstance() {
+        return instance;
+    }
+
+    private DefaultTypeConversion() {
+
+    }
+
+    @Override
+    public Class< ? > getTopType() {
+        return Object.class;
+    }
+
+    @Override
+    public Object convertTo(Class< ? > targetType, Object value) {
+        return value;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/Frame.java	Wed Dec 19 10:01:08 2012 +0100
@@ -0,0 +1,135 @@
+/*
+ * 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.frame;
+
+import com.oracle.truffle.api.*;
+
+/**
+ * Represents a frame containing values of local variables of the guest language. Instances of this type must not be
+ * stored in a field or cast to {@link java.lang.Object}.
+ */
+public interface Frame {
+
+    /**
+     * @return the arguments used when calling this method
+     */
+    Arguments getArguments();
+
+    /**
+     * Read access to a local variable of type {@link Object}.
+     *
+     * @param slot the slot of the local variable
+     * @return the current value of the local variable
+     */
+    Object getObject(FrameSlot slot);
+
+    /**
+     * Write access to a local variable of type {@link Object}.
+     *
+     * @param slot the slot of the local variable
+     * @param value the new value of the local variable
+     */
+    void setObject(FrameSlot slot, Object value);
+
+    /**
+     * Read access to a local variable of type boolean.
+     *
+     * @param slot the slot of the local variable
+     * @return the current value of the local variable
+     */
+    boolean getBoolean(FrameSlot slot);
+
+    /**
+     * Write access to a local variable of type boolean.
+     *
+     * @param slot the slot of the local variable
+     * @param value the new value of the local variable
+     */
+    void setBoolean(FrameSlot slot, boolean value);
+
+    /**
+     * Read access to a local variable of type int.
+     *
+     * @param slot the slot of the local variable
+     * @return the current value of the local variable
+     */
+    int getInt(FrameSlot slot);
+
+    /**
+     * Write access to a local variable of type int.
+     *
+     * @param slot the slot of the local variable
+     * @param value the new value of the local variable
+     */
+    void setInt(FrameSlot slot, int value);
+
+    /**
+     * Read access to a local variable of type long.
+     *
+     * @param slot the slot of the local variable
+     * @return the current value of the local variable
+     */
+    long getLong(FrameSlot slot);
+
+    /**
+     * Write access to a local variable of type long.
+     *
+     * @param slot the slot of the local variable
+     * @param value the new value of the local variable
+     */
+    void setLong(FrameSlot slot, long value);
+
+    /**
+     * Read access to a local variable of type float.
+     *
+     * @param slot the slot of the local variable
+     * @return the current value of the local variable
+     */
+    float getFloat(FrameSlot slot);
+
+    /**
+     * Write access to a local variable of type float.
+     *
+     * @param slot the slot of the local variable
+     * @param value the new value of the local variable
+     */
+    void setFloat(FrameSlot slot, float value);
+
+    /**
+     * Read access to a local variable of type double.
+     *
+     * @param slot the slot of the local variable
+     * @return the current value of the local variable
+     */
+    double getDouble(FrameSlot slot);
+
+    /**
+     * Write access to a local variable of type double.
+     *
+     * @param slot the slot of the local variable
+     * @param value the new value of the local variable
+     */
+    void setDouble(FrameSlot slot, double value);
+
+    void updateToLatestVersion();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameDescriptor.java	Wed Dec 19 10:01:08 2012 +0100
@@ -0,0 +1,201 @@
+/*
+ * 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.frame;
+
+import java.util.*;
+
+/**
+ * Descriptor of the slots of frame objects. Multiple frame instances are associated with one such descriptor.
+ */
+public final class FrameDescriptor {
+
+    protected final TypeConversion typeConversion;
+    private final ArrayList<FrameSlotImpl> slots;
+    private FrameVersionImpl lastVersion;
+    private final HashMap<String, FrameSlotImpl> nameToSlotMap;
+
+    public FrameDescriptor() {
+        this(DefaultTypeConversion.getInstance());
+    }
+
+    public FrameDescriptor(TypeConversion typeConversion) {
+        this.typeConversion = typeConversion;
+        slots = new ArrayList<>();
+        nameToSlotMap = new HashMap<>();
+        lastVersion = new FrameVersionImpl();
+    }
+
+    public FrameSlot addFrameSlot(String name) {
+        return addFrameSlot(name, typeConversion.getTopType());
+    }
+
+    public FrameSlot addFrameSlot(String name, Class<?> type) {
+        assert !nameToSlotMap.containsKey(name);
+        FrameSlotImpl slot = new FrameSlotImpl(this, name, slots.size(), type);
+        slots.add(slot);
+        nameToSlotMap.put(name, slot);
+        return slot;
+    }
+
+    public FrameSlot findFrameSlot(String name) {
+        return nameToSlotMap.get(name);
+    }
+
+    public FrameSlot findOrAddFrameSlot(String name) {
+        FrameSlot result = findFrameSlot(name);
+        if (result != null) {
+            return result;
+        }
+        return addFrameSlot(name);
+    }
+
+    public FrameVersion getCurrentVersion() {
+        return lastVersion;
+    }
+
+    public int getSize() {
+        return slots.size();
+    }
+
+    public List< ? extends FrameSlot> getSlots() {
+        return Collections.unmodifiableList(slots);
+    }
+
+    protected void appendVersion(FrameVersionImpl newVersion) {
+        lastVersion.next = newVersion;
+        lastVersion = newVersion;
+    }
+}
+
+class FrameVersionImpl implements FrameVersion {
+
+    protected FrameVersionImpl next;
+
+    @Override
+    public final FrameVersion getNext() {
+        return next;
+    }
+}
+
+class TypeChangeFrameVersionImpl extends FrameVersionImpl implements FrameVersion.TypeChange {
+
+    private final FrameSlotImpl slot;
+    private final Class< ? > oldType;
+    private final Class< ? > newType;
+
+    protected TypeChangeFrameVersionImpl(FrameSlotImpl slot, Class< ? > oldType, Class< ? > newType) {
+        this.slot = slot;
+        this.oldType = oldType;
+        this.newType = newType;
+    }
+
+    @Override
+    public final void applyTransformation(Frame frame) {
+        Object value = slot.getValue(oldType, frame);
+        slot.setValue(newType, frame, value);
+    }
+}
+
+class FrameSlotImpl implements FrameSlot {
+
+    private final FrameDescriptor descriptor;
+    private final String name;
+    private final int index;
+    private Class< ? > type;
+    private ArrayList<FrameSlotTypeListener> listeners;
+
+    protected FrameSlotImpl(FrameDescriptor descriptor, String name, int index, Class< ? > type) {
+        this.descriptor = descriptor;
+        this.name = name;
+        this.index = index;
+        this.type = type;
+        assert type != null;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public int getIndex() {
+        return index;
+    }
+
+    public Class< ? > getType() {
+        return type;
+    }
+
+    protected Object getValue(Class< ? > accessType, Frame frame) {
+        if (accessType == Integer.class) {
+            return frame.getInt(this);
+        } else if (accessType == Long.class) {
+            return frame.getLong(this);
+        } else if (accessType == Float.class) {
+            return frame.getFloat(this);
+        } else if (accessType == Double.class) {
+            return frame.getDouble(this);
+        } else {
+            return frame.getObject(this);
+        }
+    }
+
+    protected void setValue(Class< ? > accessType, Frame frame, Object value) {
+        Object newValue = descriptor.typeConversion.convertTo(accessType, value);
+        if (accessType == Integer.class) {
+            frame.setInt(this, (Integer) newValue);
+        } else if (accessType == Long.class) {
+            frame.setLong(this, (Long) newValue);
+        } else if (accessType == Float.class) {
+            frame.setFloat(this, (Float) newValue);
+        } else if (accessType == Double.class) {
+            frame.setDouble(this, (Double) newValue);
+        } else {
+            frame.setObject(this, newValue);
+        }
+    }
+
+    public void setType(final Class< ? > type) {
+        final Class< ? > oldType = this.type;
+        this.type = type;
+        ArrayList<FrameSlotTypeListener> oldListeners = this.listeners;
+        this.listeners = null;
+        if (oldListeners != null) {
+            for (FrameSlotTypeListener listener : oldListeners) {
+                listener.typeChanged(this, oldType);
+            }
+        }
+        descriptor.appendVersion(new TypeChangeFrameVersionImpl(this, oldType, type));
+    }
+
+    @Override
+    public String toString() {
+        return "[" + index + "," + name + "]";
+    }
+
+    @Override
+    public void registerOneShotTypeListener(FrameSlotTypeListener listener) {
+        if (listeners == null) {
+            listeners = new ArrayList<>();
+        }
+        listeners.add(listener);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameSlot.java	Wed Dec 19 10:01:08 2012 +0100
@@ -0,0 +1,34 @@
+/*
+ * 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.frame;
+
+/**
+ * A slot in a frame that can store a value of a given type.
+ */
+public interface FrameSlot {
+    String getName();
+    int getIndex();
+    Class< ? > getType();
+    void setType(Class< ? > type);
+    void registerOneShotTypeListener(FrameSlotTypeListener listener);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameSlotTypeListener.java	Wed Dec 19 10:01:08 2012 +0100
@@ -0,0 +1,30 @@
+/*
+ * 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.frame;
+
+/**
+ * Listener for the event of a type change of a frame slot.
+ */
+public interface FrameSlotTypeListener {
+    void typeChanged(FrameSlot slot, Class< ? > oldType);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameVersion.java	Wed Dec 19 10:01:08 2012 +0100
@@ -0,0 +1,41 @@
+/*
+ * 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.frame;
+
+/**
+ * Represents a specific version of a frame.
+ */
+public interface FrameVersion {
+
+    FrameVersion getNext();
+
+    public interface Resize {
+
+        int getNewSize();
+    }
+
+    public interface TypeChange {
+
+        void applyTransformation(Frame frame);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/MaterializedFrame.java	Wed Dec 19 10:01:08 2012 +0100
@@ -0,0 +1,32 @@
+/*
+ * 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.frame;
+
+/**
+ * Represents a materialized frame containing values of local variables of the guest language. It can be created using
+ * the {@link VirtualFrame#materialize()} method. Instances of this type are the only frame instances that may be stored
+ * in fields or cast to {@link java.lang.Object}. In contrast to a {@link VirtualFrame}, a {@link MaterializedFrame} can
+ * no longer be packed and it also does not provide access to the caller frame.
+ */
+public interface MaterializedFrame extends Frame {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/NativeFrame.java	Wed Dec 19 10:01:08 2012 +0100
@@ -0,0 +1,129 @@
+/*
+ * 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.frame;
+
+import com.oracle.truffle.api.*;
+
+/**
+ * Represents a native frame without any local variables. Instances of this type must not be stored in a field or cast
+ * to {@link java.lang.Object}.
+ */
+public class NativeFrame implements VirtualFrame, PackedFrame {
+
+    private PackedFrame caller;
+    private Arguments arguments;
+
+    public NativeFrame(PackedFrame caller, Arguments arguments) {
+        this.caller = caller;
+        this.arguments = arguments;
+    }
+
+    @Override
+    public Arguments getArguments() {
+        return arguments;
+    }
+
+    @Override
+    public Object getObject(FrameSlot slot) {
+        throw new UnsupportedOperationException("native frame");
+    }
+
+    @Override
+    public void setObject(FrameSlot slot, Object value) {
+        throw new UnsupportedOperationException("native frame");
+    }
+
+    @Override
+    public boolean getBoolean(FrameSlot slot) {
+        throw new UnsupportedOperationException("native frame");
+    }
+
+    @Override
+    public void setBoolean(FrameSlot slot, boolean value) {
+        throw new UnsupportedOperationException("native frame");
+    }
+
+    @Override
+    public int getInt(FrameSlot slot) {
+        throw new UnsupportedOperationException("native frame");
+    }
+
+    @Override
+    public void setInt(FrameSlot slot, int value) {
+        throw new UnsupportedOperationException("native frame");
+    }
+
+    @Override
+    public long getLong(FrameSlot slot) {
+        throw new UnsupportedOperationException("native frame");
+    }
+
+    @Override
+    public void setLong(FrameSlot slot, long value) {
+        throw new UnsupportedOperationException("native frame");
+    }
+
+    @Override
+    public float getFloat(FrameSlot slot) {
+        throw new UnsupportedOperationException("native frame");
+    }
+
+    @Override
+    public void setFloat(FrameSlot slot, float value) {
+        throw new UnsupportedOperationException("native frame");
+    }
+
+    @Override
+    public double getDouble(FrameSlot slot) {
+        throw new UnsupportedOperationException("native frame");
+    }
+
+    @Override
+    public void setDouble(FrameSlot slot, double value) {
+        throw new UnsupportedOperationException("native frame");
+    }
+
+    @Override
+    public PackedFrame pack() {
+        return this;
+    }
+
+    @Override
+    public PackedFrame getCaller() {
+        return caller;
+    }
+
+    @Override
+    public MaterializedFrame materialize() {
+        throw new UnsupportedOperationException("native frame");
+    }
+
+    @Override
+    public VirtualFrame unpack() {
+        return this;
+    }
+
+    @Override
+    public void updateToLatestVersion() {
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/PackedFrame.java	Wed Dec 19 10:01:08 2012 +0100
@@ -0,0 +1,37 @@
+/*
+ * 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.frame;
+
+/**
+ * Represents a packed frame that represents a virtual frame. A packed frame instance can be retrieved with the
+ * {@link VirtualFrame#pack()} method. It can be converted back into a virtual frame using {@link PackedFrame#unpack()}.
+ * Instances of this type must not be stored in a field or cast to {@link java.lang.Object}.
+ */
+public interface PackedFrame {
+
+    /**
+     * Unpacks this frame and converts it back to a virtual frame.
+     * @return the virtual frame that was the content of this packed frame
+     */
+    VirtualFrame unpack();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/TypeConversion.java	Wed Dec 19 10:01:08 2012 +0100
@@ -0,0 +1,32 @@
+/*
+ * 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.frame;
+
+/**
+ * Interface for defining type conversions for frame slot values.
+ */
+public interface TypeConversion {
+    Class<?> getTopType();
+
+    Object convertTo(Class<?> targetType, Object value);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/VirtualFrame.java	Wed Dec 19 10:01:08 2012 +0100
@@ -0,0 +1,60 @@
+/*
+ * 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.frame;
+
+import com.oracle.truffle.api.*;
+
+/**
+ * Represents a frame containing values of local variables of the guest language. Instances of this type must not be
+ * stored in a field or cast to {@link java.lang.Object}. If this is necessary, the frame must be explicitly converted
+ * into a materialized frame using the {@link VirtualFrame#materialize()} method. Whenever fast access to the local
+ * variables of a frame is no longer necessary, a virtual frame should be converted into a packed frame using the
+ * {@link VirtualFrame#pack()} method.
+ */
+public interface VirtualFrame extends Frame {
+
+    /**
+     * Converts this virtual frame into a packed frame that has no longer direct access to the local variables. This
+     * packing is an important hint to the Truffle optimizer and therefore passing around a {@link PackedFrame} should
+     * be preferred over passing around a {@link VirtualFrame} when the probability that an unpacking will occur is low.
+     *
+     * @return the packed frame
+     */
+    PackedFrame pack();
+
+    /**
+     * Accesses the caller frame passed in via {@link CallTarget#call}. To get full access, it must be first unpacked
+     * using {@link PackedFrame#unpack()}.
+     *
+     * @return the caller frame or null if this was a root method call
+     */
+    PackedFrame getCaller();
+
+    /**
+     * Materializes this frame, which allows it to be stored in a field or cast to {@link java.lang.Object}. The frame
+     * however looses the ability to be packed or to access the caller frame.
+     *
+     * @return the new materialized frame
+     */
+    MaterializedFrame materialize();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultCallTarget.java	Wed Dec 19 10:01:08 2012 +0100
@@ -0,0 +1,49 @@
+/*
+ * 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.impl;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+
+final class DefaultCallTarget extends CallTarget {
+
+    protected final RootNode rootNode;
+    protected final FrameDescriptor frameDescriptor;
+
+    DefaultCallTarget(RootNode function, FrameDescriptor frameDescriptor) {
+        this.rootNode = function;
+        this.frameDescriptor = frameDescriptor;
+    }
+
+    @Override
+    public String toString() {
+        return "DefaultCallTarget " + rootNode;
+    }
+
+    @Override
+    public Object call(PackedFrame caller, Arguments args) {
+        VirtualFrame frame = new DefaultVirtualFrame(frameDescriptor, caller, args);
+        return rootNode.execute(frame);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultMaterializedFrame.java	Wed Dec 19 10:01:08 2012 +0100
@@ -0,0 +1,104 @@
+/*
+ * 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.impl;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+
+final class DefaultMaterializedFrame implements MaterializedFrame {
+    private final DefaultVirtualFrame wrapped;
+
+    protected DefaultMaterializedFrame(DefaultVirtualFrame wrapped) {
+        this.wrapped = wrapped;
+    }
+
+    @Override
+    public Arguments getArguments() {
+        return wrapped.getArguments();
+    }
+
+    @Override
+    public Object getObject(FrameSlot slot) {
+        return wrapped.getObject(slot);
+    }
+
+    @Override
+    public void setObject(FrameSlot slot, Object value) {
+        wrapped.setObject(slot, value);
+    }
+
+    @Override
+    public boolean getBoolean(FrameSlot slot) {
+        return wrapped.getBoolean(slot);
+    }
+
+    @Override
+    public void setBoolean(FrameSlot slot, boolean value) {
+        wrapped.setBoolean(slot, value);
+    }
+
+    @Override
+    public int getInt(FrameSlot slot) {
+        return wrapped.getInt(slot);
+    }
+
+    @Override
+    public void setInt(FrameSlot slot, int value) {
+        wrapped.setInt(slot, value);
+    }
+
+    @Override
+    public long getLong(FrameSlot slot) {
+        return wrapped.getLong(slot);
+    }
+
+    @Override
+    public void setLong(FrameSlot slot, long value) {
+        wrapped.setLong(slot, value);
+    }
+
+    @Override
+    public float getFloat(FrameSlot slot) {
+        return wrapped.getFloat(slot);
+    }
+
+    @Override
+    public void setFloat(FrameSlot slot, float value) {
+        wrapped.setFloat(slot, value);
+    }
+
+    @Override
+    public double getDouble(FrameSlot slot) {
+        return wrapped.getDouble(slot);
+    }
+
+    @Override
+    public void setDouble(FrameSlot slot, double value) {
+        wrapped.setDouble(slot, value);
+    }
+
+    @Override
+    public void updateToLatestVersion() {
+        wrapped.updateToLatestVersion();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultPackedFrame.java	Wed Dec 19 10:01:08 2012 +0100
@@ -0,0 +1,38 @@
+/*
+ * 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.impl;
+
+import com.oracle.truffle.api.frame.*;
+
+final class DefaultPackedFrame implements PackedFrame {
+    private final DefaultVirtualFrame wrapped;
+
+    protected DefaultPackedFrame(DefaultVirtualFrame wrapped) {
+        this.wrapped = wrapped;
+    }
+
+    @Override
+    public VirtualFrame unpack() {
+        return wrapped;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultTruffleRuntime.java	Wed Dec 19 10:01:08 2012 +0100
@@ -0,0 +1,48 @@
+/*
+ * 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.impl;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * Default implementation of the Truffle runtime if the virtual machine does not provide a better performing alternative.
+ */
+public final class DefaultTruffleRuntime implements TruffleRuntime {
+
+    @Override
+    public String getName() {
+        return "Default Truffle Runtime";
+    }
+
+    @Override
+    public CallTarget createCallTarget(RootNode rootNode, FrameDescriptor frameDescriptor) {
+        return new DefaultCallTarget(rootNode, frameDescriptor);
+    }
+
+    @Override
+    public CallTarget createCallTarget(RootNode rootNode) {
+        return createCallTarget(rootNode, new FrameDescriptor());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultVirtualFrame.java	Wed Dec 19 10:01:08 2012 +0100
@@ -0,0 +1,194 @@
+/*
+ * 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.impl;
+
+import java.util.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+
+final class DefaultVirtualFrame implements VirtualFrame {
+
+    private static final Object UNDEFINED_OBJECT = null;
+    private static final Boolean UNDEFINED_BOOLEAN = false;
+    private static final Integer UNDEFINED_INTEGER = 0;
+    private static final Float UNDEFINED_FLOAT = 0.0f;
+    private static final Long UNDEFINED_LONG = 0L;
+    private static final Double UNDEFINED_DOUBLE = 0.0d;
+
+    private final FrameDescriptor descriptor;
+    private final PackedFrame caller;
+    private final Arguments arguments;
+    private FrameVersion currentVersion;
+    protected Object[] locals;
+    protected Class[] tags;
+
+    DefaultVirtualFrame(FrameDescriptor descriptor, PackedFrame caller, Arguments arguments) {
+        this.descriptor = descriptor;
+        this.caller = caller;
+        this.arguments = arguments;
+        this.currentVersion = descriptor.getCurrentVersion();
+        this.locals = new Object[descriptor.getSize()];
+        // The tags are only needed for assertion checking, so initialize the field only when assertions are enabled
+        assert (this.tags = new Class[descriptor.getSize()]) != null;
+    }
+
+    @Override
+    public Arguments getArguments() {
+        return arguments;
+    }
+
+    @Override
+    public PackedFrame getCaller() {
+        return caller;
+    }
+
+    @Override
+    public PackedFrame pack() {
+        return new DefaultPackedFrame(this);
+    }
+
+    @Override
+    public MaterializedFrame materialize() {
+        return new DefaultMaterializedFrame(this);
+    }
+
+    @Override
+    public Object getObject(FrameSlot slot) {
+        return get(slot, Object.class, UNDEFINED_OBJECT);
+    }
+
+    @Override
+    public void setObject(FrameSlot slot, Object value) {
+        set(slot, Object.class, value);
+    }
+
+    @Override
+    public boolean getBoolean(FrameSlot slot) {
+        return (Boolean) get(slot, Float.class, UNDEFINED_BOOLEAN);
+    }
+
+    @Override
+    public void setBoolean(FrameSlot slot, boolean value) {
+        set(slot, Float.class, value);
+    }
+
+    @Override
+    public int getInt(FrameSlot slot) {
+        return (Integer) get(slot, Integer.class, UNDEFINED_INTEGER);
+    }
+
+    @Override
+    public void setInt(FrameSlot slot, int value) {
+        set(slot, Integer.class, value);
+    }
+
+    @Override
+    public long getLong(FrameSlot slot) {
+        return (Long) get(slot, Long.class, UNDEFINED_LONG);
+    }
+
+    @Override
+    public void setLong(FrameSlot slot, long value) {
+        set(slot, Long.class, value);
+    }
+
+    @Override
+    public float getFloat(FrameSlot slot) {
+        return (Float) get(slot, Float.class, UNDEFINED_FLOAT);
+    }
+
+    @Override
+    public void setFloat(FrameSlot slot, float value) {
+        set(slot, Float.class, value);
+    }
+
+    @Override
+    public double getDouble(FrameSlot slot) {
+        return (Double) get(slot, Double.class, UNDEFINED_DOUBLE);
+    }
+
+    @Override
+    public void setDouble(FrameSlot slot, double value) {
+        set(slot, Double.class, value);
+    }
+
+    private Object get(FrameSlot slot, Class< ? > accessType, Object defaultValue) {
+        Object value = locals[slot.getIndex()];
+        assert verifyGet(slot, accessType, value);
+        if (value == null) {
+            return defaultValue;
+        } else {
+            return value;
+        }
+    }
+
+    private boolean verifyGet(FrameSlot slot, Class< ? > accessType, Object value) {
+        assert descriptor.getSlots().get(slot.getIndex()) == slot;
+        Class< ? > tag = tags[slot.getIndex()];
+        if (value == null) {
+            assert tag == null || tag == Object.class;
+        } else {
+            assert tag == accessType : "Local variable " + slot + " was written with set" + tag.getSimpleName() + ", but is read with get" + accessType.getSimpleName();
+        }
+        return true;
+    }
+
+    private void set(FrameSlot slot, Class< ? > accessType, Object value) {
+        assert verifySet(slot, accessType, value);
+        locals[slot.getIndex()] = value;
+    }
+
+    private boolean verifySet(FrameSlot slot, Class< ? > accessType, Object value) {
+        assert descriptor.getSlots().get(slot.getIndex()) == slot;
+        tags[slot.getIndex()] = accessType;
+        assert accessType.isAssignableFrom(slot.getType()) : "Local variable " + slot + ": " + accessType + " is not assignable from " + slot.getType();
+        if (value == null) {
+            assert accessType == Object.class;
+        } else {
+            assert slot.getType().isAssignableFrom(value.getClass()) : "Local variable " + slot + ": " + slot.getType() + " is not assignable from " + value.getClass();
+        }
+        return true;
+    }
+
+    @Override
+    public void updateToLatestVersion() {
+        if (currentVersion.getNext() != null) {
+            doUpdateToLatestVersion();
+        }
+    }
+
+    private void doUpdateToLatestVersion() {
+        FrameVersion version = currentVersion;
+        while (version.getNext() != null) {
+            version = version.getNext();
+            if (version instanceof FrameVersion.TypeChange) {
+                ((FrameVersion.TypeChange) version).applyTransformation(this);
+            } else if (version instanceof FrameVersion.Resize) {
+                int newSize = ((FrameVersion.Resize) version).getNewSize();
+                locals = Arrays.copyOf(locals, newSize);
+            }
+        }
+        currentVersion = version;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/intrinsics/ExactMath.java	Wed Dec 19 10:01:08 2012 +0100
@@ -0,0 +1,91 @@
+/*
+ * 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.intrinsics;
+
+/**
+ * This class contains methods that will be part of java.lang.Math starting with JDK 8. Until JDK 8 is release, we
+ * duplicate them here because they are generally useful for dynamic language implementations.
+ */
+public class ExactMath {
+
+    public static int addExact(int x, int y) {
+        int r = x + y;
+        // HD 2-12 Overflow iff both arguments have the opposite sign of the result
+        if (((x ^ r) & (y ^ r)) < 0) {
+            throw new ArithmeticException("integer overflow");
+        }
+        return r;
+    }
+
+    public static long addExact(long x, long y) {
+        long r = x + y;
+        // HD 2-12 Overflow iff both arguments have the opposite sign of the result
+        if (((x ^ r) & (y ^ r)) < 0) {
+            throw new ArithmeticException("long overflow");
+        }
+        return r;
+    }
+
+    public static int subtractExact(int x, int y) {
+        int r = x - y;
+        // HD 2-12 Overflow iff the arguments have different signs and
+        // the sign of the result is different than the sign of x
+        if (((x ^ y) & (x ^ r)) < 0) {
+            throw new ArithmeticException("integer overflow");
+        }
+        return r;
+    }
+
+    public static long subtractExact(long x, long y) {
+        long r = x - y;
+        // HD 2-12 Overflow iff the arguments have different signs and
+        // the sign of the result is different than the sign of x
+        if (((x ^ y) & (x ^ r)) < 0) {
+            throw new ArithmeticException("long overflow");
+        }
+        return r;
+    }
+
+    public static int multiplyExact(int x, int y) {
+        long r = (long) x * (long) y;
+        if ((int) r != r) {
+            throw new ArithmeticException("long overflow");
+        }
+        return (int) r;
+    }
+
+    public static long multiplyExact(long x, long y) {
+        long r = x * y;
+        long ax = Math.abs(x);
+        long ay = Math.abs(y);
+        if (((ax | ay) >>> 31 != 0)) {
+            // Some bits greater than 2^31 that might cause overflow
+            // Check the result using the divide operator
+            // and check for the special case of Long.MIN_VALUE * -1
+            if (((y != 0) && (r / y != x)) || (x == Long.MIN_VALUE && y == -1)) {
+                throw new ArithmeticException("long overflow");
+            }
+        }
+        return r;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/intrinsics/TruffleIntrinsics.java	Wed Dec 19 10:01:08 2012 +0100
@@ -0,0 +1,45 @@
+/*
+ * 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.intrinsics;
+
+/**
+ * Predefined Truffle intrinsics that allow direct influence of the generated machine code.
+ */
+public final class TruffleIntrinsics {
+
+    /**
+     * Specifies that the compiler should put a deoptimization point at this position that will continue execution in the interpreter.
+     * Should be used to cut off cold paths that should not be part of the compiled machine code.
+     */
+    public static void deoptimize() {
+    }
+
+    /**
+     * Checks whether the Thread has been interrupted in the interpreter in order to avoid endless loops. The compiled code may choose a more efficient implementation.
+     */
+    public static void checkThreadInterrupted() {
+        if (Thread.currentThread().isInterrupted()) {
+            throw new RuntimeException("Timeout");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/ExplodeLoop.java	Wed Dec 19 10:01:08 2012 +0100
@@ -0,0 +1,33 @@
+/*
+ * 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.nodes;
+
+import java.lang.annotation.*;
+
+/**
+ * Specifies for a method that the loops with constant number of invocations should be fully unrolled.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface ExplodeLoop {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/GraphPrintVisitor.java	Wed Dec 19 10:01:08 2012 +0100
@@ -0,0 +1,385 @@
+/*
+ * 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.nodes;
+
+import java.io.*;
+import java.lang.annotation.*;
+import java.lang.reflect.*;
+import java.net.*;
+import java.util.*;
+
+import javax.xml.parsers.*;
+import javax.xml.transform.*;
+import javax.xml.transform.dom.*;
+import javax.xml.transform.stream.*;
+
+import org.w3c.dom.*;
+
+/**
+ * Utility class for creating output for the ideal graph visualizer.
+ */
+public class GraphPrintVisitor {
+
+    public static final String GraphVisualizerAddress = "127.0.0.1";
+    public static final int GraphVisualizerPort = 4444;
+
+    private Document dom;
+    private Map<Object, Element> nodeMap;
+    private List<Element> edgeList;
+    private Map<Object, Element> prevNodeMap;
+    private int id;
+    private Element graphDocument;
+    private Element groupElement;
+    private Element graphElement;
+    private Element nodesElement;
+    private Element edgesElement;
+
+    public GraphPrintVisitor() {
+        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+        try {
+            DocumentBuilder db = dbf.newDocumentBuilder();
+
+            dom = db.newDocument();
+        } catch (ParserConfigurationException ex) {
+            System.out.println("Error while trying to instantiate DocumentBuilder " + ex);
+        }
+
+        graphDocument = dom.createElement("graphDocument");
+        dom.appendChild(graphDocument);
+    }
+
+    public GraphPrintVisitor beginGroup(String groupName) {
+        groupElement = dom.createElement("group");
+        graphDocument.appendChild(groupElement);
+        Element properties = dom.createElement("properties");
+        groupElement.appendChild(properties);
+
+        if (!groupName.isEmpty()) {
+            // set group name
+            Element propName = dom.createElement("p");
+            propName.setAttribute("name", "name");
+            propName.setTextContent(groupName);
+            properties.appendChild(propName);
+        }
+
+        // forget old nodes
+        nodeMap = prevNodeMap = null;
+        edgeList = null;
+
+        return this;
+    }
+
+    public GraphPrintVisitor beginGraph(String graphName) {
+        if (null == groupElement) {
+            beginGroup("");
+        } else if (null != prevNodeMap) {
+            // TODO: difference (create removeNode,removeEdge elements)
+        }
+
+        graphElement = dom.createElement("graph");
+        groupElement.appendChild(graphElement);
+        Element properties = dom.createElement("properties");
+        graphElement.appendChild(properties);
+        nodesElement = dom.createElement("nodes");
+        graphElement.appendChild(nodesElement);
+        edgesElement = dom.createElement("edges");
+        graphElement.appendChild(edgesElement);
+
+        // set graph name
+        Element propName = dom.createElement("p");
+        propName.setAttribute("name", "name");
+        propName.setTextContent(graphName);
+        properties.appendChild(propName);
+
+        // save old nodes
+        prevNodeMap = nodeMap;
+        nodeMap = new HashMap<>();
+        edgeList = new ArrayList<>();
+
+        return this;
+    }
+
+    @Override
+    public String toString() {
+        if (null != dom) {
+            try {
+                Transformer tr = TransformerFactory.newInstance().newTransformer();
+                tr.setOutputProperty(OutputKeys.INDENT, "yes");
+                tr.setOutputProperty(OutputKeys.METHOD, "xml");
+                tr.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
+
+                StringWriter strWriter = new StringWriter();
+                tr.transform(new DOMSource(dom), new StreamResult(strWriter));
+                return strWriter.toString();
+            } catch (TransformerException e) {
+                e.printStackTrace();
+            }
+        }
+        return "";
+    }
+
+    public void printToFile(File f) {
+        try {
+            Transformer tr = TransformerFactory.newInstance().newTransformer();
+            tr.setOutputProperty(OutputKeys.INDENT, "yes");
+            tr.setOutputProperty(OutputKeys.METHOD, "xml");
+            tr.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
+
+            tr.transform(new DOMSource(dom), new StreamResult(new FileOutputStream(f)));
+        } catch (TransformerException | FileNotFoundException e) {
+            e.printStackTrace();
+        }
+    }
+
+    public void printToSysout() {
+        try {
+            Transformer tr = TransformerFactory.newInstance().newTransformer();
+            tr.setOutputProperty(OutputKeys.INDENT, "yes");
+            tr.setOutputProperty(OutputKeys.METHOD, "xml");
+            tr.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
+
+            tr.transform(new DOMSource(dom), new StreamResult(System.out));
+        } catch (TransformerException e) {
+            e.printStackTrace();
+        }
+    }
+
+    public void printToNetwork() {
+        try {
+            Transformer tr = TransformerFactory.newInstance().newTransformer();
+            tr.setOutputProperty(OutputKeys.METHOD, "xml");
+
+            Socket socket = new Socket(GraphVisualizerAddress, GraphVisualizerPort);
+            BufferedOutputStream stream = new BufferedOutputStream(socket.getOutputStream(), 0x4000);
+            tr.transform(new DOMSource(dom), new StreamResult(stream));
+        } catch (TransformerException | IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    private String nextId() {
+        return String.valueOf(id++);
+    }
+
+    private String oldOrNextId(Object node) {
+        if (null != prevNodeMap && prevNodeMap.containsKey(node)) {
+            Element nodeElem = prevNodeMap.get(node);
+            return nodeElem.getAttribute("id");
+        } else {
+            return nextId();
+        }
+    }
+
+    protected Element getElementByObject(Object op) {
+        return nodeMap.get(op);
+    }
+
+    protected void createElementForNode(Object node) {
+        boolean exists = nodeMap.containsKey(node);
+        if (!exists || NodeUtil.findAnnotation(node.getClass(), GraphDuplicate.class) != null) {
+            Element nodeElem = dom.createElement("node");
+            nodeElem.setAttribute("id", !exists ? oldOrNextId(node) : nextId());
+            nodeMap.put(node, nodeElem);
+            Element properties = dom.createElement("properties");
+            nodeElem.appendChild(properties);
+            nodesElement.appendChild(nodeElem);
+
+            setNodeProperty(node, "name", node.getClass().getSimpleName().replaceFirst("Node$", ""));
+            NodeInfo nodeInfo = node.getClass().getAnnotation(NodeInfo.class);
+            if (nodeInfo != null && !nodeInfo.shortName().isEmpty()) {
+                setNodeProperty(node, "shortName", nodeInfo.shortName());
+            }
+            setNodeProperty(node, "nodeType", (Node.class.isAssignableFrom(node.getClass()) ? Node.class.getSimpleName() : "other"));
+            setNodeProperty(node, "nodeClass", node.getClass().getSimpleName());
+            copyDebugProperties(node); // TODO: may overwrite property "name"? (currently allowed)
+            readNodeProperties(node);
+        }
+    }
+
+    private Element getPropertyElement(Object node, String propertyName) {
+        Element nodeElem = getElementByObject(node);
+        Element propertiesElem = (Element) nodeElem.getElementsByTagName("properties").item(0);
+        if (propertiesElem == null) {
+            return null;
+        }
+
+        NodeList propList = propertiesElem.getElementsByTagName("p");
+        for (int i = 0; i < propList.getLength(); i++) {
+            Element p = (Element) propList.item(i);
+            if (propertyName.equals(p.getAttribute("name"))) {
+                return p;
+            }
+        }
+        return null;
+    }
+
+    protected void setNodeProperty(Object node, String propertyName, Object value) {
+        Element nodeElem = getElementByObject(node);
+        Element propElem = getPropertyElement(node, propertyName); // if property exists, replace its value
+        if (null == propElem) { // if property doesn't exist, create one
+            propElem = dom.createElement("p");
+            propElem.setAttribute("name", propertyName);
+            nodeElem.getElementsByTagName("properties").item(0).appendChild(propElem);
+        }
+        propElem.setTextContent(String.valueOf(value));
+    }
+
+    private void copyDebugProperties(Object node) {
+        if (node instanceof Node) {
+            Map<String, Object> debugProperties = ((Node) node).getDebugProperties();
+            for (Map.Entry<String, Object> property : debugProperties.entrySet()) {
+                setNodeProperty(node, property.getKey(), property.getValue());
+            }
+        }
+    }
+
+    private void readNodeProperties(Object node) {
+        Field[] fields = NodeUtil.getAllFields(node.getClass());
+        for (Field field : fields) {
+            if (Modifier.isStatic(field.getModifiers())) {
+                continue;
+            }
+            if (Node.class.isAssignableFrom(field.getType()) || (field.getType().getComponentType() != null && Node.class.isAssignableFrom(field.getType()))) {
+                continue;
+            }
+            String key = field.getName();
+            if (field.getAnnotation(HiddenField.class) == null && getPropertyElement(node, key) == null) {
+                try {
+                    field.setAccessible(true);
+                    Object value = field.get(node);
+                    setNodeProperty(node, key, value);
+                } catch (IllegalArgumentException | IllegalAccessException e) {
+                    assert false : e;
+                }
+            }
+        }
+    }
+
+    protected void connectNodes(Object a, Object b) {
+        if (nodeMap.get(a) == null || nodeMap.get(b) == null) {
+            return;
+        }
+
+        String fromId = nodeMap.get(a).getAttribute("id");
+        String toId = nodeMap.get(b).getAttribute("id");
+
+        // count existing to-edges
+        int count = 0;
+        for (Element e : edgeList) {
+            if (e.getAttribute("to").equals(toId)) {
+                ++count;
+            }
+        }
+
+        Element edgeElem = dom.createElement("edge");
+        edgeElem.setAttribute("from", fromId);
+        edgeElem.setAttribute("to", toId);
+        edgeElem.setAttribute("index", String.valueOf(count));
+        edgesElement.appendChild(edgeElem);
+        edgeList.add(edgeElem);
+    }
+
+    public GraphPrintVisitor visit(Object node) {
+        if (null == graphElement) {
+            beginGraph("truffle tree");
+        }
+
+        // if node is visited once again, skip
+        if (getElementByObject(node) == null || NodeUtil.findAnnotation(node.getClass(), GraphDuplicate.class) != null) {
+            visitAny(node);
+        }
+
+        return this;
+    }
+
+    private void visitAny(Object node) {
+        // respect node's custom handler
+        if (NodeUtil.findAnnotation(node.getClass(), NullGraphPrintHandler.class) != null) {
+            return;
+        }
+        if (NodeUtil.findAnnotation(node.getClass(), CustomGraphPrintHandler.class) != null) {
+            Class<? extends GraphPrintHandler> gpHandlerClass = NodeUtil.findAnnotation(node.getClass(), CustomGraphPrintHandler.class).handler();
+            try {
+                GraphPrintHandler gpHandler = gpHandlerClass.newInstance();
+                gpHandler.visit(node, new GraphPrintAdapter());
+            } catch (InstantiationException e) {
+                assert false;
+            } catch (IllegalAccessException e) {
+                assert false;
+            }
+            return;
+        }
+
+        // default handler
+        createElementForNode(node);
+
+        List<Object> children = NodeUtil.findNodeChildren(node);
+        for (Object child : children) {
+            if (child == null) {
+                continue;
+            } else if (child instanceof Node) {
+                visit(child);
+            } else {
+                continue;
+            }
+            connectNodes(node, child);
+        }
+    }
+
+    public class GraphPrintAdapter {
+        public void createElementForNode(Object node) {
+            GraphPrintVisitor.this.createElementForNode(node);
+        }
+        public void visit(Object node) {
+            GraphPrintVisitor.this.visit(node);
+        }
+        public void connectNodes(Object node, Object child) {
+            GraphPrintVisitor.this.connectNodes(node, child);
+        }
+        public void setNodeProperty(Object node, String propertyName, Object value) {
+            GraphPrintVisitor.this.setNodeProperty(node, propertyName, value);
+        }
+    }
+
+    public interface GraphPrintHandler {
+        void visit(Object node, GraphPrintAdapter gPrinter);
+    }
+
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.TYPE)
+    public @interface CustomGraphPrintHandler {
+        Class<? extends GraphPrintHandler> handler();
+    }
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.TYPE)
+    public @interface NullGraphPrintHandler {
+    }
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.TYPE)
+    public @interface GraphDuplicate {
+    }
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.FIELD)
+    public @interface HiddenField {
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java	Wed Dec 19 10:01:08 2012 +0100
@@ -0,0 +1,212 @@
+/*
+ * 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.nodes;
+
+import java.lang.annotation.*;
+import java.util.*;
+
+/**
+ * Abstract base class for all Truffle nodes.
+ */
+public abstract class Node implements Cloneable {
+
+    /**
+     * Utility constant representing an empty node array.
+     */
+    public static final Node[] EMPTY_ARRAY = new Node[0];
+
+    private Node parent;
+
+    /**
+     * Marks array fields that are children of this node.
+     */
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target({ElementType.FIELD})
+    public @interface Children {
+    }
+
+    /**
+     * Marks fields that represent child nodes of this node.
+     */
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target({ElementType.FIELD})
+    public @interface Child {
+    }
+
+    /**
+     * Method that updates the link to the parent in the array of specified new child nodes to this node.
+     *
+     * @param newChildren the array of new children whose parent should be updated
+     * @return the array of new children
+     */
+    protected final <T extends Node> T[] adoptChildren(T[] newChildren) {
+        if (newChildren != null) {
+            for (T n : newChildren) {
+                adoptChild(n);
+            }
+        }
+        return newChildren;
+    }
+
+    /**
+     * Method that updates the link to the parent in the specified new child node to this node.
+     *
+     * @param newChild the new child whose parent should be updated
+     * @return the new child
+     */
+    protected final <T extends Node> T adoptChild(T newChild) {
+        if (newChild != null) {
+            ((Node) newChild).parent = this;
+        }
+        return newChild;
+    }
+
+    /**
+     * Returns properties of this node interesting for debugging and can be overwritten by subclasses to add their own
+     * custom properties.
+     *
+     * @return the properties as a key/value hash map
+     */
+    public Map<String, Object> getDebugProperties() {
+        Map<String, Object> properties = new HashMap<>();
+        return properties;
+    }
+
+    /**
+     * The current parent node of this node.
+     *
+     * @return the parent node
+     */
+    public final Node getParent() {
+        return parent;
+    }
+
+    /**
+     * Replaces one child of this node with another node.
+     *
+     * @param oldChild the old child
+     * @param newChild the new child that should replace the old child
+     * @return the new child
+     */
+    public final <T extends Node> T replaceChild(T oldChild, T newChild) {
+        NodeUtil.replaceChild(this, oldChild, newChild);
+        adoptChild(newChild);
+        return newChild;
+    }
+
+    /**
+     * Replaces this node with another node.
+     *
+     * @param newNode the new node that is the replacement
+     * @param reason a description of the reason for the replacement
+     * @return the new node
+     */
+    @SuppressWarnings({"unchecked"})
+    public <T extends Node> T replace(T newNode, String reason) {
+        assert this.getParent() != null;
+        return (T) this.getParent().replaceChild(this, newNode);
+    }
+
+    /**
+     * Replaces this node with another node.
+     *
+     * @param newNode the new node that is the replacement
+     * @return the new node
+     */
+    public <T extends Node> T replace(T newNode) {
+        return replace(newNode, "");
+    }
+
+    /**
+     * Invokes the {@link NodeVisitor#visit(Node)} method for this node and recursively also for all child nodes.
+     *
+     * @param nodeVisitor the visitor
+     */
+    public final void accept(NodeVisitor nodeVisitor) {
+        if (nodeVisitor.visit(this)) {
+            for (Node child : this.getChildren()) {
+                if (child != null) {
+                    child.accept(nodeVisitor);
+                }
+            }
+        }
+    }
+
+    /**
+     * Iterator over the children of this node.
+     *
+     * @return the iterator
+     */
+    public final Iterable<Node> getChildren() {
+        final Node node = this;
+        return new Iterable<Node>() {
+
+            public Iterator<Node> iterator() {
+                return new NodeUtil.NodeIterator(node);
+            }
+        };
+    }
+
+    /**
+     * Creates a shallow copy of this node.
+     *
+     * @return the new copy
+     */
+    public Node copy() {
+        try {
+            return (Node) super.clone();
+        } catch (CloneNotSupportedException e) {
+            return null;
+        }
+    }
+
+    /**
+     * This method must never be called. It enforces that {@link Object#clone} is not directly called by subclasses.
+     * Use the {@link #copy()} method instead.
+     */
+    @Override
+    @Deprecated
+    protected final Object clone() throws CloneNotSupportedException {
+        throw new IllegalStateException("This method should never be called, use the copy method instead!");
+    }
+
+    /**
+     * Converts this node to a textual representation useful for debugging.
+     */
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder(getClass().getSimpleName());
+        Map<String, Object> properties = getDebugProperties();
+        boolean hasProperties = false;
+        for (Map.Entry<String, Object> entry : properties.entrySet()) {
+            sb.append(hasProperties ? "," : "<");
+            hasProperties = true;
+            sb.append(entry.getKey()).append("=").append(entry.getValue());
+        }
+        if (hasProperties) {
+            sb.append(">");
+        }
+        sb.append("@").append(Integer.toHexString(hashCode()));
+        return sb.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeInfo.java	Wed Dec 19 10:01:08 2012 +0100
@@ -0,0 +1,39 @@
+/*
+ * 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.nodes;
+
+import java.lang.annotation.*;
+
+/**
+ * Annotation for providing additional information on nodes.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface NodeInfo {
+
+    /**
+     * Short name representing the node that can be used for debugging.
+     * @return the short name
+     */
+    String shortName() default "";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java	Wed Dec 19 10:01:08 2012 +0100
@@ -0,0 +1,702 @@
+/*
+ * 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.nodes;
+
+import java.io.*;
+import java.lang.annotation.*;
+import java.lang.reflect.*;
+import java.util.*;
+
+import sun.misc.*;
+
+/**
+ * Utility class that manages the special access methods for node instances.
+ */
+public class NodeUtil {
+
+    public static final class NodeClass {
+
+        private final Class parentClass;
+        private final long[] nodeFieldOffsets;
+        private final Class[] nodeFieldClasses;
+        private final long[] nodeArrayFieldOffsets;
+        private final Class[] nodeArrayFieldClasses;
+        private final long parentOffset;
+        private final long[] nodeDataFieldOffsets;
+        private final Class< ? >[] nodeDataFieldClasses;
+
+        private static final Map<Class< ? >, NodeClass> nodeClasses = new IdentityHashMap<>();
+
+        public static NodeClass get(Class< ? > clazz) {
+            NodeClass nodeClass = nodeClasses.get(clazz);
+            if (nodeClass == null) {
+                nodeClass = new NodeClass(clazz);
+                nodeClasses.put(clazz, nodeClass);
+            }
+            return nodeClass;
+        }
+
+        private NodeClass(Class< ? > clazz) {
+            // scan object fields
+            Class< ? > parentClassTmp = null;
+            List<Long> nodeFieldOffsetsList = new ArrayList<>();
+            List<Class< ? >> nodeFieldClassesList = new ArrayList<>();
+            List<Long> nodeArrayFieldOffsetsList = new ArrayList<>();
+            List<Class< ? >> nodeArrayFieldClassesList = new ArrayList<>();
+            List<Long> nodeDataFieldOffsetList = new ArrayList<>();
+            List<Class< ? >> nodeDataFieldClassList = new ArrayList<>();
+            Field[] fields = getAllFields(clazz);
+            long parentOffsetTemp = -1;
+            for (Field field : fields) {
+                if (Modifier.isStatic(field.getModifiers()) || field.isSynthetic()) {
+                    continue;
+                }
+
+                // Node fields
+                if (Node.class.isAssignableFrom(field.getType())) {
+                    if (!field.getName().equals("parent")) {
+                        nodeFieldOffsetsList.add(unsafe.objectFieldOffset(field));
+                        nodeFieldClassesList.add(field.getType());
+                    } else {
+                        parentOffsetTemp = unsafe.objectFieldOffset(field);
+                        parentClassTmp = field.getType();
+                    }
+                } else if (field.getType().getComponentType() != null && Node.class.isAssignableFrom(field.getType().getComponentType())) {
+                    nodeArrayFieldOffsetsList.add(unsafe.objectFieldOffset(field));
+                    nodeArrayFieldClassesList.add(field.getType());
+                } else {
+                    nodeDataFieldOffsetList.add(unsafe.objectFieldOffset(field));
+                    nodeDataFieldClassList.add(field.getType());
+                }
+            }
+            this.parentClass = parentClassTmp;
+            this.nodeFieldOffsets = toLongArray(nodeFieldOffsetsList);
+            this.nodeFieldClasses = nodeFieldClassesList.toArray(new Class[nodeFieldClassesList.size()]);
+            this.nodeArrayFieldOffsets = toLongArray(nodeArrayFieldOffsetsList);
+            this.nodeArrayFieldClasses = nodeArrayFieldClassesList.toArray(new Class[nodeArrayFieldClassesList.size()]);
+            this.nodeDataFieldOffsets = toLongArray(nodeDataFieldOffsetList);
+            this.nodeDataFieldClasses = nodeDataFieldClassList.toArray(new Class< ? >[nodeDataFieldClassList.size()]);
+
+            this.parentOffset = parentOffsetTemp;
+        }
+    }
+
+    public static class NodeIterator implements Iterator<Node> {
+
+        private final Node node;
+        private final NodeClass nodeClass;
+        private final int childrenCount;
+        private int index;
+
+        public NodeIterator(Node node) {
+            this(node, 0);
+        }
+
+        public NodeIterator(Node node, int index) {
+            this.node = node;
+            this.index = index;
+            this.nodeClass = NodeClass.get(node.getClass());
+            this.childrenCount = childrenCount();
+        }
+
+        private int childrenCount() {
+            int nodeCount = nodeClass.nodeFieldOffsets.length;
+            for (long fieldOffset : nodeClass.nodeArrayFieldOffsets) {
+                Node[] children = ((Node[]) unsafe.getObject(node, fieldOffset));
+                if (children != null) {
+                    nodeCount += children.length;
+                }
+            }
+            return nodeCount;
+        }
+
+        private Node nodeAt(int idx) {
+            int nodeCount = nodeClass.nodeFieldOffsets.length;
+            if (idx < nodeCount) {
+                return (Node) unsafe.getObject(node, nodeClass.nodeFieldOffsets[idx]);
+            } else {
+                for (long fieldOffset : nodeClass.nodeArrayFieldOffsets) {
+                    Node[] nodeArray = (Node[]) unsafe.getObject(node, fieldOffset);
+                    if (idx < nodeCount + nodeArray.length) {
+                        return nodeArray[idx - nodeCount];
+                    }
+                    nodeCount += nodeArray.length;
+                }
+            }
+            return null;
+        }
+
+        private void forward() {
+            if (index < childrenCount) {
+                index++;
+            }
+        }
+
+        @Override
+        public boolean hasNext() {
+            return index < childrenCount;
+        }
+
+        @Override
+        public Node next() {
+            try {
+                return nodeAt(index);
+            } finally {
+                forward();
+            }
+        }
+
+        @Override
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    private static long[] toLongArray(List<Long> list) {
+        long[] array = new long[list.size()];
+        for (int i = 0; i < list.size(); i++) {
+            array[i] = list.get(i);
+        }
+        return array;
+    }
+
+    private static final Unsafe unsafe = getUnsafe();
+
+    private static Unsafe getUnsafe() {
+        try {
+            return Unsafe.getUnsafe();
+        } catch (SecurityException e) {
+        }
+        try {
+            Field theUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe");
+            theUnsafeInstance.setAccessible(true);
+            return (Unsafe) theUnsafeInstance.get(Unsafe.class);
+        } catch (Exception e) {
+            throw new RuntimeException("exception while trying to get Unsafe.theUnsafe via reflection:", e);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <T extends Node> T cloneNode(T orig) {
+        Class< ? extends Node> clazz = orig.getClass();
+        NodeClass nodeClass = NodeClass.get(clazz);
+        Node clone = orig.copy();
+        if (clone == null) {
+            return null;
+        }
+
+        unsafe.putObject(clone, nodeClass.parentOffset, null);
+
+        for (long fieldOffset : nodeClass.nodeFieldOffsets) {
+            Node child = (Node) unsafe.getObject(orig, fieldOffset);
+            if (child != null) {
+                Node clonedChild = cloneNode(child);
+                if (clonedChild == null) {
+                    return null;
+                }
+
+                unsafe.putObject(clonedChild, nodeClass.parentOffset, clone);
+                unsafe.putObject(clone, fieldOffset, clonedChild);
+            }
+        }
+        for (long fieldOffset : nodeClass.nodeArrayFieldOffsets) {
+            Node[] children = (Node[]) unsafe.getObject(orig, fieldOffset);
+            if (children != null) {
+                Node[] clonedChildren = new Node[children.length];
+                for (int i = 0; i < children.length; i++) {
+                    Node clonedChild = cloneNode(children[i]);
+                    if (clonedChild == null) {
+                        return null;
+                    }
+
+                    clonedChildren[i] = clonedChild;
+                    unsafe.putObject(clonedChild, nodeClass.parentOffset, clone);
+                }
+                unsafe.putObject(clone, fieldOffset, clonedChildren);
+            }
+        }
+        return (T) clone;
+    }
+
+    public static List<Object> findNodeChildren(Object node) {
+        List<Object> nodes = new ArrayList<>();
+        NodeClass nodeClass = NodeClass.get(node.getClass());
+
+        for (long fieldOffset : nodeClass.nodeFieldOffsets) {
+            Object child = unsafe.getObject(node, fieldOffset);
+            if (child != null) {
+                nodes.add(child);
+            }
+        }
+        for (long fieldOffset : nodeClass.nodeArrayFieldOffsets) {
+            Object[] children = (Object[]) unsafe.getObject(node, fieldOffset);
+            if (children != null) {
+                nodes.addAll(Arrays.asList(children));
+            }
+        }
+
+        return nodes;
+    }
+
+    public static void replaceChild(Node parent, Node oldChild, Node newChild) {
+        NodeClass nodeClass = NodeClass.get(parent.getClass());
+
+        for (long fieldOffset : nodeClass.nodeFieldOffsets) {
+            if (unsafe.getObject(parent, fieldOffset) == oldChild) {
+                unsafe.putObject(parent, fieldOffset, newChild);
+            }
+        }
+        for (long fieldOffset : nodeClass.nodeArrayFieldOffsets) {
+            Node[] array = (Node[]) unsafe.getObject(parent, fieldOffset);
+            if (array != null) {
+                for (int i = 0; i < array.length; i++) {
+                    if (array[i] == oldChild) {
+                        array[i] = newChild;
+                        return;
+                    }
+                }
+            }
+        }
+    }
+
+    public static long[] getNodeDataFieldOffsets(Class< ? > nodeClass) {
+        NodeClass clazz = NodeClass.get(nodeClass);
+        return Arrays.copyOf(clazz.nodeDataFieldOffsets, clazz.nodeDataFieldClasses.length);
+    }
+
+    public static Class[] getNodeDataFieldClasses(Class< ? > nodeClass) {
+        NodeClass clazz = NodeClass.get(nodeClass);
+        return Arrays.copyOf(clazz.nodeDataFieldClasses, clazz.nodeDataFieldClasses.length);
+    }
+
+    public static long getNodeParentOffset(Class< ? > nodeClass) {
+        NodeClass clazz = NodeClass.get(nodeClass);
+        return clazz.parentOffset;
+    }
+
+    /** Returns the number of Node field declarations in the class hierarchy. */
+    public static long[] getNodeFieldOffsets(Class< ? > nodeClass) {
+        NodeClass clazz = NodeClass.get(nodeClass);
+        return Arrays.copyOf(clazz.nodeFieldOffsets, clazz.nodeFieldOffsets.length);
+    }
+
+    /** Returns the number of Node[] declaration in the class hierarchy. */
+    public static long[] getNodeFieldArrayOffsets(Class< ? > nodeClass) {
+        NodeClass clazz = NodeClass.get(nodeClass);
+        return Arrays.copyOf(clazz.nodeArrayFieldOffsets, clazz.nodeArrayFieldOffsets.length);
+    }
+
+    public static Class[] getNodeFieldArrayClasses(Class< ? > nodeClass) {
+        NodeClass clazz = NodeClass.get(nodeClass);
+        return Arrays.copyOf(clazz.nodeArrayFieldClasses, clazz.nodeArrayFieldClasses.length);
+    }
+
+    public static Class getNodeParentClass(Class< ? > nodeClass) {
+        return NodeClass.get(nodeClass).parentClass;
+    }
+
+    public static Class[] getNodeFieldClasses(Class< ? > nodeClass) {
+        NodeClass clazz = NodeClass.get(nodeClass);
+        return Arrays.copyOf(clazz.nodeFieldClasses, clazz.nodeFieldClasses.length);
+    }
+
+    /** Returns all declared fields in the class hierarchy. */
+    public static Field[] getAllFields(Class< ? extends Object> clazz) {
+        Field[] declaredFields = clazz.getDeclaredFields();
+        if (clazz.getSuperclass() != null) {
+            return concat(getAllFields(clazz.getSuperclass()), declaredFields);
+        }
+        return declaredFields;
+    }
+
+    public static <T> T[] concat(T[] first, T[] second) {
+        T[] result = Arrays.copyOf(first, first.length + second.length);
+        System.arraycopy(second, 0, result, first.length, second.length);
+        return result;
+    }
+
+    /** find annotation in class/interface hierarchy. */
+    public static <T extends Annotation> T findAnnotation(Class< ? > clazz, Class<T> annotationClass) {
+        if (clazz.getAnnotation(annotationClass) != null) {
+            return clazz.getAnnotation(annotationClass);
+        } else {
+            for (Class< ? > intf : clazz.getInterfaces()) {
+                if (intf.getAnnotation(annotationClass) != null) {
+                    return intf.getAnnotation(annotationClass);
+                }
+            }
+            if (clazz.getSuperclass() != null) {
+                return findAnnotation(clazz.getSuperclass(), annotationClass);
+            }
+        }
+        return null;
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <T extends Node> T findParent(final Node start, final Class<T> clazz) {
+        assert start != null;
+        if (clazz.isInstance(start.getParent())) {
+            return (T) start.getParent();
+        } else {
+            return start.getParent() != null ? findParent(start.getParent(), clazz) : null;
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <I> I findParentInterface(final Node start, final Class<I> clazz) {
+        assert start != null;
+        if (clazz.isInstance(start.getParent())) {
+            return (I) start.getParent();
+        } else {
+            return (start.getParent() != null ? findParentInterface(start.getParent(), clazz) : null);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <T> T findFirstNodeInstance(Object root, Class<T> clazz) {
+        List<Object> childNodes = findNodeChildren(root);
+
+        for (Object childNode : childNodes) {
+            if (clazz.isInstance(childNode)) {
+                return (T) childNode;
+            } else {
+                return findFirstNodeInstance(childNode, clazz);
+            }
+        }
+        return null;
+    }
+
+    public static <T extends Node> List<T> findAllNodeInstances(final Node root, final Class<T> clazz) {
+        final List<T> nodeList = new ArrayList<>();
+        root.accept(new NodeVisitor() {
+
+            @SuppressWarnings("unchecked")
+            @Override
+            public boolean visit(Node node) {
+                if (clazz.isInstance(node)) {
+                    nodeList.add((T) node);
+                }
+                return true;
+            }
+        });
+        return nodeList;
+    }
+
+    // Don't visit found node instances.
+    public static <T extends Node> List<T> findNodeInstancesShallow(final Node root, final Class<T> clazz) {
+        final List<T> nodeList = new ArrayList<>();
+        root.accept(new NodeVisitor() {
+
+            @SuppressWarnings("unchecked")
+            @Override
+            public boolean visit(Node node) {
+                if (clazz.isInstance(node)) {
+                    nodeList.add((T) node);
+                    return false;
+                }
+                return true;
+            }
+        });
+        return nodeList;
+    }
+
+    /** Find node instances within current function only (not in nested functions). */
+    public static <T extends Node> List<T> findNodeInstancesInFunction(final Node root, final Class<T> clazz) {
+        final List<T> nodeList = new ArrayList<>();
+        root.accept(new NodeVisitor() {
+
+            @SuppressWarnings("unchecked")
+            @Override
+            public boolean visit(Node node) {
+                if (clazz.isInstance(node)) {
+                    nodeList.add((T) node);
+                } else if (node instanceof RootNode && node != root) {
+                    return false;
+                }
+                return true;
+            }
+        });
+        return nodeList;
+    }
+
+    public static <I> List<I> findNodeInstancesInFunctionInterface(final Node root, final Class<I> clazz) {
+        final List<I> nodeList = new ArrayList<>();
+        root.accept(new NodeVisitor() {
+
+            @SuppressWarnings("unchecked")
+            @Override
+            public boolean visit(Node node) {
+                if (clazz.isInstance(node)) {
+                    nodeList.add((I) node);
+                } else if (node instanceof RootNode && node != root) {
+                    return false;
+                }
+                return true;
+            }
+        });
+        return nodeList;
+    }
+
+    public static String printTreeToString(Node node) {
+        ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
+        printTree(new PrintStream(byteOut), node);
+        try {
+            byteOut.flush();
+        } catch (IOException e) {
+        }
+        return new String(byteOut.toByteArray());
+    }
+
+    /**
+     * Prints a human readable form of a {@link Node} AST to the given {@link PrintStream}. This print method does not
+     * check for cycles in the node structure.
+     *
+     * @param p the {@link PrintStream} to print to.
+     * @param node the root node to write
+     */
+    public static void printTree(PrintStream p, Node node) {
+        printTree(p, node, new NodeTreeResolver());
+    }
+
+    /**
+     * Prints a human readable form of a tree to the given {@link PrintStream}. The {@link TreeResolver} interface needs
+     * to be implemented to specify how the method can read the tree from plain a object.
+     *
+     * @param p the {@link PrintStream} to print to.
+     * @param o the root object to be printed.
+     * @param resolver an implementation of a tree resolver
+     */
+    public static void printTree(PrintStream p, Object o, TreeResolver resolver) {
+        printTree(p, o, resolver, 1);
+        p.println();
+    }
+
+    private static void printTree(PrintStream p, Object node, TreeResolver resolver, int level) {
+        if (node == null) {
+            p.print("null");
+            return;
+        }
+
+        p.print(node.getClass().getSimpleName());
+
+        Field[] fields = NodeUtil.getAllFields(node.getClass());
+        p.print("(");
+
+        ArrayList<Field> childFields = new ArrayList<>();
+
+        boolean first = true;
+        for (int i = 0; i < fields.length; i++) {
+            Field field = fields[i];
+            if (Modifier.isStatic(field.getModifiers()) || resolver.isFiltered(field)) {
+                continue;
+            }
+            if (resolver.isChildObject(field) || resolver.isChildArrayObject(field)) {
+                childFields.add(field);
+            }
+            if (!resolver.isDataField(field)) {
+                continue;
+            }
+            if (!first) {
+                p.print(", ");
+            } else {
+                first = false;
+            }
+
+            Object value = getObjectValue(node, field.getType(), unsafe.objectFieldOffset(field));
+
+            p.print(field.getName());
+            p.print(" = ");
+            p.print(resolver.toString(value));
+        }
+        p.print(")");
+
+        if (childFields.size() != 0) {
+            p.print(" {");
+        }
+
+        // I refetch the fields to get declaration order.
+        for (int i = 0; i < childFields.size(); i++) {
+            Field field = childFields.get(i);
+            Class< ? > fieldClass = field.getType();
+            String name = field.getName();
+
+            long offset = unsafe.objectFieldOffset(field);
+
+            Object value = getObjectValue(node, fieldClass, offset);
+
+            printNewLine(p, level);
+            p.print(name);
+            if (value == null) {
+                p.print(" = null ");
+            } else if (resolver.isChildObject(field)) {
+                p.print(" = ");
+                printTree(p, value, resolver, level + 1);
+            } else if (resolver.isChildArrayObject(field)) {
+                Object[] objectArray = resolver.convertToArray(field, value);
+                if (objectArray.length == 0) {
+                    p.print(" = []");
+                } else {
+                    p.print(" = [");
+                    for (int j = 0; j < objectArray.length; j++) {
+                        printTree(p, objectArray[j], resolver, level + 1);
+                        if (j < objectArray.length - 1) {
+                            p.print(", ");
+                        }
+                    }
+                    p.print("]");
+                }
+            } else {
+                assert false;
+            }
+        }
+
+        if (childFields.size() != 0) {
+            printNewLine(p, level - 1);
+            p.print("}");
+        }
+    }
+
+    private static Object getObjectValue(Object base, Class< ? > fieldClass, long offset) {
+        if (fieldClass == boolean.class) {
+            return unsafe.getBoolean(base, offset);
+        } else if (fieldClass == byte.class) {
+            return unsafe.getByte(base, offset);
+        } else if (fieldClass == short.class) {
+            return unsafe.getShort(base, offset);
+        } else if (fieldClass == char.class) {
+            return unsafe.getChar(base, offset);
+        } else if (fieldClass == int.class) {
+            return unsafe.getInt(base, offset);
+        } else if (fieldClass == long.class) {
+            return unsafe.getLong(base, offset);
+        } else if (fieldClass == float.class) {
+            return unsafe.getFloat(base, offset);
+        } else if (fieldClass == double.class) {
+            return unsafe.getDouble(base, offset);
+        } else {
+            return unsafe.getObject(base, offset);
+        }
+    }
+
+    private static void printNewLine(PrintStream p, int level) {
+        p.println();
+        for (int i = 0; i < level; i++) {
+            p.print("    ");
+        }
+    }
+
+    private static class NodeTreeResolver implements TreeResolver {
+
+        @Override
+        public boolean isFiltered(Field f) {
+            if (f.getName().equals("parent")) {
+                return true;
+            }
+            return f.isSynthetic();
+        }
+
+        @Override
+        public boolean isDataField(Field f) {
+            return !isChildArrayObject(f) && !isChildObject(f);
+        }
+
+        @Override
+        public boolean isChildObject(Field f) {
+            return Node.class.isAssignableFrom(f.getType());
+        }
+
+        @Override
+        public boolean isChildArrayObject(Field f) {
+            return f.getType().getComponentType() != null && Node.class.isAssignableFrom(f.getType().getComponentType());
+        }
+
+        @Override
+        public Object[] convertToArray(Field f, Object data) {
+            return (Object[]) data;
+        }
+
+        @Override
+        public String toString(Object o) {
+            return o == null ? "null" : o.toString();
+        }
+    }
+
+    /**
+     * Specifies how a tree can be built from plain objects.
+     */
+    public interface TreeResolver {
+
+        /**
+         * Returns true if a {@link Field} is filtered from the tree.
+         *
+         * @param f the field to check
+         */
+        boolean isFiltered(Field f);
+
+        /**
+         * Returns true if a {@link Field} is a field that contains a data value which should not be traversed
+         * recursively.
+         *
+         * @param f the field to check
+         * @return true if a the given field is a data field else false.
+         */
+        boolean isDataField(Field f);
+
+        /**
+         * Returns true if a {@link Field} is a field that contains an {@link Object} which should be recursively
+         * visited.
+         *
+         * @param f the field to check
+         * @return true if a the given field is a child field else false.
+         */
+        boolean isChildObject(Field f);
+
+        /**
+         * Returns true if a {@link Field} is a field that contains any kind of list/array structure which itself holds
+         * values that should be recursively visited.
+         *
+         * @param f the field to check
+         * @return true if a the given field is a child array/list field else false.
+         */
+        boolean isChildArrayObject(Field f);
+
+        /**
+         * Converts an given child array object to array which can be traversed. This is especially useful to convert
+         * any kind of list structure to a traversable array.
+         *
+         * @param f the field for meta data needed to convert the data {@link Object}.
+         * @param value the actual value of the child array/list object.
+         * @return the converted {@link Object} array.
+         */
+        Object[] convertToArray(Field f, Object value);
+
+        /**
+         * Returns a human readable string for any data field object in the tree.
+         *
+         * @param o the object to convert to string.
+         * @return the converted string
+         */
+        String toString(Object o);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeVisitor.java	Wed Dec 19 10:01:08 2012 +0100
@@ -0,0 +1,38 @@
+/*
+ * 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.nodes;
+
+/**
+ * Visitor for trees of nodes.
+ */
+public interface NodeVisitor {
+
+    /**
+     * This visitor method is called for every node in the tree. Its return value determines if the children of this
+     * node should be excluded in the iteration.
+     *
+     * @param node the node that is currently visited
+     * @return {@code true} if the children should be visited too, {@code false} otherwise
+     */
+    boolean visit(Node node);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/RootNode.java	Wed Dec 19 10:01:08 2012 +0100
@@ -0,0 +1,39 @@
+/*
+ * 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.nodes;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+
+/**
+ * A root node is a node with a method to execute it given only a frame as a parameter. Therefore, a root node can be used to create a call target using {@link TruffleRuntime#createCallTarget(RootNode, FrameDescriptor)}.
+ */
+public abstract class RootNode extends Node {
+
+    /**
+     * Executes this function using the specified frame and returns the result value.
+     * @param frame the frame of the currently executing guest language method
+     * @return the value of the execution
+     */
+    public abstract Object execute(VirtualFrame frame);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/SlowPathException.java	Wed Dec 19 10:01:08 2012 +0100
@@ -0,0 +1,39 @@
+/*
+ * 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.nodes;
+
+/**
+ * An exception thrown to enter a slow path. The Truffle optimizer has special knowledge of this exception class and
+ * will never compile a catch block that catches this exception type.
+ */
+public class SlowPathException extends Exception {
+
+    private static final long serialVersionUID = 3676602078425211386L;
+
+    /**
+     * Creates an exception thrown to enter a slow path.
+     */
+    public SlowPathException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/UnexpectedResultException.java	Wed Dec 19 10:01:08 2012 +0100
@@ -0,0 +1,59 @@
+/*
+ * 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.nodes;
+
+/**
+ * An exception that should be thrown if the return value cannot be represented as a value of the return type. The
+ * Truffle optimizer has special knowledge of this exception class and will never compile a catch block that catches this
+ * exception type.
+ */
+public final class UnexpectedResultException extends SlowPathException {
+
+    private static final long serialVersionUID = 3676602078425211386L;
+    private final Object result;
+
+    /**
+     * Creates the exception with the alternative result that cannot be respresented as a value of the return type.
+     * @param result the alternative result
+     */
+    public UnexpectedResultException(Object result) {
+        super(null, null);
+        assert !(result instanceof Throwable);
+        this.result = result;
+    }
+
+    /**
+     * @return the unexpected result
+     */
+    public Object getResult() {
+        return result;
+    }
+
+    /**
+     * For performance reasons, this exception does not record any stack trace information.
+     */
+    @Override
+    public synchronized Throwable fillInStackTrace() {
+        return null;
+    }
+}
--- a/mx/projects	Tue Dec 18 15:05:58 2012 +0100
+++ b/mx/projects	Wed Dec 19 10:01:08 2012 +0100
@@ -90,6 +90,13 @@
 project@com.oracle.graal.hotspot.server@checkstyle=com.oracle.graal.graph
 project@com.oracle.graal.hotspot.server@javaCompliance=1.7
 
+# graal.hotspot.test
+project@com.oracle.graal.hotspot.test@subDir=graal
+project@com.oracle.graal.hotspot.test@sourceDirs=src
+project@com.oracle.graal.hotspot.test@dependencies=com.oracle.graal.hotspot,com.oracle.graal.compiler.test
+project@com.oracle.graal.hotspot.test@checkstyle=com.oracle.graal.graph
+project@com.oracle.graal.hotspot.test@javaCompliance=1.7
+
 # graal.graph
 project@com.oracle.graal.graph@subDir=graal
 project@com.oracle.graal.graph@sourceDirs=src
@@ -247,3 +254,18 @@
 project@com.oracle.graal.asm.amd64@dependencies=com.oracle.graal.asm,com.oracle.graal.amd64
 project@com.oracle.graal.asm.amd64@checkstyle=com.oracle.graal.graph
 project@com.oracle.graal.asm.amd64@javaCompliance=1.7
+
+# truffle.api
+project@com.oracle.truffle.api@subDir=graal
+project@com.oracle.truffle.api@sourceDirs=src
+project@com.oracle.truffle.api@dependencies=
+project@com.oracle.truffle.api@checkstyle=com.oracle.graal.graph
+project@com.oracle.truffle.api@javaCompliance=1.7
+
+# truffle.api.test
+project@com.oracle.truffle.api.test@subDir=graal
+project@com.oracle.truffle.api.test@sourceDirs=src
+project@com.oracle.truffle.api.test@dependencies=com.oracle.truffle.api,JUNIT
+project@com.oracle.truffle.api.test@checkstyle=com.oracle.graal.graph
+project@com.oracle.truffle.api.test@javaCompliance=1.7
+