changeset 13205:bef512e42262

Merge
author Christos Kotselidis <christos.kotselidis@oracle.com>
date Mon, 02 Dec 2013 12:45:18 +0100
parents ffa3d2d26cc2 (current diff) 401e1473c546 (diff)
children b96cc3b87e87
files
diffstat 247 files changed, 4489 insertions(+), 2412 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.meta.jdk8.test/src/com/oracle/graal/api/meta/jdk8/test/TestResolvedJavaMethodJDK8.java	Mon Dec 02 12:45:18 2013 +0100
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.api.meta.jdk8.test;
+
+import static org.junit.Assert.*;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+import org.junit.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.test.*;
+
+/**
+ * Tests for {@link ResolvedJavaMethod} that require JDK >= 8.
+ */
+public class TestResolvedJavaMethodJDK8 extends MethodUniverse {
+
+    public TestResolvedJavaMethodJDK8() {
+    }
+
+    @Test
+    public void isDefaultTest() {
+        for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) {
+            ResolvedJavaMethod m = e.getValue();
+            assertEquals(e.getKey().isDefault(), m.isDefault());
+        }
+        for (Map.Entry<Constructor, ResolvedJavaMethod> e : constructors.entrySet()) {
+            ResolvedJavaMethod m = e.getValue();
+            assertFalse(m.isDefault());
+        }
+    }
+}
--- a/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaMethod.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaMethod.java	Mon Dec 02 12:45:18 2013 +0100
@@ -292,7 +292,8 @@
         "canBeInlined",
         "getLineNumberTable",
         "getLocalVariableTable",
-        "isInVirtualMethodTable"
+        "isInVirtualMethodTable",
+        "isDefault" // tested in TestResolvedJavaMethodJDK8
     };
     // @formatter:on
 
--- a/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaType.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaType.java	Mon Dec 02 12:45:18 2013 +0100
@@ -443,8 +443,14 @@
             if (c.isInterface() || c.isPrimitive()) {
                 ResolvedJavaType type = metaAccess.lookupJavaType(c);
                 for (Method m : c.getDeclaredMethods()) {
-                    ResolvedJavaMethod impl = type.resolveMethod(metaAccess.lookupJavaMethod(m));
-                    assertEquals(m.toString(), null, impl);
+                    if (JAVA_VERSION <= 1.7D || (!isStatic(m.getModifiers()) && !isPrivate(m.getModifiers()))) {
+                        ResolvedJavaMethod resolved = metaAccess.lookupJavaMethod(m);
+                        ResolvedJavaMethod impl = type.resolveMethod(resolved);
+                        ResolvedJavaMethod expected = resolved.isDefault() ? resolved : null;
+                        assertEquals(m.toString(), expected, impl);
+                    } else {
+                        // As of JDK 8, interfaces can have static and private methods
+                    }
                 }
             } else {
                 ResolvedJavaType type = metaAccess.lookupJavaType(c);
--- a/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TypeUniverse.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TypeUniverse.java	Mon Dec 02 12:45:18 2013 +0100
@@ -42,6 +42,7 @@
 public class TypeUniverse {
 
     public final Unsafe unsafe;
+    public static final double JAVA_VERSION = Double.valueOf(System.getProperty("java.specification.version"));
 
     public final MetaAccessProvider metaAccess;
     public final ConstantReflectionProvider constantReflection;
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Constant.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Constant.java	Mon Dec 02 12:45:18 2013 +0100
@@ -250,7 +250,7 @@
         if (getKind() == Kind.Object) {
             return System.identityHashCode(object);
         }
-        return (int) primitive;
+        return (int) primitive * getKind().ordinal();
     }
 
     /**
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/DeoptimizationReason.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/DeoptimizationReason.java	Mon Dec 02 12:45:18 2013 +0100
@@ -40,4 +40,5 @@
     ArithmeticException,
     RuntimeConstraint,
     LoopLimitCheck,
+    Aliasing,
 }
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaMethodProfile.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaMethodProfile.java	Mon Dec 02 12:45:18 2013 +0100
@@ -45,8 +45,8 @@
 
         private static final long serialVersionUID = 5418813647187024693L;
 
-        public ProfiledMethod(ResolvedJavaMethod item, double probability) {
-            super(item, probability);
+        public ProfiledMethod(ResolvedJavaMethod method, double probability) {
+            super(method, probability);
         }
 
         /**
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaTypeProfile.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaTypeProfile.java	Mon Dec 02 12:45:18 2013 +0100
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.api.meta;
 
+import static java.lang.reflect.Modifier.*;
+
 import java.util.*;
 
 import com.oracle.graal.api.meta.JavaTypeProfile.ProfiledType;
@@ -116,7 +118,7 @@
             probabilitySum += newNotRecorded;
 
             double factor = 1.0 / probabilitySum; // Normalize to 1.0
-            assert factor > 1.0;
+            assert factor >= 1.0;
             ProfiledType[] newResult = new ProfiledType[result.size()];
             for (int i = 0; i < newResult.length; ++i) {
                 ProfiledType curType = result.get(i);
@@ -142,8 +144,9 @@
 
         private static final long serialVersionUID = 1481773321889860837L;
 
-        public ProfiledType(ResolvedJavaType item, double probability) {
-            super(item, probability);
+        public ProfiledType(ResolvedJavaType type, double probability) {
+            super(type, probability);
+            assert type.isArray() || !isAbstract(type.getModifiers()) : type;
         }
 
         /**
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java	Mon Dec 02 12:45:18 2013 +0100
@@ -91,6 +91,17 @@
     boolean isSynthetic();
 
     /**
+     * Returns {@code true} if this method is a default method; returns {@code false} otherwise.
+     * 
+     * A default method is a public non-abstract instance method, that is, a non-static method with
+     * a body, declared in an interface type.
+     * 
+     * @return true if and only if this method is a default method as defined by the Java Language
+     *         Specification.
+     */
+    boolean isDefault();
+
+    /**
      * Checks whether this method is a class initializer.
      * 
      * @return {@code true} if the method is a class initializer
--- a/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Address.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Address.java	Mon Dec 02 12:45:18 2013 +0100
@@ -70,6 +70,8 @@
         this.index = index;
         this.scale = scale;
         this.displacement = displacement;
+
+        assert scale != null;
     }
 
     /**
@@ -104,7 +106,7 @@
                 case 8:
                     return Times8;
                 default:
-                    throw new IllegalArgumentException(String.valueOf(scale));
+                    return null;
             }
         }
     }
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Mon Dec 02 12:45:18 2013 +0100
@@ -164,6 +164,17 @@
             if (isConstant(index)) {
                 finalDisp += asConstant(index).asLong() * scale;
                 indexRegister = Value.ILLEGAL;
+
+            } else if (scaleEnum == null) {
+                /* Scale value that architecture cannot handle, so scale manually. */
+                Value longIndex = index.getKind().getStackKind() == Kind.Int ? emitConvert(Kind.Int, Kind.Long, index) : index;
+                if (CodeUtil.isPowerOf2(scale)) {
+                    indexRegister = emitShl(longIndex, Constant.forLong(CodeUtil.log2(scale)));
+                } else {
+                    indexRegister = emitMul(longIndex, Constant.forLong(scale));
+                }
+                scaleEnum = Scale.Times1;
+
             } else {
                 indexRegister = asAllocatable(index);
             }
@@ -812,7 +823,10 @@
         Kind from = inputVal.getKind();
         AllocatableValue input = asAllocatable(inputVal);
 
-        // These cases require a move between CPU and FPU registers:
+        /*
+         * Conversions between integer to floating point types require moves between CPU and FPU
+         * registers.
+         */
         switch (to) {
             case Int:
                 switch (from) {
@@ -826,6 +840,19 @@
                     case Float:
                     case Double:
                         return emitConvert2Op(to, MOV_D2L, input);
+                    case Int:
+                        /*
+                         * Unsigned int-to-long conversion: In theory, instructions that move or
+                         * generate 32-bit register values also set the upper 32 bits of the
+                         * register to zero. However, we cannot rely that the value was really
+                         * generated by an instruction, it could come from an untrusted source such
+                         * as native code. Therefore, make sure the high bits are really cleared.
+                         */
+                        Variable temp = newVariable(Kind.Int);
+                        Variable result = newVariable(Kind.Long);
+                        append(new BinaryRegConst(AMD64Arithmetic.IAND, temp, input, Constant.forInt(0xFFFFFFFF)));
+                        emitMove(result, temp);
+                        return result;
                 }
                 break;
             case Float:
@@ -843,12 +870,7 @@
                 }
                 break;
         }
-
-        // Otherwise, just emit an ordinary move instruction.
-        // Instructions that move or generate 32-bit register values also set the upper 32
-        // bits of the register to zero.
-        // Consequently, there is no need for a special zero-extension move.
-        return emitConvertMove(to, input);
+        throw GraalInternalError.shouldNotReachHere();
     }
 
     @Override
--- a/graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/GraalKernelTester.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/GraalKernelTester.java	Mon Dec 02 12:45:18 2013 +0100
@@ -85,54 +85,19 @@
     }
 
     @Override
-    protected void dispatchLambdaMethodKernelOkra(int range, MyIntConsumer consumer) {
-        HSAILCompilationResult hcr = HSAILCompilationResult.getCompiledLambda(consumer.getClass());
+    protected void dispatchKernelOkra(int range, Object... args) {
+        HSAILCompilationResult hcr = HSAILCompilationResult.getHSAILCompilationResult(testMethod);
         HotSpotNmethod code = (HotSpotNmethod) hcr.getInstalledCode();
 
-        logger.info("To determine parameters to pass to hsail kernel, we will examine   " + consumer.getClass());
-        Field[] fields = consumer.getClass().getDeclaredFields();
-        Object[] args = new Object[fields.length];
-        int argIndex = 0;
-        for (Field f : fields) {
-            logger.info("... " + f);
-            args[argIndex++] = getFieldFromObject(f, consumer);
-        }
-
         if (code != null) {
             try {
-                // No return value from HSAIL kernels
                 code.executeParallel(range, 0, 0, args);
             } catch (InvalidInstalledCodeException e) {
                 Debug.log("WARNING:Invalid installed code: " + e);
                 e.printStackTrace();
             }
-        }
-    }
-
-    @Override
-    protected void dispatchMethodKernelOkra(int range, Object... args) {
-        Object[] fixedArgs = fixArgTypes(args);
-
-        HSAILCompilationResult hcr = HSAILCompilationResult.getHSAILCompilationResult(testMethod);
-        HotSpotNmethod code = (HotSpotNmethod) hcr.getInstalledCode();
-
-        if (code != null) {
-            try {
-                if (Modifier.isStatic(testMethod.getModifiers())) {
-                    code.executeParallel(range, 0, 0, fixedArgs);
-                } else {
-                    // If it is a non-static method we have to push "this" as the first argument.
-                    Object[] newFixedArgs = new Object[fixedArgs.length + 1];
-                    System.arraycopy(fixedArgs, 0, newFixedArgs, 1, fixedArgs.length);
-                    newFixedArgs[0] = this;
-                    code.executeParallel(range, 0, 0, newFixedArgs);
-                }
-            } catch (InvalidInstalledCodeException e) {
-                Debug.log("WARNING:Invalid installed code: " + e);
-                e.printStackTrace();
-            }
         } else {
-            super.dispatchMethodKernelOkra(range, args);
+            super.dispatchKernelOkra(range, args);
         }
     }
 
--- a/graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/KernelTester.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/KernelTester.java	Mon Dec 02 12:45:18 2013 +0100
@@ -88,7 +88,7 @@
 
     static {
         logger = Logger.getLogger(propPkgName);
-        logLevel = Level.parse(System.getProperty("kerneltester.logLevel", "SEVERE"));
+        logLevel = Level.parse(System.getProperty("kerneltester.logLevel", "OFF"));
 
         // This block configure the logger with handler and formatter.
         consoleHandler = new ConsoleHandler();
@@ -367,6 +367,20 @@
     }
 
     /**
+     * The "array stream" version of {@link #dispatchMethodKernel(int, Object...)}.
+     */
+    public void dispatchMethodKernel(Object[] ary, Object... args) {
+        if (testMethod == null) {
+            setTestMethod(getTestMethodName(), this.getClass());
+        }
+        if (dispatchMode == DispatchMode.SEQ) {
+            dispatchMethodKernelSeq(ary, args);
+        } else if (dispatchMode == DispatchMode.OKRA) {
+            dispatchMethodKernelOkra(ary, args);
+        }
+    }
+
+    /**
      * This dispatchLambdaMethodKernel dispatches the lambda version of a kernel where the "kernel"
      * is for the lambda method itself (like lambda$0).
      */
@@ -530,7 +544,11 @@
         }
     }
 
-    private void dispatchKernelOkra(int range, Object... args) {
+    /**
+     * Dispatches an okra kernel over a given range using JNI. Protected so that it can be
+     * overridden in {@link GraalKernelTester} which will dispatch without JNI.
+     */
+    protected void dispatchKernelOkra(int range, Object... args) {
         if (okraKernel == null) {
             createOkraKernel();
         }
@@ -544,6 +562,7 @@
         okraKernel.dispatchWithArgs(args);
     }
 
+    // int stream version
     private void dispatchMethodKernelSeq(int range, Object... args) {
         Object[] invokeArgs = new Object[args.length + 1];
         // Need space on the end for the gid parameter.
@@ -556,32 +575,46 @@
         }
         for (int rangeIndex = 0; rangeIndex < range; rangeIndex++) {
             invokeArgs[gidArgIndex] = rangeIndex;
-            try {
-                testMethod.invoke(this, invokeArgs);
-            } catch (IllegalAccessException e) {
-                fail("could not invoke " + testMethod + ", make sure it is public");
-            } catch (IllegalArgumentException e) {
-                fail("wrong arguments invoking " + testMethod + ", check number and type of args passed to dispatchMethodKernel");
-            } catch (InvocationTargetException e) {
-                Throwable cause = e.getCause();
-                /**
-                 * We will ignore ArrayIndexOutOfBoundsException because the graal okra target
-                 * doesn't really handle it yet (basically returns early if it sees one).
-                 */
-                if (cause instanceof ArrayIndexOutOfBoundsException) {
-                    logger.severe("ignoring ArrayIndexOutOfBoundsException for index " + rangeIndex);
-                } else {
-                    // Other exceptions.
-                    String errstr = testMethod + " threw an exception on gid=" + rangeIndex + ", exception was " + cause;
-                    fail(errstr);
-                }
-            } catch (Exception e) {
-                fail("Unknown exception " + e + " invoking " + testMethod);
+            invokeMethodKernelSeq(invokeArgs, rangeIndex);
+        }
+    }
+
+    // array stream version
+    private void dispatchMethodKernelSeq(Object[] ary, Object... args) {
+        Object[] invokeArgs = new Object[args.length + 1];
+        // Need space on the end for the final obj parameter.
+        System.arraycopy(args, 0, invokeArgs, 0, args.length);
+        int objArgIndex = invokeArgs.length - 1;
+        if (logLevel.intValue() <= Level.FINE.intValue()) {
+            for (Object arg : args) {
+                logger.fine(arg.toString());
             }
         }
+        int range = ary.length;
+        for (int rangeIndex = 0; rangeIndex < range; rangeIndex++) {
+            invokeArgs[objArgIndex] = ary[rangeIndex];
+            invokeMethodKernelSeq(invokeArgs, rangeIndex);
+        }
     }
 
-    protected void dispatchMethodKernelOkra(int range, Object... args) {
+    private void invokeMethodKernelSeq(Object[] invokeArgs, int rangeIndex) {
+        try {
+            testMethod.invoke(this, invokeArgs);
+        } catch (IllegalAccessException e) {
+            fail("could not invoke " + testMethod + ", make sure it is public");
+        } catch (IllegalArgumentException e) {
+            fail("wrong arguments invoking " + testMethod + ", check number and type of args passed to dispatchMethodKernel");
+        } catch (InvocationTargetException e) {
+            Throwable cause = e.getCause();
+            String errstr = testMethod + " threw an exception on gid=" + rangeIndex + ", exception was " + cause;
+            fail(errstr);
+        } catch (Exception e) {
+            fail("Unknown exception " + e + " invoking " + testMethod);
+        }
+    }
+
+    // int stream version
+    private void dispatchMethodKernelOkra(int range, Object... args) {
         Object[] fixedArgs = fixArgTypes(args);
         if (Modifier.isStatic(testMethod.getModifiers())) {
             dispatchKernelOkra(range, fixedArgs);
@@ -594,6 +627,26 @@
         }
     }
 
+    // array stream version
+    private void dispatchMethodKernelOkra(Object[] ary, Object... args) {
+        // add the ary itself as the last arg in the passed parameter list
+        Object[] argsWithAry = new Object[args.length + 1];
+        System.arraycopy(args, 0, argsWithAry, 0, args.length);
+        argsWithAry[argsWithAry.length - 1] = ary;
+
+        Object[] fixedArgs = fixArgTypes(argsWithAry);
+        int range = ary.length;
+        if (Modifier.isStatic(testMethod.getModifiers())) {
+            dispatchKernelOkra(range, fixedArgs);
+        } else {
+            // If it is a non-static method we have to push "this" as the first argument.
+            Object[] newFixedArgs = new Object[fixedArgs.length + 1];
+            System.arraycopy(fixedArgs, 0, newFixedArgs, 1, fixedArgs.length);
+            newFixedArgs[0] = this;
+            dispatchKernelOkra(range, newFixedArgs);
+        }
+    }
+
     /**
      * For primitive arg parameters, make sure arg types are cast to whatever the testMethod
      * signature says they should be.
@@ -659,12 +712,13 @@
     private void dispatchLambdaMethodKernelOkra(Object[] ary, MyObjConsumer consumer) {
         logger.info("To determine parameters to pass to hsail kernel, we will examine   " + consumer.getClass());
         Field[] fields = consumer.getClass().getDeclaredFields();
-        Object[] args = new Object[fields.length];
+        Object[] args = new Object[fields.length + 1];  // + 1 because we also pass the array
         int argIndex = 0;
         for (Field f : fields) {
             logger.info("... " + f);
             args[argIndex++] = getFieldFromObject(f, consumer);
         }
+        args[argIndex] = ary;
         dispatchKernelOkra(ary.length, args);
     }
 
@@ -682,8 +736,9 @@
 
     private void dispatchLambdaKernelOkra(Object[] ary, MyObjConsumer consumer) {
         // The "wrapper" method always has only one arg consisting of the consumer.
-        Object[] args = new Object[1];
+        Object[] args = new Object[2];
         args[0] = consumer;
+        args[1] = ary;
         dispatchKernelOkra(ary.length, args);
     }
 
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BasicHSAILTest.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BasicHSAILTest.java	Mon Dec 02 12:45:18 2013 +0100
@@ -25,6 +25,8 @@
 import org.junit.*;
 
 import com.oracle.graal.compiler.test.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.hotspot.hsail.*;
 import com.oracle.graal.hsail.*;
 import com.oracle.graal.nodes.*;
@@ -330,10 +332,14 @@
         out[gid] = val;
     }
 
-    private void test(String snippet) {
-        StructuredGraph graph = parse(snippet);
-        HSAILCompilationResult compResult = HSAILCompilationResult.getHSAILCompilationResult(graph);
-        compResult.dumpCompilationResult();
+    private void test(final String snippet) {
+        try (Scope s = Debug.scope("HSAILCodeGen")) {
+            StructuredGraph graph = parse(snippet);
+            HSAILCompilationResult compResult = HSAILCompilationResult.getHSAILCompilationResult(graph);
+            Debug.log("HSAIL code generated for %s:%n%s", snippet, compResult.getHSAILCode());
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
     }
 
     public static void nBodySpill(float[] inxyz, float[] outxyz, float[] invxyz, float[] outvxyz, int gid) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/LongModTest.java	Mon Dec 02 12:45:18 2013 +0100
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.hsail.test;
+
+import com.oracle.graal.compiler.hsail.test.infra.GraalKernelTester;
+import org.junit.Test;
+
+/**
+ * Tests the remainder operation (%) on two longs. Generates a rem_s64 instruction.
+ */
+public class LongModTest extends GraalKernelTester {
+
+    static final int num = 20;
+    @Result protected long[] outArray = new long[num];
+
+    /**
+     * The static "kernel" method we will be testing. By convention the gid is the last parameter.
+     * This routine performs the remainder operation (%) on elements from two input arrays and
+     * writes the result to the corresponding index of an output array.
+     * 
+     * @param out the output array
+     * @param ina the first input array
+     * @param inb the second input array
+     * @param gid the parameter used to index into the input and output arrays
+     */
+    public static void run(long[] out, long[] ina, long[] inb, int gid) {
+        out[gid] = (ina[gid] % inb[gid]);
+    }
+
+    @Test
+    public void test() {
+        super.testGeneratedHsail();
+    }
+
+    /**
+     * Initialize input and output arrays.
+     * 
+     * @param in first input array
+     * @param in2 second input array
+     */
+    void setupArrays(long[] in, long[] in2) {
+        for (int i = 0; i < num; i++) {
+            // Fill input arrays with a mix of positive and negative values.
+            in[i] = i < num / 2 ? i + 1 : -(i + 1);
+            in2[i] = (i & 1) == 0 ? i + 10 : -(i + 10);
+            outArray[i] = 0;
+        }
+    }
+
+    /**
+     * Dispatches the HSAIL kernel for this test case.
+     */
+    @Override
+    public void runTest() {
+        long[] inArray = new long[num];
+        long[] inArray2 = new long[num];
+        setupArrays(inArray, inArray2);
+        dispatchMethodKernel(num, outArray, inArray, inArray2);
+    }
+
+}
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticMethod16InArraysTest.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticMethod16InArraysTest.java	Mon Dec 02 12:45:18 2013 +0100
@@ -23,7 +23,10 @@
 
 package com.oracle.graal.compiler.hsail.test;
 
-import org.junit.Test;
+import org.junit.*;
+
+import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.internal.*;
 
 /**
  * Tests the addition of elements from sixteen input arrays.
@@ -60,7 +63,17 @@
      */
     @Test(expected = java.lang.ClassCastException.class)
     public void test() {
-        testGeneratedHsail();
+        DebugConfig debugConfig = DebugScope.getConfig();
+        DebugConfig noInterceptConfig = new DelegatingDebugConfig(debugConfig) {
+            @Override
+            public RuntimeException interceptException(Throwable e) {
+                return null;
+            }
+        };
+
+        try (DebugConfigScope s = Debug.setConfig(noInterceptConfig)) {
+            testGeneratedHsail();
+        }
     }
 
 }
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticMethodThreeIntArrays.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticMethodThreeIntArrays.java	Mon Dec 02 12:45:18 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,15 +24,22 @@
 package com.oracle.graal.compiler.hsail.test;
 
 /**
- * Superclass that initializes two input arrays and one output array. Derived by some of the other
- * test cases that take two arrays as input parameters.
+ * Superclass that initializes two input arrays containing ints and one output array. Derived by
+ * some of the other test cases that take two arrays of ints as input parameters.
  */
 public abstract class StaticMethodThreeIntArrays extends StaticMethodTwoIntArrays {
 
+    /**
+     * Initialize the input and output arrays.
+     * 
+     * @param in1 the first input array
+     * @param in2 the second input array
+     */
     void setupArrays(int[] in1, int[] in2) {
         for (int i = 0; i < num; i++) {
-            in1[i] = i + 1;
-            in2[i] = in1[i] + 10;
+            // Fill input arrays with a mix of positive and negative values.
+            in1[i] = i < num / 2 ? i + 1 : -(i + 1);
+            in2[i] = (i & 1) == 0 ? in1[i] + 10 : -(in1[i] + 10);
             outArray[i] = -i;
         }
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/Vec3.java	Mon Dec 02 12:45:18 2013 +0100
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2009, 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.graal.compiler.hsail.test;
+
+/**
+ * A simple 3 element Vector object used in some junit tests.
+ */
+public class Vec3 {
+
+    public Vec3(float x, float y, float z) {
+        this.x = x;
+        this.y = y;
+        this.z = z;
+    }
+
+    public float x;
+    public float y;
+    public float z;
+
+    public static Vec3 add(Vec3 a, Vec3 b) {
+        return new Vec3(a.x + b.x, a.y + b.y, a.z + b.z);
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (!(other instanceof Vec3)) {
+            return false;
+        }
+        Vec3 oth = (Vec3) other;
+        return (oth.x == x && oth.y == y && oth.z == z);
+    }
+
+    @Override
+    public String toString() {
+        return ("Vec3[" + x + ", " + y + ", " + z + "]");
+    }
+
+    @Override
+    public int hashCode() {
+        return (int) (x + y + z);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/Vec3ObjStreamFloatCaptureTest.java	Mon Dec 02 12:45:18 2013 +0100
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2009, 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.graal.compiler.hsail.test;
+
+import com.oracle.graal.compiler.hsail.test.infra.GraalKernelTester;
+import org.junit.Test;
+
+/**
+ * Tests codegen for a java 7 style object array stream kernel, one float capture.
+ */
+public class Vec3ObjStreamFloatCaptureTest extends GraalKernelTester {
+
+    static final int NUM = 20;
+
+    @Result public Vec3[] inArray = new Vec3[NUM];
+
+    void setupArrays() {
+        for (int i = 0; i < NUM; i++) {
+            inArray[i] = new Vec3(i, i + 1, -1);
+        }
+    }
+
+    /**
+     * The "kernel" method we will be testing. For Array Stream, an object from the array will be
+     * the last parameter
+     */
+    public void run(float adjustment, Vec3 vec3) {
+        vec3.z = vec3.x + vec3.y - adjustment;
+    }
+
+    @Override
+    public void runTest() {
+        setupArrays();
+        dispatchMethodKernel(inArray, 0.5f);
+    }
+
+    @Test
+    public void test() {
+        testGeneratedHsail();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/Vec3ObjStreamIntCaptureTest.java	Mon Dec 02 12:45:18 2013 +0100
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2009, 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.graal.compiler.hsail.test;
+
+import com.oracle.graal.compiler.hsail.test.infra.GraalKernelTester;
+import org.junit.Test;
+
+/**
+ * Tests codegen for a java 7 style object array stream kernel, one int capture.
+ */
+public class Vec3ObjStreamIntCaptureTest extends GraalKernelTester {
+
+    static final int NUM = 20;
+
+    @Result public Vec3[] inArray = new Vec3[NUM];
+
+    void setupArrays() {
+        for (int i = 0; i < NUM; i++) {
+            inArray[i] = new Vec3(i, i + 1, -1);
+        }
+    }
+
+    /**
+     * The "kernel" method we will be testing. For Array Stream, an object from the array will be
+     * the last parameter
+     */
+    public void run(int adjustment, Vec3 vec3) {
+        vec3.z = vec3.x + vec3.y - adjustment;
+    }
+
+    @Override
+    public void runTest() {
+        setupArrays();
+        dispatchMethodKernel(inArray, 7);
+    }
+
+    @Test
+    public void test() {
+        testGeneratedHsail();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/Vec3ObjStreamIntFloatCaptureTest.java	Mon Dec 02 12:45:18 2013 +0100
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2009, 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.graal.compiler.hsail.test;
+
+import com.oracle.graal.compiler.hsail.test.infra.GraalKernelTester;
+import org.junit.Test;
+
+/**
+ * Tests codegen for a java 7 style object array stream kernel, with one int and one float capture.
+ */
+public class Vec3ObjStreamIntFloatCaptureTest extends GraalKernelTester {
+
+    static final int NUM = 20;
+
+    @Result public Vec3[] inArray = new Vec3[NUM];
+
+    void setupArrays() {
+        for (int i = 0; i < NUM; i++) {
+            inArray[i] = new Vec3(i, i + 1, -1);
+        }
+    }
+
+    /**
+     * The "kernel" method we will be testing. For Array Stream, an object from the array will be
+     * the last parameter
+     */
+    public void run(int adjustment, float multiplier, Vec3 vec3) {
+        vec3.z = (vec3.x + vec3.y - adjustment) * multiplier;
+    }
+
+    @Override
+    public void runTest() {
+        setupArrays();
+        dispatchMethodKernel(inArray, 7, 0.5f);
+    }
+
+    @Test
+    public void test() {
+        testGeneratedHsail();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/Vec3ObjStreamObjCaptureTest.java	Mon Dec 02 12:45:18 2013 +0100
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2009, 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.graal.compiler.hsail.test;
+
+import com.oracle.graal.compiler.hsail.test.infra.GraalKernelTester;
+import org.junit.Test;
+
+/**
+ * Tests codegen for a java 7 style object array stream kernel, one object capture.
+ */
+public class Vec3ObjStreamObjCaptureTest extends GraalKernelTester {
+
+    static final int NUM = 20;
+
+    @Result public Vec3[] inArray = new Vec3[NUM];
+
+    void setupArrays() {
+        for (int i = 0; i < NUM; i++) {
+            inArray[i] = new Vec3(i, i + 1, -1);
+        }
+    }
+
+    /**
+     * The "kernel" method we will be testing. For Array Stream, an object from the array will be
+     * the last parameter
+     */
+    public void run(Vec3 basevec, Vec3 vec3) {
+        vec3.z = vec3.x + vec3.y - basevec.z;
+    }
+
+    @Override
+    public void runTest() {
+        setupArrays();
+        dispatchMethodKernel(inArray, new Vec3(1, 2, 3));
+    }
+
+    @Test
+    public void test() {
+        testGeneratedHsail();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/Vec3ObjStreamObjFieldTest.java	Mon Dec 02 12:45:18 2013 +0100
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2009, 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.graal.compiler.hsail.test;
+
+import com.oracle.graal.compiler.hsail.test.infra.GraalKernelTester;
+import org.junit.Test;
+
+/**
+ * Tests codegen for a java 7 style object array stream kernel, no captures. Instance method which
+ * accesses an object field
+ */
+public class Vec3ObjStreamObjFieldTest extends GraalKernelTester {
+
+    static final int NUM = 20;
+
+    @Result public Vec3[] inArray = new Vec3[NUM];
+    Vec3 basevec = new Vec3(1, 2, 3);
+
+    void setupArrays() {
+        for (int i = 0; i < NUM; i++) {
+            inArray[i] = new Vec3(i, i + 1, -1);
+        }
+    }
+
+    /**
+     * The "kernel" method we will be testing. For Array Stream, an object from the array will be
+     * the last parameter
+     */
+    public void run(Vec3 vec3) {
+        vec3.z = vec3.x + vec3.y - basevec.z;
+    }
+
+    @Override
+    public void runTest() {
+        setupArrays();
+        dispatchMethodKernel(inArray);
+    }
+
+    @Test
+    public void test() {
+        testGeneratedHsail();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/Vec3ObjStreamTest.java	Mon Dec 02 12:45:18 2013 +0100
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2009, 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.graal.compiler.hsail.test;
+
+import org.junit.*;
+
+import com.oracle.graal.compiler.hsail.test.infra.*;
+
+/**
+ * Tests codegen for a java 7 style object array stream kernel, no captures.
+ */
+public class Vec3ObjStreamTest extends GraalKernelTester {
+
+    static final int NUM = 20;
+
+    @Result public Vec3[] inArray = new Vec3[NUM];
+
+    void setupArrays() {
+        for (int i = 0; i < NUM; i++) {
+            inArray[i] = new Vec3(i, i + 1, -1);
+        }
+    }
+
+    /**
+     * The "kernel" method we will be testing. For Array Stream, an object from the array will be
+     * the last parameter
+     */
+    public void run(Vec3 vec3) {
+        vec3.z = vec3.x + vec3.y;
+    }
+
+    @Override
+    public void runTest() {
+        setupArrays();
+        dispatchMethodKernel(inArray);
+    }
+
+    @Test
+    public void test() {
+        testGeneratedHsail();
+    }
+
+}
--- a/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/ArrayPTXTest.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/ArrayPTXTest.java	Mon Dec 02 12:45:18 2013 +0100
@@ -24,12 +24,12 @@
 
 import static com.oracle.graal.lir.ptx.ThreadDimension.*;
 
-import com.oracle.graal.lir.ptx.ParallelOver;
-import com.oracle.graal.lir.ptx.Warp;
+import java.lang.reflect.*;
+import java.util.*;
 
-import java.lang.reflect.Method;
-import java.util.Arrays;
-import org.junit.Test;
+import org.junit.*;
+
+import com.oracle.graal.lir.ptx.*;
 
 public class ArrayPTXTest extends PTXTestBase {
 
@@ -71,9 +71,7 @@
         for (Method m : ArrayPTXTest.class.getMethods()) {
             String name = m.getName();
             if (m.getAnnotation(Test.class) == null && name.startsWith("test")) {
-                // CheckStyle: stop system..print check
-                System.out.println(name + ": \n" + new String(test.compile(name).getTargetCode()));
-                // CheckStyle: resume system..print check
+                printReport(name + ": \n" + new String(test.compile(name).getTargetCode()));
             }
         }
     }
--- a/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/BasicPTXTest.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/BasicPTXTest.java	Mon Dec 02 12:45:18 2013 +0100
@@ -22,9 +22,9 @@
  */
 package com.oracle.graal.compiler.ptx.test;
 
-import java.lang.reflect.Method;
+import java.lang.reflect.*;
 
-import org.junit.Test;
+import org.junit.*;
 
 /**
  * Test class for small Java methods compiled to PTX kernels.
@@ -51,9 +51,7 @@
         for (Method m : methods) {
             String name = m.getName();
             if (m.getAnnotation(Test.class) == null && name.startsWith("test")) {
-                // CheckStyle: stop system..print check
-                System.out.println(name + ": \n" + new String(test.compile(name).getTargetCode()));
-                // CheckStyle: resume system..print check
+                printReport(name + ": \n" + new String(test.compile(name).getTargetCode()));
             }
         }
     }
--- a/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/ControlPTXTest.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/ControlPTXTest.java	Mon Dec 02 12:45:18 2013 +0100
@@ -22,9 +22,9 @@
  */
 package com.oracle.graal.compiler.ptx.test;
 
-import org.junit.*;
+import java.lang.reflect.*;
 
-import java.lang.reflect.Method;
+import org.junit.*;
 
 public class ControlPTXTest extends PTXTestBase {
 
@@ -214,9 +214,7 @@
         for (Method m : ControlPTXTest.class.getMethods()) {
             String name = m.getName();
             if (m.getAnnotation(Test.class) == null && name.startsWith("test")) {
-                // CheckStyle: stop system..print check
-                System.out.println(name + ": \n" + new String(test.compile(name).getTargetCode()));
-                // CheckStyle: resume system..print check
+                printReport(name + ": \n" + new String(test.compile(name).getTargetCode()));
             }
         }
     }
--- a/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/FloatPTXTest.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/FloatPTXTest.java	Mon Dec 02 12:45:18 2013 +0100
@@ -366,9 +366,7 @@
         for (Method m : FloatPTXTest.class.getMethods()) {
             String name = m.getName();
             if (m.getAnnotation(Test.class) == null && name.startsWith("test") && name.startsWith("testRem") == false) {
-                // CheckStyle: stop system..print check
-                System.out.println(name + ": \n" + new String(test.compile(name).getTargetCode()));
-                // CheckStyle: resume system..print check
+                printReport(name + ": \n" + new String(test.compile(name).getTargetCode()));
             }
         }
     }
--- a/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/IntegerPTXTest.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/IntegerPTXTest.java	Mon Dec 02 12:45:18 2013 +0100
@@ -352,9 +352,7 @@
         for (Method m : IntegerPTXTest.class.getMethods()) {
             String name = m.getName();
             if (m.getAnnotation(Test.class) == null && name.startsWith("test")) {
-                // CheckStyle: stop system..print check
-                System.out.println(name + ": \n" + new String(test.compile(name).getTargetCode()));
-                // CheckStyle: resume system..print check
+                printReport(name + ": \n" + new String(test.compile(name).getTargetCode()));
             }
         }
     }
--- a/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/LogicPTXTest.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/LogicPTXTest.java	Mon Dec 02 12:45:18 2013 +0100
@@ -128,9 +128,7 @@
         for (Method m : LogicPTXTest.class.getMethods()) {
             String name = m.getName();
             if (m.getAnnotation(Test.class) == null && name.startsWith("test")) {
-                // CheckStyle: stop system..print check
-                System.out.println(name + ": \n" + new String(test.compile(name).getTargetCode()));
-                // CheckStyle: resume system..print check
+                printReport(name + ": \n" + new String(test.compile(name).getTargetCode()));
             }
         }
     }
--- a/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/PTXTestBase.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/PTXTestBase.java	Mon Dec 02 12:45:18 2013 +0100
@@ -48,11 +48,9 @@
 
     private StructuredGraph sg;
 
-    public void printReport(String message) {
-        // CheckStyle: stop system..print check
-        System.out.println(message);
-        // CheckStyle: resume system..print check
-
+    public static void printReport(String message) {
+        // Use -G:Log=Test to see these messages on the console
+        Debug.log(message);
     }
 
     public PTXTestBase() {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java	Mon Dec 02 12:45:18 2013 +0100
@@ -25,7 +25,6 @@
 import org.junit.*;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.debug.*;
 import com.oracle.graal.loop.phases.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.*;
@@ -317,33 +316,27 @@
     }
 
     private void compareGraphs(final String snippet, final String referenceSnippet, final boolean loopPeeling, final boolean excludeVirtual) {
-        Debug.scope("BoxingEliminationTest " + snippet, new DebugDumpScope(snippet), new Runnable() {
-
-            @Override
-            public void run() {
-                graph = parse(snippet);
+        graph = parse(snippet);
 
-                Assumptions assumptions = new Assumptions(false);
-                HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL);
-                CanonicalizerPhase canonicalizer = new CanonicalizerPhase(true);
-                new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
-                if (loopPeeling) {
-                    new LoopTransformHighPhase().apply(graph);
-                }
-                new DeadCodeEliminationPhase().apply(graph);
-                canonicalizer.apply(graph, context);
-                new PartialEscapePhase(false, canonicalizer).apply(graph, context);
+        Assumptions assumptions = new Assumptions(false);
+        HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL);
+        CanonicalizerPhase canonicalizer = new CanonicalizerPhase(true);
+        new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
+        if (loopPeeling) {
+            new LoopTransformHighPhase().apply(graph);
+        }
+        new DeadCodeEliminationPhase().apply(graph);
+        canonicalizer.apply(graph, context);
+        new PartialEscapePhase(false, canonicalizer).apply(graph, context);
 
-                new DeadCodeEliminationPhase().apply(graph);
-                canonicalizer.apply(graph, context);
+        new DeadCodeEliminationPhase().apply(graph);
+        canonicalizer.apply(graph, context);
 
-                StructuredGraph referenceGraph = parse(referenceSnippet);
-                new InliningPhase(new CanonicalizerPhase(true)).apply(referenceGraph, context);
-                new DeadCodeEliminationPhase().apply(referenceGraph);
-                new CanonicalizerPhase(true).apply(referenceGraph, context);
+        StructuredGraph referenceGraph = parse(referenceSnippet);
+        new InliningPhase(new CanonicalizerPhase(true)).apply(referenceGraph, context);
+        new DeadCodeEliminationPhase().apply(referenceGraph);
+        new CanonicalizerPhase(true).apply(referenceGraph, context);
 
-                assertEquals(referenceGraph, graph, excludeVirtual);
-            }
-        });
+        assertEquals(referenceGraph, graph, excludeVirtual);
     }
 }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/DegeneratedLoopsTest.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/DegeneratedLoopsTest.java	Mon Dec 02 12:45:18 2013 +0100
@@ -26,6 +26,7 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
@@ -78,18 +79,17 @@
     }
 
     private void test(final String snippet) {
-        Debug.scope("DegeneratedLoopsTest", new DebugDumpScope(snippet), new Runnable() {
-
-            public void run() {
-                StructuredGraph graph = parse(snippet);
-                HighTierContext context = new HighTierContext(getProviders(), new Assumptions(false), null, getDefaultPhasePlan(), OptimisticOptimizations.ALL);
-                new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
-                new CanonicalizerPhase(true).apply(graph, context);
-                Debug.dump(graph, "Graph");
-                StructuredGraph referenceGraph = parse(REFERENCE_SNIPPET);
-                Debug.dump(referenceGraph, "ReferenceGraph");
-                assertEquals(referenceGraph, graph);
-            }
-        });
+        try (Scope s = Debug.scope("DegeneratedLoopsTest", new DebugDumpScope(snippet))) {
+            StructuredGraph graph = parse(snippet);
+            HighTierContext context = new HighTierContext(getProviders(), new Assumptions(false), null, getDefaultPhasePlan(), OptimisticOptimizations.ALL);
+            new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
+            new CanonicalizerPhase(true).apply(graph, context);
+            Debug.dump(graph, "Graph");
+            StructuredGraph referenceGraph = parse(REFERENCE_SNIPPET);
+            Debug.dump(referenceGraph, "ReferenceGraph");
+            assertEquals(referenceGraph, graph);
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
     }
 }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/EliminateNestedCheckCastsTest.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/EliminateNestedCheckCastsTest.java	Mon Dec 02 12:45:18 2013 +0100
@@ -22,12 +22,11 @@
  */
 package com.oracle.graal.compiler.test;
 
-import java.util.concurrent.*;
-
 import org.junit.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.phases.common.*;
@@ -108,18 +107,16 @@
 
     private StructuredGraph compileSnippet(final String snippet, final int checkcasts, final int afterCanon) {
         final StructuredGraph graph = parse(snippet);
-        return Debug.scope("NestedCheckCastsTest", graph, new Callable<StructuredGraph>() {
+        try (Scope s = Debug.scope("NestedCheckCastsTest", graph)) {
+            Debug.dump(graph, "After parsing: " + snippet);
+            Assert.assertEquals(checkcasts, graph.getNodes().filter(CheckCastNode.class).count());
+            new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), new Assumptions(false)));
+            Assert.assertEquals(afterCanon, graph.getNodes().filter(CheckCastNode.class).count());
+            return graph;
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
 
-            @Override
-            public StructuredGraph call() throws Exception {
-                Debug.dump(graph, "After parsing: " + snippet);
-                Assert.assertEquals(checkcasts, graph.getNodes().filter(CheckCastNode.class).count());
-                new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), new Assumptions(false)));
-                Assert.assertEquals(afterCanon, graph.getNodes().filter(CheckCastNode.class).count());
-                return graph;
-            }
-
-        });
     }
 
     public static class A1 {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FinalizableSubclassTest.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FinalizableSubclassTest.java	Mon Dec 02 12:45:18 2013 +0100
@@ -25,7 +25,6 @@
 import java.io.*;
 import java.lang.reflect.*;
 import java.util.*;
-import java.util.concurrent.*;
 
 import org.junit.*;
 
@@ -119,46 +118,40 @@
 
         @Override
         protected Class<?> findClass(final String name) throws ClassNotFoundException {
-            return Debug.scope("FinalizableSubclassTest", new Callable<Class<?>>() {
+            String nameReplaced = name.replaceAll("AAAA", replaceTo);
+            if (cache.containsKey(nameReplaced)) {
+                return cache.get(nameReplaced);
+            }
 
-                @Override
-                public Class<?> call() throws Exception {
-                    String nameReplaced = name.replaceAll("AAAA", replaceTo);
-                    if (cache.containsKey(nameReplaced)) {
-                        return cache.get(nameReplaced);
-                    }
-
-                    // copy classfile to byte array
-                    byte[] classData = null;
-                    try {
-                        InputStream is = FinalizableSubclassTest.class.getResourceAsStream("FinalizableSubclassTest$" + name + ".class");
-                        assert is != null;
-                        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            // copy classfile to byte array
+            byte[] classData = null;
+            try {
+                InputStream is = FinalizableSubclassTest.class.getResourceAsStream("FinalizableSubclassTest$" + name + ".class");
+                assert is != null;
+                ByteArrayOutputStream baos = new ByteArrayOutputStream();
 
-                        byte[] buf = new byte[1024];
-                        int size;
-                        while ((size = is.read(buf, 0, buf.length)) != -1) {
-                            baos.write(buf, 0, size);
-                        }
-                        baos.flush();
-                        classData = baos.toByteArray();
-                    } catch (IOException e) {
-                        Assert.fail("can't access class: " + name);
-                    }
-                    dumpStringsInByteArray(classData);
+                byte[] buf = new byte[1024];
+                int size;
+                while ((size = is.read(buf, 0, buf.length)) != -1) {
+                    baos.write(buf, 0, size);
+                }
+                baos.flush();
+                classData = baos.toByteArray();
+            } catch (IOException e) {
+                Assert.fail("can't access class: " + name);
+            }
+            dumpStringsInByteArray(classData);
 
-                    // replace all occurrences of "AAAA" in classfile
-                    int index = -1;
-                    while ((index = indexOfAAAA(classData, index + 1)) != -1) {
-                        replaceAAAA(classData, index, replaceTo);
-                    }
-                    dumpStringsInByteArray(classData);
+            // replace all occurrences of "AAAA" in classfile
+            int index = -1;
+            while ((index = indexOfAAAA(classData, index + 1)) != -1) {
+                replaceAAAA(classData, index, replaceTo);
+            }
+            dumpStringsInByteArray(classData);
 
-                    Class c = defineClass(null, classData, 0, classData.length);
-                    cache.put(nameReplaced, c);
-                    return c;
-                }
-            });
+            Class c = defineClass(null, classData, 0, classData.length);
+            cache.put(nameReplaced, c);
+            return c;
         }
 
         private static int indexOfAAAA(byte[] b, int index) {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FloatingReadTest.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FloatingReadTest.java	Mon Dec 02 12:45:18 2013 +0100
@@ -26,6 +26,7 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
@@ -54,35 +55,35 @@
     }
 
     private void test(final String snippet) {
-        Debug.scope("FloatingReadTest", new DebugDumpScope(snippet), new Runnable() {
+        try (Scope s = Debug.scope("FloatingReadTest", new DebugDumpScope(snippet))) {
 
-            public void run() {
-                StructuredGraph graph = parse(snippet);
-                PhaseContext context = new PhaseContext(getProviders(), new Assumptions(false));
-                new LoweringPhase(new CanonicalizerPhase(true)).apply(graph, context);
-                new FloatingReadPhase().apply(graph);
+            StructuredGraph graph = parse(snippet);
+            PhaseContext context = new PhaseContext(getProviders(), new Assumptions(false));
+            new LoweringPhase(new CanonicalizerPhase(true)).apply(graph, context);
+            new FloatingReadPhase().apply(graph);
 
-                ReturnNode returnNode = null;
-                MonitorExit monitorexit = null;
+            ReturnNode returnNode = null;
+            MonitorExit monitorexit = null;
 
-                for (Node n : graph.getNodes()) {
-                    if (n instanceof ReturnNode) {
-                        returnNode = (ReturnNode) n;
-                    } else if (n instanceof MonitorExit) {
-                        monitorexit = (MonitorExit) n;
-                    }
+            for (Node n : graph.getNodes()) {
+                if (n instanceof ReturnNode) {
+                    returnNode = (ReturnNode) n;
+                } else if (n instanceof MonitorExit) {
+                    monitorexit = (MonitorExit) n;
                 }
+            }
 
-                Debug.dump(graph, "After lowering");
+            Debug.dump(graph, "After lowering");
 
-                Assert.assertNotNull(returnNode);
-                Assert.assertNotNull(monitorexit);
-                Assert.assertTrue(returnNode.result() instanceof FloatingReadNode);
+            Assert.assertNotNull(returnNode);
+            Assert.assertNotNull(monitorexit);
+            Assert.assertTrue(returnNode.result() instanceof FloatingReadNode);
 
-                FloatingReadNode read = (FloatingReadNode) returnNode.result();
+            FloatingReadNode read = (FloatingReadNode) returnNode.result();
 
-                assertOrderedAfterSchedule(graph, read, (Node) monitorexit);
-            }
-        });
+            assertOrderedAfterSchedule(graph, read, (Node) monitorexit);
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
     }
 }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Mon Dec 02 12:45:18 2013 +0100
@@ -29,7 +29,6 @@
 import java.io.*;
 import java.lang.reflect.*;
 import java.util.*;
-import java.util.concurrent.*;
 import java.util.concurrent.atomic.*;
 
 import org.junit.*;
@@ -42,6 +41,7 @@
 import com.oracle.graal.compiler.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Node.Verbosity;
 import com.oracle.graal.java.*;
@@ -113,6 +113,20 @@
         DebugEnvironment.initialize(System.out);
     }
 
+    private Scope debugScope;
+
+    @Before
+    public void beforeTest() {
+        assert debugScope == null;
+        debugScope = Debug.scope(getClass().getSimpleName());
+    }
+
+    @After
+    public void afterTest() {
+        debugScope.close();
+        debugScope = null;
+    }
+
     protected void assertEquals(StructuredGraph expected, StructuredGraph graph) {
         assertEquals(expected, graph, false);
     }
@@ -212,6 +226,10 @@
         return providers;
     }
 
+    protected TargetDescription getTarget() {
+        return getProviders().getCodeCache().getTarget();
+    }
+
     protected CodeCacheProvider getCodeCache() {
         return getProviders().getCodeCache();
     }
@@ -525,49 +543,48 @@
 
         final int id = compilationId.incrementAndGet();
 
-        InstalledCode installedCode = Debug.scope("Compiling", new Object[]{new DebugDumpScope(String.valueOf(id), true)}, new Callable<InstalledCode>() {
-
-            public InstalledCode call() throws Exception {
-                final boolean printCompilation = PrintCompilation.getValue() && !TTY.isSuppressed();
-                if (printCompilation) {
-                    TTY.println(String.format("@%-6d Graal %-70s %-45s %-50s ...", id, method.getDeclaringClass().getName(), method.getName(), method.getSignature()));
-                }
-                long start = System.currentTimeMillis();
-                PhasePlan phasePlan = new PhasePlan();
-                GraphBuilderPhase graphBuilderPhase = new GraphBuilderPhase(getMetaAccess(), getForeignCalls(), GraphBuilderConfiguration.getDefault(), OptimisticOptimizations.ALL);
-                phasePlan.addPhase(PhasePosition.AFTER_PARSING, graphBuilderPhase);
-                CallingConvention cc = getCallingConvention(getCodeCache(), Type.JavaCallee, graph.method(), false);
-                final CompilationResult compResult = GraalCompiler.compileGraph(graph, cc, method, getProviders(), getBackend(), getCodeCache().getTarget(), null, phasePlan,
-                                OptimisticOptimizations.ALL, new SpeculationLog(), getSuites(), new CompilationResult());
-                if (printCompilation) {
-                    TTY.println(String.format("@%-6d Graal %-70s %-45s %-50s | %4dms %5dB", id, "", "", "", System.currentTimeMillis() - start, compResult.getTargetCodeSize()));
-                }
-                return Debug.scope("CodeInstall", new Object[]{getCodeCache(), method}, new Callable<InstalledCode>() {
+        InstalledCode installedCode = null;
+        try (Scope ds = Debug.scope("Compiling", new DebugDumpScope(String.valueOf(id), true))) {
+            final boolean printCompilation = PrintCompilation.getValue() && !TTY.isSuppressed();
+            if (printCompilation) {
+                TTY.println(String.format("@%-6d Graal %-70s %-45s %-50s ...", id, method.getDeclaringClass().getName(), method.getName(), method.getSignature()));
+            }
+            long start = System.currentTimeMillis();
+            PhasePlan phasePlan = new PhasePlan();
+            GraphBuilderPhase graphBuilderPhase = new GraphBuilderPhase(getMetaAccess(), getForeignCalls(), GraphBuilderConfiguration.getDefault(), OptimisticOptimizations.ALL);
+            phasePlan.addPhase(PhasePosition.AFTER_PARSING, graphBuilderPhase);
+            CallingConvention cc = getCallingConvention(getCodeCache(), Type.JavaCallee, graph.method(), false);
+            final CompilationResult compResult = GraalCompiler.compileGraph(graph, cc, method, getProviders(), getBackend(), getCodeCache().getTarget(), null, phasePlan, OptimisticOptimizations.ALL,
+                            new SpeculationLog(), getSuites(), new CompilationResult());
+            if (printCompilation) {
+                TTY.println(String.format("@%-6d Graal %-70s %-45s %-50s | %4dms %5dB", id, "", "", "", System.currentTimeMillis() - start, compResult.getTargetCodeSize()));
+            }
 
-                    @Override
-                    public InstalledCode call() throws Exception {
-                        InstalledCode code = addMethod(method, compResult);
-                        if (code == null) {
-                            throw new GraalInternalError("Could not install code for " + MetaUtil.format("%H.%n(%p)", method));
-                        }
-                        if (Debug.isDumpEnabled()) {
-                            Debug.dump(new Object[]{compResult, code}, "After code installation");
+            try (Scope s = Debug.scope("CodeInstall", getCodeCache(), method)) {
+                InstalledCode code = addMethod(method, compResult);
+                if (code == null) {
+                    throw new GraalInternalError("Could not install code for " + MetaUtil.format("%H.%n(%p)", method));
+                }
+                if (Debug.isDumpEnabled()) {
+                    Debug.dump(new Object[]{compResult, code}, "After code installation");
+                }
+                if (Debug.isLogEnabled()) {
+                    DisassemblerProvider dis = backend.getDisassembler();
+                    if (dis != null) {
+                        String text = dis.disassemble(code);
+                        if (text != null) {
+                            Debug.log("Code installed for %s%n%s", method, text);
                         }
-                        if (Debug.isLogEnabled()) {
-                            DisassemblerProvider dis = backend.getDisassembler();
-                            if (dis != null) {
-                                String text = dis.disassemble(code);
-                                if (text != null) {
-                                    Debug.log("Code installed for %s%n%s", method, text);
-                                }
-                            }
-                        }
+                    }
+                }
 
-                        return code;
-                    }
-                });
+                installedCode = code;
+            } catch (Throwable e) {
+                throw Debug.handle(e);
             }
-        });
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
 
         if (!forceCompile) {
             cache.put(method, installedCode);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/LoopUnswitchTest.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/LoopUnswitchTest.java	Mon Dec 02 12:45:18 2013 +0100
@@ -26,6 +26,7 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.loop.phases.*;
 import com.oracle.graal.nodes.*;
@@ -136,12 +137,10 @@
         Assumptions assumptions = new Assumptions(false);
         new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions));
         new CanonicalizerPhase(true).apply(referenceGraph, new PhaseContext(getProviders(), assumptions));
-        Debug.scope("Test", new DebugDumpScope("Test:" + snippet), new Runnable() {
-
-            @Override
-            public void run() {
-                assertEquals(referenceGraph, graph);
-            }
-        });
+        try (Scope s = Debug.scope("Test", new DebugDumpScope("Test:" + snippet))) {
+            assertEquals(referenceGraph, graph);
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
     }
 }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java	Mon Dec 02 12:45:18 2013 +0100
@@ -26,12 +26,12 @@
 import static org.junit.Assert.*;
 
 import java.util.*;
-import java.util.concurrent.*;
 
 import org.junit.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.nodes.*;
@@ -579,47 +579,44 @@
 
     private SchedulePhase getFinalSchedule(final String snippet, final TestMode mode, final MemoryScheduling memsched, final SchedulingStrategy schedulingStrategy) {
         final StructuredGraph graph = parse(snippet);
-        return Debug.scope("FloatingReadTest", graph, new Callable<SchedulePhase>() {
-
-            @Override
-            public SchedulePhase call() throws Exception {
-
-                try (OverrideScope s = OptionValue.override(OptScheduleOutOfLoops, schedulingStrategy == SchedulingStrategy.LATEST_OUT_OF_LOOPS)) {
-                    Assumptions assumptions = new Assumptions(false);
-                    HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL);
-                    CanonicalizerPhase canonicalizer = new CanonicalizerPhase(true);
-                    canonicalizer.apply(graph, context);
-                    if (mode == TestMode.INLINED_WITHOUT_FRAMESTATES) {
-                        new InliningPhase(canonicalizer).apply(graph, context);
-                    }
-                    new LoweringPhase(canonicalizer).apply(graph, context);
-                    if (mode == TestMode.WITHOUT_FRAMESTATES || mode == TestMode.INLINED_WITHOUT_FRAMESTATES) {
-                        for (Node node : graph.getNodes()) {
-                            if (node instanceof StateSplit) {
-                                FrameState stateAfter = ((StateSplit) node).stateAfter();
-                                if (stateAfter != null) {
-                                    ((StateSplit) node).setStateAfter(null);
-                                    GraphUtil.killWithUnusedFloatingInputs(stateAfter);
-                                }
+        try (Scope d = Debug.scope("FloatingReadTest", graph)) {
+            try (OverrideScope s = OptionValue.override(OptScheduleOutOfLoops, schedulingStrategy == SchedulingStrategy.LATEST_OUT_OF_LOOPS)) {
+                Assumptions assumptions = new Assumptions(false);
+                HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL);
+                CanonicalizerPhase canonicalizer = new CanonicalizerPhase(true);
+                canonicalizer.apply(graph, context);
+                if (mode == TestMode.INLINED_WITHOUT_FRAMESTATES) {
+                    new InliningPhase(canonicalizer).apply(graph, context);
+                }
+                new LoweringPhase(canonicalizer).apply(graph, context);
+                if (mode == TestMode.WITHOUT_FRAMESTATES || mode == TestMode.INLINED_WITHOUT_FRAMESTATES) {
+                    for (Node node : graph.getNodes()) {
+                        if (node instanceof StateSplit) {
+                            FrameState stateAfter = ((StateSplit) node).stateAfter();
+                            if (stateAfter != null) {
+                                ((StateSplit) node).setStateAfter(null);
+                                GraphUtil.killWithUnusedFloatingInputs(stateAfter);
                             }
                         }
                     }
-                    Debug.dump(graph, "after removal of framestates");
+                }
+                Debug.dump(graph, "after removal of framestates");
 
-                    new FloatingReadPhase().apply(graph);
-                    new RemoveValueProxyPhase().apply(graph);
+                new FloatingReadPhase().apply(graph);
+                new RemoveValueProxyPhase().apply(graph);
 
-                    MidTierContext midContext = new MidTierContext(getProviders(), assumptions, getCodeCache().getTarget(), OptimisticOptimizations.ALL);
-                    new GuardLoweringPhase().apply(graph, midContext);
-                    new LoweringPhase(canonicalizer).apply(graph, midContext);
-                    new LoweringPhase(canonicalizer).apply(graph, midContext);
+                MidTierContext midContext = new MidTierContext(getProviders(), assumptions, getCodeCache().getTarget(), OptimisticOptimizations.ALL);
+                new GuardLoweringPhase().apply(graph, midContext);
+                new LoweringPhase(canonicalizer).apply(graph, midContext);
+                new LoweringPhase(canonicalizer).apply(graph, midContext);
 
-                    SchedulePhase schedule = new SchedulePhase(schedulingStrategy, memsched);
-                    schedule.apply(graph);
-                    assertEquals(1, graph.getNodes().filter(StartNode.class).count());
-                    return schedule;
-                }
+                SchedulePhase schedule = new SchedulePhase(schedulingStrategy, memsched);
+                schedule.apply(graph);
+                assertEquals(1, graph.getNodes().filter(StartNode.class).count());
+                return schedule;
             }
-        });
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
     }
 }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/PushNodesThroughPiTest.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/PushNodesThroughPiTest.java	Mon Dec 02 12:45:18 2013 +0100
@@ -27,6 +27,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
@@ -64,29 +65,27 @@
     @Test
     public void test1() {
         final String snippet = "test1Snippet";
-        Debug.scope("PushThroughPi", new DebugDumpScope(snippet), new Runnable() {
-
-            public void run() {
-                StructuredGraph graph = compileTestSnippet(snippet);
+        try (Scope s = Debug.scope("PushThroughPi", new DebugDumpScope(snippet))) {
+            StructuredGraph graph = compileTestSnippet(snippet);
+            for (ReadNode rn : graph.getNodes().filter(ReadNode.class)) {
+                if (rn.location() instanceof ConstantLocationNode && rn.object().stamp() instanceof ObjectStamp) {
+                    long disp = ((ConstantLocationNode) rn.location()).getDisplacement();
+                    ResolvedJavaType receiverType = ObjectStamp.typeOrNull(rn.object());
+                    ResolvedJavaField field = receiverType.findInstanceFieldWithOffset(disp);
 
-                for (ReadNode rn : graph.getNodes().filter(ReadNode.class)) {
-                    if (rn.location() instanceof ConstantLocationNode && rn.object().stamp() instanceof ObjectStamp) {
-                        long disp = ((ConstantLocationNode) rn.location()).getDisplacement();
-                        ResolvedJavaType receiverType = ObjectStamp.typeOrNull(rn.object());
-                        ResolvedJavaField field = receiverType.findInstanceFieldWithOffset(disp);
-
-                        assert field != null : "Node " + rn + " tries to access a field which doesn't exists for this type";
-                        if (field.getName().equals("x")) {
-                            Assert.assertTrue(rn.object() instanceof LocalNode);
-                        } else {
-                            Assert.assertTrue(rn.object().toString(), rn.object() instanceof PiNode);
-                        }
+                    assert field != null : "Node " + rn + " tries to access a field which doesn't exists for this type";
+                    if (field.getName().equals("x")) {
+                        Assert.assertTrue(rn.object() instanceof LocalNode);
+                    } else {
+                        Assert.assertTrue(rn.object().toString(), rn.object() instanceof PiNode);
                     }
                 }
+            }
 
-                Assert.assertTrue(graph.getNodes().filter(IsNullNode.class).count() == 1);
-            }
-        });
+            Assert.assertTrue(graph.getNodes().filter(IsNullNode.class).count() == 1);
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
     }
 
     private StructuredGraph compileTestSnippet(final String snippet) {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ReadAfterCheckCastTest.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ReadAfterCheckCastTest.java	Mon Dec 02 12:45:18 2013 +0100
@@ -27,6 +27,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.phases.common.*;
@@ -77,27 +78,26 @@
     }
 
     private void test(final String snippet) {
-        Debug.scope("FloatingReadTest", new DebugDumpScope(snippet), new Runnable() {
-
+        try (Scope s = Debug.scope("ReadAfterCheckCastTest", new DebugDumpScope(snippet))) {
             // check shape of graph, with lots of assumptions. will probably fail if graph
             // structure changes significantly
-            public void run() {
-                StructuredGraph graph = parse(snippet);
-                PhaseContext context = new PhaseContext(getProviders(), new Assumptions(false));
-                new LoweringPhase(new CanonicalizerPhase(true)).apply(graph, context);
-                new FloatingReadPhase().apply(graph);
-                new OptimizeGuardAnchors().apply(graph);
-                new ReadEliminationPhase().apply(graph);
-                new CanonicalizerPhase(true).apply(graph, context);
+            StructuredGraph graph = parse(snippet);
+            PhaseContext context = new PhaseContext(getProviders(), new Assumptions(false));
+            new LoweringPhase(new CanonicalizerPhase(true)).apply(graph, context);
+            new FloatingReadPhase().apply(graph);
+            new OptimizeGuardAnchors().apply(graph);
+            new ReadEliminationPhase().apply(graph);
+            new CanonicalizerPhase(true).apply(graph, context);
 
-                Debug.dump(graph, "After lowering");
+            Debug.dump(graph, "After lowering");
 
-                for (FloatingReadNode node : graph.getNodes(LocalNode.class).first().usages().filter(FloatingReadNode.class)) {
-                    // Checking that the parameter a is not directly used for the access to field
-                    // x10 (because x10 must be guarded by the checkcast).
-                    Assert.assertTrue(node.location().getLocationIdentity() == LocationIdentity.FINAL_LOCATION);
-                }
+            for (FloatingReadNode node : graph.getNodes(LocalNode.class).first().usages().filter(FloatingReadNode.class)) {
+                // Checking that the parameter a is not directly used for the access to field
+                // x10 (because x10 must be guarded by the checkcast).
+                Assert.assertTrue(node.location().getLocationIdentity() == LocationIdentity.FINAL_LOCATION);
             }
-        });
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
     }
 }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SimpleCFGTest.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SimpleCFGTest.java	Mon Dec 02 12:45:18 2013 +0100
@@ -31,13 +31,7 @@
 public class SimpleCFGTest extends GraalCompilerTest {
 
     private static void dumpGraph(final StructuredGraph graph) {
-        Debug.scope("SimpleCFGTest", new Runnable() {
-
-            @Override
-            public void run() {
-                Debug.dump(graph, "Graph");
-            }
-        });
+        Debug.dump(graph, "Graph");
     }
 
     @Test
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/backend/AllocatorTest.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/backend/AllocatorTest.java	Mon Dec 02 12:45:18 2013 +0100
@@ -26,7 +26,6 @@
 import static com.oracle.graal.phases.GraalOptions.*;
 
 import java.util.*;
-import java.util.concurrent.*;
 
 import org.junit.*;
 
@@ -36,6 +35,7 @@
 import com.oracle.graal.compiler.*;
 import com.oracle.graal.compiler.test.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.LIRInstruction.ValueProcedure;
 import com.oracle.graal.lir.StandardOp.MoveOp;
@@ -47,23 +47,18 @@
 
     protected void test(String snippet, final int expectedRegisters, final int expectedRegRegMoves, final int expectedSpillMoves) {
         final StructuredGraph graph = parse(snippet);
-        Debug.scope("AllocatorTest", new Object[]{graph, graph.method(), getCodeCache()}, new Runnable() {
-
-            @Override
-            public void run() {
-                final RegisterStats stats = getRegisterStats(graph);
-
-                Debug.scope("Assertions", stats.lir, new Runnable() {
-
-                    @Override
-                    public void run() {
-                        Assert.assertEquals("register count", expectedRegisters, stats.registers.size());
-                        Assert.assertEquals("reg-reg moves", expectedRegRegMoves, stats.regRegMoves);
-                        Assert.assertEquals("spill moves", expectedSpillMoves, stats.spillMoves);
-                    }
-                });
+        try (Scope s = Debug.scope("AllocatorTest", graph, graph.method(), getCodeCache())) {
+            final RegisterStats stats = getRegisterStats(graph);
+            try (Scope s2 = Debug.scope("Assertions", stats.lir)) {
+                Assert.assertEquals("register count", expectedRegisters, stats.registers.size());
+                Assert.assertEquals("reg-reg moves", expectedRegRegMoves, stats.regRegMoves);
+                Assert.assertEquals("spill moves", expectedSpillMoves, stats.spillMoves);
+            } catch (Throwable e) {
+                throw Debug.handle(e);
             }
-        });
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
     }
 
     private class RegisterStats {
@@ -115,22 +110,19 @@
         final PhasePlan phasePlan = getDefaultPhasePlan();
         final Assumptions assumptions = new Assumptions(OptAssumptions.getValue());
 
-        final LIR lir = Debug.scope("FrontEnd", new Callable<LIR>() {
-
-            @Override
-            public LIR call() {
-                return GraalCompiler.emitHIR(getProviders(), getBackend().getTarget(), graph, assumptions, null, phasePlan, OptimisticOptimizations.NONE, new SpeculationLog(), getSuites());
-            }
-        });
+        LIR lir = null;
+        try (Scope s = Debug.scope("FrontEnd")) {
+            lir = GraalCompiler.emitHIR(getProviders(), getBackend().getTarget(), graph, assumptions, null, phasePlan, OptimisticOptimizations.NONE, new SpeculationLog(), getSuites());
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
 
-        return Debug.scope("BackEnd", lir, new Callable<RegisterStats>() {
-
-            @Override
-            public RegisterStats call() {
-                CallingConvention cc = getCallingConvention(getCodeCache(), Type.JavaCallee, graph.method(), false);
-                GraalCompiler.emitLIR(getBackend(), getBackend().getTarget(), lir, graph, cc);
-                return new RegisterStats(lir);
-            }
-        });
+        try (Scope s = Debug.scope("BackEnd", lir)) {
+            CallingConvention cc = getCallingConvention(getCodeCache(), Type.JavaCallee, graph.method(), false);
+            GraalCompiler.emitLIR(getBackend(), getBackend().getTarget(), lir, graph, cc);
+            return new RegisterStats(lir);
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
     }
 }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EATestBase.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EATestBase.java	Mon Dec 02 12:45:18 2013 +0100
@@ -28,6 +28,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.test.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
@@ -144,19 +145,18 @@
     protected void prepareGraph(String snippet, final boolean iterativeEscapeAnalysis) {
         ResolvedJavaMethod method = getMetaAccess().lookupJavaMethod(getMethod(snippet));
         graph = new StructuredGraph(method);
-        Debug.scope(getClass().getSimpleName(), new Object[]{graph, method, getCodeCache()}, new Runnable() {
-
-            public void run() {
-                new GraphBuilderPhase(getMetaAccess(), getForeignCalls(), GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL).apply(graph);
-                Assumptions assumptions = new Assumptions(false);
-                context = new HighTierContext(getProviders(), assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL);
-                new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
-                new DeadCodeEliminationPhase().apply(graph);
-                new CanonicalizerPhase(true).apply(graph, context);
-                new PartialEscapePhase(iterativeEscapeAnalysis, false, new CanonicalizerPhase(true)).apply(graph, context);
-                Assert.assertEquals(1, graph.getNodes().filter(ReturnNode.class).count());
-                returnNode = graph.getNodes().filter(ReturnNode.class).first();
-            }
-        });
+        try (Scope s = Debug.scope(getClass().getSimpleName(), graph, method, getCodeCache())) {
+            new GraphBuilderPhase(getMetaAccess(), getForeignCalls(), GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL).apply(graph);
+            Assumptions assumptions = new Assumptions(false);
+            context = new HighTierContext(getProviders(), assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL);
+            new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
+            new DeadCodeEliminationPhase().apply(graph);
+            new CanonicalizerPhase(true).apply(graph, context);
+            new PartialEscapePhase(iterativeEscapeAnalysis, false, new CanonicalizerPhase(true)).apply(graph, context);
+            Assert.assertEquals(1, graph.getNodes().filter(ReturnNode.class).count());
+            returnNode = graph.getNodes().filter(ReturnNode.class).first();
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
     }
 }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/inlining/InliningTest.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/inlining/InliningTest.java	Mon Dec 02 12:45:18 2013 +0100
@@ -25,13 +25,13 @@
 import static org.junit.Assert.*;
 
 import java.lang.reflect.*;
-import java.util.concurrent.*;
 
 import org.junit.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.compiler.test.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.*;
@@ -229,24 +229,22 @@
     }
 
     private StructuredGraph getGraph(final String snippet, final boolean eagerInfopointMode) {
-        return Debug.scope("InliningTest", new DebugDumpScope(snippet), new Callable<StructuredGraph>() {
-
-            @Override
-            public StructuredGraph call() {
-                Method method = getMethod(snippet);
-                StructuredGraph graph = eagerInfopointMode ? parseDebug(method) : parse(method);
-                PhasePlan phasePlan = getDefaultPhasePlan(eagerInfopointMode);
-                Assumptions assumptions = new Assumptions(true);
-                HighTierContext context = new HighTierContext(getProviders(), assumptions, null, phasePlan, OptimisticOptimizations.ALL);
-                Debug.dump(graph, "Graph");
-                new CanonicalizerPhase(true).apply(graph, context);
-                new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
-                Debug.dump(graph, "Graph");
-                new CanonicalizerPhase(true).apply(graph, context);
-                new DeadCodeEliminationPhase().apply(graph);
-                return graph;
-            }
-        });
+        try (Scope s = Debug.scope("InliningTest", new DebugDumpScope(snippet))) {
+            Method method = getMethod(snippet);
+            StructuredGraph graph = eagerInfopointMode ? parseDebug(method) : parse(method);
+            PhasePlan phasePlan = getDefaultPhasePlan(eagerInfopointMode);
+            Assumptions assumptions = new Assumptions(true);
+            HighTierContext context = new HighTierContext(getProviders(), assumptions, null, phasePlan, OptimisticOptimizations.ALL);
+            Debug.dump(graph, "Graph");
+            new CanonicalizerPhase(true).apply(graph, context);
+            new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
+            Debug.dump(graph, "Graph");
+            new CanonicalizerPhase(true).apply(graph, context);
+            new DeadCodeEliminationPhase().apply(graph);
+            return graph;
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
     }
 
     private static StructuredGraph assertInlined(StructuredGraph graph) {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Mon Dec 02 12:45:18 2013 +0100
@@ -27,7 +27,6 @@
 import static com.oracle.graal.phases.GraalOptions.*;
 
 import java.util.*;
-import java.util.concurrent.*;
 
 import com.oracle.graal.alloc.*;
 import com.oracle.graal.api.code.*;
@@ -36,6 +35,7 @@
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.debug.internal.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
@@ -132,49 +132,44 @@
      *            argument can be null.
      * @return the result of the compilation
      */
-    public static <T extends CompilationResult> T compileGraph(final StructuredGraph graph, final CallingConvention cc, final ResolvedJavaMethod installedCodeOwner, final Providers providers,
-                    final Backend backend, final TargetDescription target, final GraphCache cache, final PhasePlan plan, final OptimisticOptimizations optimisticOpts,
-                    final SpeculationLog speculationLog, final Suites suites, final T compilationResult) {
-        Debug.scope("GraalCompiler", new Object[]{graph, providers.getCodeCache()}, new Runnable() {
-
-            public void run() {
-                compileGraphNoScope(graph, cc, installedCodeOwner, providers, backend, target, cache, plan, optimisticOpts, speculationLog, suites, compilationResult);
-            }
-        });
-
+    public static <T extends CompilationResult> T compileGraph(StructuredGraph graph, CallingConvention cc, ResolvedJavaMethod installedCodeOwner, Providers providers, Backend backend,
+                    TargetDescription target, GraphCache cache, PhasePlan plan, OptimisticOptimizations optimisticOpts, SpeculationLog speculationLog, Suites suites, T compilationResult) {
+        try (Scope s = Debug.scope("GraalCompiler", graph, providers.getCodeCache())) {
+            compileGraphNoScope(graph, cc, installedCodeOwner, providers, backend, target, cache, plan, optimisticOpts, speculationLog, suites, compilationResult);
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
         return compilationResult;
     }
 
     /**
      * Same as {@link #compileGraph} but without entering a
-     * {@linkplain Debug#scope(String, Object[], Runnable) debug scope}.
+     * {@linkplain Debug#scope(String, Object...) debug scope}.
      */
-    public static <T extends CompilationResult> T compileGraphNoScope(final StructuredGraph graph, final CallingConvention cc, final ResolvedJavaMethod installedCodeOwner, final Providers providers,
-                    final Backend backend, final TargetDescription target, final GraphCache cache, final PhasePlan plan, final OptimisticOptimizations optimisticOpts,
-                    final SpeculationLog speculationLog, final Suites suites, final T compilationResult) {
-        final Assumptions assumptions = new Assumptions(OptAssumptions.getValue());
-        final LIR lir = Debug.scope("FrontEnd", new Callable<LIR>() {
+    public static <T extends CompilationResult> T compileGraphNoScope(StructuredGraph graph, CallingConvention cc, ResolvedJavaMethod installedCodeOwner, Providers providers, Backend backend,
+                    TargetDescription target, GraphCache cache, PhasePlan plan, OptimisticOptimizations optimisticOpts, SpeculationLog speculationLog, Suites suites, T compilationResult) {
+        Assumptions assumptions = new Assumptions(OptAssumptions.getValue());
 
-            public LIR call() {
-                try (TimerCloseable a = FrontEnd.start()) {
-                    return emitHIR(providers, target, graph, assumptions, cache, plan, optimisticOpts, speculationLog, suites);
-                }
+        LIR lir = null;
+        try (Scope s = Debug.scope("FrontEnd"); TimerCloseable a = FrontEnd.start()) {
+            lir = emitHIR(providers, target, graph, assumptions, cache, plan, optimisticOpts, speculationLog, suites);
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+        try (TimerCloseable a = BackEnd.start()) {
+            LIRGenerator lirGen = null;
+            try (Scope s = Debug.scope("BackEnd", lir)) {
+                lirGen = emitLIR(backend, target, lir, graph, cc);
+            } catch (Throwable e) {
+                throw Debug.handle(e);
             }
-        });
-        try (TimerCloseable a = BackEnd.start()) {
-            final LIRGenerator lirGen = Debug.scope("BackEnd", lir, new Callable<LIRGenerator>() {
-
-                public LIRGenerator call() {
-                    return emitLIR(backend, target, lir, graph, cc);
-                }
-            });
-            Debug.scope("CodeGen", lirGen, new Runnable() {
-
-                public void run() {
-                    emitCode(backend, getLeafGraphIdArray(graph), assumptions, lirGen, compilationResult, installedCodeOwner);
-                }
-
-            });
+            try (Scope s = Debug.scope("CodeGen", lirGen)) {
+                emitCode(backend, getLeafGraphIdArray(graph), assumptions, lirGen, compilationResult, installedCodeOwner);
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            }
+        } catch (Throwable e) {
+            throw Debug.handle(e);
         }
 
         return compilationResult;
@@ -193,8 +188,8 @@
     /**
      * Builds the graph, optimizes it.
      */
-    public static LIR emitHIR(Providers providers, TargetDescription target, final StructuredGraph graph, Assumptions assumptions, GraphCache cache, PhasePlan plan,
-                    OptimisticOptimizations optimisticOpts, final SpeculationLog speculationLog, final Suites suites) {
+    public static LIR emitHIR(Providers providers, TargetDescription target, StructuredGraph graph, Assumptions assumptions, GraphCache cache, PhasePlan plan, OptimisticOptimizations optimisticOpts,
+                    SpeculationLog speculationLog, Suites suites) {
 
         if (speculationLog != null) {
             speculationLog.snapshot();
@@ -224,68 +219,63 @@
             InliningPhase.storeStatisticsAfterLowTier(graph);
         }
 
-        final SchedulePhase schedule = new SchedulePhase();
+        SchedulePhase schedule = new SchedulePhase();
         schedule.apply(graph);
         Debug.dump(schedule, "final schedule");
 
-        final Block[] blocks = schedule.getCFG().getBlocks();
-        final Block startBlock = schedule.getCFG().getStartBlock();
+        Block[] blocks = schedule.getCFG().getBlocks();
+        Block startBlock = schedule.getCFG().getStartBlock();
         assert startBlock != null;
         assert startBlock.getPredecessorCount() == 0;
 
-        return Debug.scope("ComputeLinearScanOrder", new Callable<LIR>() {
+        try (Scope s = Debug.scope("ComputeLinearScanOrder")) {
+            NodesToDoubles nodeProbabilities = new ComputeProbabilityClosure(graph).apply();
+            List<Block> codeEmittingOrder = ComputeBlockOrder.computeCodeEmittingOrder(blocks.length, startBlock, nodeProbabilities);
+            List<Block> linearScanOrder = ComputeBlockOrder.computeLinearScanOrder(blocks.length, startBlock, nodeProbabilities);
 
-            @Override
-            public LIR call() {
-                NodesToDoubles nodeProbabilities = new ComputeProbabilityClosure(graph).apply();
-                List<Block> codeEmittingOrder = ComputeBlockOrder.computeCodeEmittingOrder(blocks.length, startBlock, nodeProbabilities);
-                List<Block> linearScanOrder = ComputeBlockOrder.computeLinearScanOrder(blocks.length, startBlock, nodeProbabilities);
-
-                LIR lir = new LIR(schedule.getCFG(), schedule.getBlockToNodesMap(), linearScanOrder, codeEmittingOrder);
-                Debug.dump(lir, "After linear scan order");
-                return lir;
-
-            }
-        });
+            LIR lir = new LIR(schedule.getCFG(), schedule.getBlockToNodesMap(), linearScanOrder, codeEmittingOrder);
+            Debug.dump(lir, "After linear scan order");
+            return lir;
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
 
     }
 
-    public static LIRGenerator emitLIR(final Backend backend, final TargetDescription target, final LIR lir, StructuredGraph graph, CallingConvention cc) {
-        final FrameMap frameMap = backend.newFrameMap();
-        final LIRGenerator lirGen = backend.newLIRGenerator(graph, frameMap, cc, lir);
-
-        Debug.scope("LIRGen", lirGen, new Runnable() {
+    private static void emitBlock(LIRGenerator lirGen, Block b) {
+        if (lirGen.lir.lir(b) == null) {
+            for (Block pred : b.getPredecessors()) {
+                if (!b.isLoopHeader() || !pred.isLoopEnd()) {
+                    emitBlock(lirGen, pred);
+                }
+            }
+            lirGen.doBlock(b);
+        }
+    }
 
-            public void run() {
-                for (Block b : lir.linearScanOrder()) {
-                    emitBlock(b);
-                }
+    public static LIRGenerator emitLIR(Backend backend, TargetDescription target, LIR lir, StructuredGraph graph, CallingConvention cc) {
+        FrameMap frameMap = backend.newFrameMap();
+        LIRGenerator lirGen = backend.newLIRGenerator(graph, frameMap, cc, lir);
 
-                Debug.dump(lir, "After LIR generation");
+        try (Scope s = Debug.scope("LIRGen", lirGen)) {
+            for (Block b : lir.linearScanOrder()) {
+                emitBlock(lirGen, b);
             }
 
-            private void emitBlock(Block b) {
-                if (lir.lir(b) == null) {
-                    for (Block pred : b.getPredecessors()) {
-                        if (!b.isLoopHeader() || !pred.isLoopEnd()) {
-                            emitBlock(pred);
-                        }
-                    }
-                    lirGen.doBlock(b);
-                }
-            }
-        });
+            Debug.dump(lir, "After LIR generation");
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
 
         lirGen.beforeRegisterAllocation();
 
-        Debug.scope("Allocator", new Runnable() {
-
-            public void run() {
-                if (backend.shouldAllocateRegisters()) {
-                    new LinearScan(target, lir, lirGen, frameMap).allocate();
-                }
+        try (Scope s = Debug.scope("Allocator")) {
+            if (backend.shouldAllocateRegisters()) {
+                new LinearScan(target, lir, lirGen, frameMap).allocate();
             }
-        });
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
         return lirGen;
     }
 
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java	Mon Dec 02 12:45:18 2013 +0100
@@ -37,6 +37,7 @@
 import com.oracle.graal.compiler.alloc.Interval.SpillState;
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.LIRInstruction.OperandFlag;
@@ -1818,66 +1819,61 @@
 
     public void allocate() {
 
-        Debug.scope("LifetimeAnalysis", new Runnable() {
-
-            public void run() {
-                numberInstructions();
-                printLir("Before register allocation", true);
-                computeLocalLiveSets();
-                computeGlobalLiveSets();
-                buildIntervals();
-                sortIntervalsBeforeAllocation();
-            }
-        });
-
-        Debug.scope("RegisterAllocation", new Runnable() {
+        try (Scope s = Debug.scope("LifetimeAnalysis")) {
+            numberInstructions();
+            printLir("Before register allocation", true);
+            computeLocalLiveSets();
+            computeGlobalLiveSets();
+            buildIntervals();
+            sortIntervalsBeforeAllocation();
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
 
-            public void run() {
-                printIntervals("Before register allocation");
-                allocateRegisters();
-            }
-        });
+        try (Scope s = Debug.scope("RegisterAllocation")) {
+            printIntervals("Before register allocation");
+            allocateRegisters();
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
 
-        Debug.scope("ResolveDataFlow", new Runnable() {
+        try (Scope s = Debug.scope("ResolveDataFlow")) {
+            resolveDataFlow();
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
 
-            public void run() {
-                resolveDataFlow();
-            }
-        });
-
-        Debug.scope("DebugInfo", new Runnable() {
+        try (Scope s = Debug.scope("DebugInfo")) {
+            frameMap.finish();
 
-            public void run() {
-                frameMap.finish();
+            printIntervals("After register allocation");
+            printLir("After register allocation", true);
 
-                printIntervals("After register allocation");
-                printLir("After register allocation", true);
+            sortIntervalsAfterAllocation();
 
-                sortIntervalsAfterAllocation();
+            if (DetailedAsserts.getValue()) {
+                verify();
+            }
 
-                if (DetailedAsserts.getValue()) {
-                    verify();
-                }
-
-                eliminateSpillMoves();
-                assignLocations();
+            eliminateSpillMoves();
+            assignLocations();
 
-                if (DetailedAsserts.getValue()) {
-                    verifyIntervals();
-                }
+            if (DetailedAsserts.getValue()) {
+                verifyIntervals();
             }
-        });
-
-        Debug.scope("ControlFlowOptimizations", new Runnable() {
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
 
-            public void run() {
-                printLir("After register number assignment", true);
-                EdgeMoveOptimizer.optimize(ir);
-                ControlFlowOptimizer.optimize(ir);
-                NullCheckOptimizer.optimize(ir, target.implicitNullCheckLimit);
-                printLir("After control flow optimization", false);
-            }
-        });
+        try (Scope s = Debug.scope("ControlFlowOptimizations")) {
+            printLir("After register number assignment", true);
+            EdgeMoveOptimizer.optimize(ir);
+            ControlFlowOptimizer.optimize(ir);
+            NullCheckOptimizer.optimize(ir, target.implicitNullCheckLimit);
+            printLir("After control flow optimization", false);
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
     }
 
     void printIntervals(String label) {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java	Mon Dec 02 12:45:18 2013 +0100
@@ -37,7 +37,7 @@
 
 public class HighTier extends PhaseSuite<HighTierContext> {
 
-    static class Options {
+    public static class Options {
 
         // @formatter:off
         @Option(help = "")
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/MidTier.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/MidTier.java	Mon Dec 02 12:45:18 2013 +0100
@@ -89,7 +89,9 @@
 
         appendPhase(new FrameStateAssignmentPhase());
 
-        appendPhase(new DeoptimizationGroupingPhase());
+        if (OptDeoptimizationGrouping.getValue()) {
+            appendPhase(new DeoptimizationGroupingPhase());
+        }
 
         if (OptCanonicalizer.getValue()) {
             appendPhase(canonicalizer);
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java	Mon Dec 02 12:45:18 2013 +0100
@@ -105,68 +105,10 @@
         return callable;
     }
 
-    public static void sandbox(String name, DebugConfig config, Runnable runnable) {
-        if (ENABLED) {
-            DebugScope.getInstance().scope(name, runnable, null, true, config, new Object[0]);
-        } else {
-            runnable.run();
-        }
-    }
-
     /**
-     * Creates a new debug scope that is unrelated to the current scope and runs a given task in the
-     * new scope.
-     * 
-     * @param name new scope name
-     * @param context the context objects of the new scope
-     * @param config the debug configuration to use for the new scope
-     * @param runnable the task to run in the new scope
+     * Gets a string composed of the names in the current nesting of debug
+     * {@linkplain #scope(String, Object...) scopes} separated by {@code '.'}.
      */
-    public static void sandbox(String name, Object[] context, DebugConfig config, Runnable runnable) {
-        if (ENABLED) {
-            DebugScope.getInstance().scope(name, runnable, null, true, config, context);
-        } else {
-            runnable.run();
-        }
-    }
-
-    /**
-     * Creates a new debug scope that is unrelated to the current scope and runs a given task in the
-     * new scope.
-     * 
-     * @param name new scope name
-     * @param context the context objects of the new scope
-     * @param config the debug configuration to use for the new scope
-     * @param callable the task to run in the new scope
-     */
-    public static <T> T sandbox(String name, Object[] context, DebugConfig config, Callable<T> callable) {
-        if (ENABLED) {
-            return DebugScope.getInstance().scope(name, null, callable, true, config, context);
-        } else {
-            return DebugScope.call(callable);
-        }
-    }
-
-    public static void scope(String name, Runnable runnable) {
-        scope(name, new Object[0], runnable);
-    }
-
-    public static <T> T scope(String name, Callable<T> callable) {
-        return scope(name, new Object[0], callable);
-    }
-
-    public static void scope(String name, Object context, Runnable runnable) {
-        scope(name, new Object[]{context}, runnable);
-    }
-
-    public static void scope(String name, Object[] context, Runnable runnable) {
-        if (ENABLED) {
-            DebugScope.getInstance().scope(name, runnable, null, false, null, context);
-        } else {
-            runnable.run();
-        }
-    }
-
     public static String currentScope() {
         if (ENABLED) {
             return DebugScope.getInstance().getQualifiedName();
@@ -175,20 +117,97 @@
         }
     }
 
-    public static <T> T scope(String name, Object context, Callable<T> callable) {
-        return scope(name, new Object[]{context}, callable);
+    /**
+     * Represents a debug scope entered by {@link Debug#scope(String, Object...)} or
+     * {@link Debug#sandbox(String, DebugConfig, Object...)}. Leaving the scope is achieved via
+     * {@link #close()}.
+     */
+    public interface Scope extends AutoCloseable {
+        void close();
     }
 
-    public static <T> T scope(String name, Object[] context, Callable<T> callable) {
+    /**
+     * Creates and enters a new debug scope which will be a child of the current debug scope.
+     * <p>
+     * It is recommended to use the try-with-resource statement for managing entering and leaving
+     * debug scopes. For example:
+     * 
+     * <pre>
+     * try (Scope s = Debug.scope(&quot;InliningGraph&quot;, inlineeGraph)) {
+     *     ...
+     * } catch (Throwable e) {
+     *     throw Debug.handle(e);
+     * }
+     * </pre>
+     * 
+     * @param name the name of the new scope
+     * @param context objects to be appended to the {@linkplain #context() current} debug context
+     * @return the scope entered by this method which will be exited when its {@link Scope#close()}
+     *         method is called
+     */
+    public static Scope scope(String name, Object... context) {
         if (ENABLED) {
-            return DebugScope.getInstance().scope(name, null, callable, false, null, context);
+            return DebugScope.getInstance().scope(name, false, null, context);
         } else {
-            return DebugScope.call(callable);
+            return null;
         }
     }
 
     /**
-     * Prints an indented message to the current DebugLevel's logging stream if logging is enabled.
+     * Creates and enters a new debug scope which will be disjoint from the current debug scope.
+     * <p>
+     * It is recommended to use the try-with-resource statement for managing entering and leaving
+     * debug scopes. For example:
+     * 
+     * <pre>
+     * try (Scope s = Debug.sandbox(&quot;CompilingStub&quot;, null, stubGraph)) {
+     *     ...
+     * } catch (Throwable e) {
+     *     throw Debug.handle(e);
+     * }
+     * </pre>
+     * 
+     * @param name the name of the new scope
+     * @param config the debug configuration to use for the new scope
+     * @param context objects to be appended to the {@linkplain #context() current} debug context
+     * @return the scope entered by this method which will be exited when its {@link Scope#close()}
+     *         method is called
+     */
+    public static Scope sandbox(String name, DebugConfig config, Object... context) {
+        if (ENABLED) {
+            DebugConfig sandboxConfig = config == null ? silentConfig() : config;
+            return DebugScope.getInstance().scope(name, true, sandboxConfig, context);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Handles an exception in the context of the debug scope just exited. The just exited scope
+     * must have the current scope as its parent which will be the case if the try-with-resource
+     * pattern recommended by {@link #scope(String, Object...)} and
+     * {@link #sandbox(String, DebugConfig, Object...)} is used
+     * 
+     * @see #scope(String, Object...)
+     * @see #sandbox(String, DebugConfig, Object...)
+     */
+    public static RuntimeException handle(Throwable exception) {
+        if (ENABLED) {
+            return DebugScope.getInstance().handle(exception);
+        } else {
+            if (exception instanceof Error) {
+                throw (Error) exception;
+            }
+            if (exception instanceof RuntimeException) {
+                throw (RuntimeException) exception;
+            }
+            throw new RuntimeException(exception);
+        }
+    }
+
+    /**
+     * Prints an indented message to the current debug scopes's logging stream if logging is enabled
+     * in the scope.
      * 
      * @param msg The format string of the log message
      * @param args The arguments referenced by the log message string
@@ -231,7 +250,7 @@
         }
 
         @Override
-        public Indent logIndent(String msg, Object... args) {
+        public Indent logAndIndent(String msg, Object... args) {
             return this;
         }
 
@@ -240,6 +259,9 @@
             return this;
         }
 
+        @Override
+        public void close() {
+        }
     }
 
     private static final NoLogger noLoggerInstance = new NoLogger();
@@ -281,9 +303,9 @@
      * @param msg The format string of the log message
      * @param args The arguments referenced by the log message string
      * @return The new indentation level
-     * @see Indent#logIndent
+     * @see Indent#logAndIndent
      */
-    public static Indent logIndent(String msg, Object... args) {
+    public static Indent logAndIndent(String msg, Object... args) {
         if (ENABLED) {
             DebugScope scope = DebugScope.getInstance();
             scope.log(msg, args);
@@ -300,7 +322,7 @@
      * @param args The arguments referenced by the log message string
      * @return The new indentation level
      */
-    public static Indent logIndent(boolean enabled, String msg, Object... args) {
+    public static Indent logAndIndent(boolean enabled, String msg, Object... args) {
         if (ENABLED) {
             DebugScope scope = DebugScope.getInstance();
             boolean saveLogEnabled = scope.isLogEnabled();
@@ -373,9 +395,19 @@
         }
     }
 
-    public static void setConfig(DebugConfig config) {
+    /**
+     * Changes the debug configuration for the current thread.
+     * 
+     * @param config new configuration to use for the current thread
+     * @return an object that when {@linkplain DebugConfigScope#close() closed} will restore the
+     *         debug configuration for the current thread to what it was before this method was
+     *         called
+     */
+    public static DebugConfigScope setConfig(DebugConfig config) {
         if (ENABLED) {
-            DebugScope.getInstance().setConfig(config);
+            return new DebugConfigScope(config);
+        } else {
+            return null;
         }
     }
 
@@ -386,6 +418,10 @@
         return new DebugHistogramImpl(name);
     }
 
+    public static DebugConfig silentConfig() {
+        return fixedConfig(false, false, false, false, Collections.<DebugDumpHandler> emptyList(), System.out);
+    }
+
     public static DebugConfig fixedConfig(final boolean isLogEnabled, final boolean isDumpEnabled, final boolean isMeterEnabled, final boolean isTimerEnabled,
                     final Collection<DebugDumpHandler> dumpHandlers, final PrintStream output) {
         return new DebugConfig() {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugConfigScope.java	Mon Dec 02 12:45:18 2013 +0100
@@ -0,0 +1,55 @@
+/*
+ * 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.graal.debug;
+
+import com.oracle.graal.debug.internal.*;
+
+/**
+ * A utility for scoping a change to the current debug
+ * {@linkplain DebugScope#setConfig(DebugConfig) configuration}. For example:
+ * 
+ * <pre>
+ *     DebugConfig config = ...;
+ *     try (DebugConfigScope s = new DebugConfigScope(config)) {
+ *         // ...
+ *     }
+ * </pre>
+ */
+public class DebugConfigScope implements AutoCloseable {
+
+    private final DebugConfig current;
+
+    /**
+     * Sets the current debug {@linkplain DebugScope#setConfig(DebugConfig) configuration} to a
+     * given value and creates an object that when {@linkplain #close() closed} resets the
+     * configuration to the {@linkplain DebugScope#getConfig() current} configuration.
+     */
+    public DebugConfigScope(DebugConfig config) {
+        this.current = DebugScope.getConfig();
+        DebugScope.getInstance().setConfig(config);
+    }
+
+    public void close() {
+        DebugScope.getInstance().setConfig(current);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DelegatingDebugConfig.java	Mon Dec 02 12:45:18 2013 +0100
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.debug;
+
+import java.io.*;
+import java.util.*;
+
+public class DelegatingDebugConfig implements DebugConfig {
+
+    protected final DebugConfig delegate;
+
+    public DelegatingDebugConfig(DebugConfig delegate) {
+        this.delegate = delegate;
+    }
+
+    @Override
+    public boolean isLogEnabled() {
+        return delegate.isLogEnabled();
+    }
+
+    @Override
+    public boolean isMeterEnabled() {
+        return delegate.isMeterEnabled();
+    }
+
+    @Override
+    public boolean isDumpEnabled() {
+        return delegate.isDumpEnabled();
+    }
+
+    @Override
+    public boolean isTimeEnabled() {
+        return delegate.isTimeEnabled();
+    }
+
+    @Override
+    public RuntimeException interceptException(Throwable e) {
+        return delegate.interceptException(e);
+    }
+
+    @Override
+    public Collection<DebugDumpHandler> dumpHandlers() {
+        return delegate.dumpHandlers();
+    }
+
+    @Override
+    public PrintStream output() {
+        return delegate.output();
+    }
+
+    @Override
+    public void addToContext(Object o) {
+        delegate.addToContext(o);
+    }
+
+    @Override
+    public void removeFromContext(Object o) {
+        delegate.removeFromContext(o);
+    }
+}
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Indent.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Indent.java	Mon Dec 02 12:45:18 2013 +0100
@@ -48,8 +48,20 @@
  *          in.outdent();
  *      }
  * </pre>
+ * 
+ * Example usage with try-with-resources:
+ * 
+ * <pre>
+ * 
+ *      try (Indent in = Debug.logIndent("header message")) {
+ *          ...
+ *          in.log("message");
+ *          ...
+ *      }
+ * 
+ * </pre>
  */
-public interface Indent {
+public interface Indent extends AutoCloseable {
 
     /**
      * Prints an indented message to the DebugLevel's logging stream if logging is enabled.
@@ -81,9 +93,9 @@
      * @param msg The format string of the log message
      * @param args The arguments referenced by the log message string
      * @return The new indentation level
-     * @see Debug#logIndent
+     * @see Debug#logAndIndent
      */
-    Indent logIndent(String msg, Object... args);
+    Indent logAndIndent(String msg, Object... args);
 
     /**
      * Restores the previous indent level. Calling this method is important to restore the correct
@@ -92,4 +104,6 @@
      * @return The indent level from which this Indent was created.
      */
     Indent outdent();
+
+    void close();
 }
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugScope.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugScope.java	Mon Dec 02 12:45:18 2013 +0100
@@ -28,7 +28,7 @@
 
 import com.oracle.graal.debug.*;
 
-public final class DebugScope {
+public final class DebugScope implements Debug.Scope {
 
     private final class IndentImpl implements Indent {
 
@@ -75,7 +75,7 @@
         }
 
         @Override
-        public Indent logIndent(String msg, Object... args) {
+        public Indent logAndIndent(String msg, Object... args) {
             log(msg, args);
             return indent();
         }
@@ -87,17 +87,25 @@
             }
             return lastUsedIndent;
         }
+
+        @Override
+        public void close() {
+            outdent();
+        }
     }
 
     private static ThreadLocal<DebugScope> instanceTL = new ThreadLocal<>();
+    private static ThreadLocal<DebugScope> lastClosedTL = new ThreadLocal<>();
     private static ThreadLocal<DebugConfig> configTL = new ThreadLocal<>();
     private static ThreadLocal<Throwable> lastExceptionThrownTL = new ThreadLocal<>();
 
     private final DebugScope parent;
+    private final DebugConfig parentConfig;
+    private final boolean sandbox;
     private IndentImpl lastUsedIndent;
     private boolean logScopeName;
 
-    private Object[] context;
+    private final Object[] context;
 
     private final DebugValueMap valueMap;
     private final String qualifiedName;
@@ -113,7 +121,7 @@
     public static DebugScope getInstance() {
         DebugScope result = instanceTL.get();
         if (result == null) {
-            DebugScope topLevelDebugScope = new DebugScope(Thread.currentThread().getName(), "", null);
+            DebugScope topLevelDebugScope = new DebugScope(Thread.currentThread().getName(), "", null, false);
             instanceTL.set(topLevelDebugScope);
             DebugValueMap.registerTopLevel(topLevelDebugScope.getValueMap());
             return topLevelDebugScope;
@@ -126,8 +134,10 @@
         return configTL.get();
     }
 
-    private DebugScope(String name, String qualifiedName, DebugScope parent, Object... context) {
+    private DebugScope(String name, String qualifiedName, DebugScope parent, boolean sandbox, Object... context) {
         this.parent = parent;
+        this.sandbox = sandbox;
+        this.parentConfig = getConfig();
         this.context = context;
         this.qualifiedName = qualifiedName;
         if (parent != null) {
@@ -157,6 +167,12 @@
         }
     }
 
+    public void close() {
+        instanceTL.set(parent);
+        setConfig(parentConfig);
+        lastClosedTL.set(this);
+    }
+
     public boolean isDumpEnabled() {
         return dumpEnabled;
     }
@@ -216,65 +232,56 @@
     }
 
     /**
-     * Runs a task in a new debug scope which is either a child of the current scope or a disjoint
-     * top level scope.
+     * Creates and enters a new debug scope which is either a child of the current scope or a
+     * disjoint top level scope.
      * 
-     * @param newName the name of the new scope
-     * @param runnable the task to run (must be null iff {@code callable} is not null)
-     * @param callable the task to run (must be null iff {@code runnable} is not null)
+     * @param name the name of the new scope
      * @param sandbox specifies if the scope is a child of the current scope or a top level scope
-     * @param sandboxConfig the config to use of a new top level scope (ignored if
+     * @param sandboxConfig the configuration to use for a new top level scope (ignored if
      *            {@code sandbox == false})
-     * @param newContext context objects of the new scope
-     * @return the value returned by the task
+     * @param context objects to be appended to the debug context
+     * @return the new scope which will be exited when its {@link #close()} method is called
      */
-    public <T> T scope(String newName, Runnable runnable, Callable<T> callable, boolean sandbox, DebugConfig sandboxConfig, Object[] newContext) {
-        DebugScope oldContext = getInstance();
-        DebugConfig oldConfig = getConfig();
-        boolean oldLogEnabled = oldContext.isLogEnabled();
-        DebugScope newChild = null;
+    @SuppressWarnings("hiding")
+    public DebugScope scope(String name, boolean sandbox, DebugConfig sandboxConfig, Object... context) {
+        DebugScope newScope = null;
         if (sandbox) {
-            newChild = new DebugScope(newName, newName, null, newContext);
+            newScope = new DebugScope(name, name, this, true, context);
             setConfig(sandboxConfig);
         } else {
-            newChild = oldContext.createChild(newName, newContext);
+            newScope = this.createChild(name, context);
         }
-        instanceTL.set(newChild);
-        newChild.updateFlags();
-        try {
-            return executeScope(runnable, callable);
-        } finally {
-            newChild.context = null;
-            instanceTL.set(oldContext);
-            setConfig(oldConfig);
-            setLogEnabled(oldLogEnabled);
-        }
+        instanceTL.set(newScope);
+        newScope.setLogEnabled(this.isLogEnabled());
+        newScope.updateFlags();
+        return newScope;
     }
 
-    private <T> T executeScope(Runnable runnable, Callable<T> callable) {
-
-        try {
-            if (runnable != null) {
-                runnable.run();
-            }
-            if (callable != null) {
-                return call(callable);
+    public RuntimeException handle(Throwable e) {
+        DebugScope lastClosed = lastClosedTL.get();
+        assert lastClosed.parent == this : "Debug.handle() used with no matching Debug.scope(...) or Debug.sandbox(...)";
+        if (e != lastExceptionThrownTL.get()) {
+            RuntimeException newException = null;
+            instanceTL.set(lastClosed);
+            try (DebugScope s = lastClosed) {
+                newException = s.interceptException(e);
             }
-        } catch (Throwable e) {
-            if (e == lastExceptionThrownTL.get()) {
-                throw e;
+            assert instanceTL.get() == this;
+            assert lastClosed == lastClosedTL.get();
+            if (newException == null) {
+                lastExceptionThrownTL.set(e);
             } else {
-                RuntimeException newException = interceptException(e);
-                if (newException == null) {
-                    lastExceptionThrownTL.set(e);
-                    throw e;
-                } else {
-                    lastExceptionThrownTL.set(newException);
-                    throw newException;
-                }
+                lastExceptionThrownTL.set(newException);
+                throw newException;
             }
         }
-        return null;
+        if (e instanceof Error) {
+            throw (Error) e;
+        }
+        if (e instanceof RuntimeException) {
+            throw (RuntimeException) e;
+        }
+        throw new RuntimeException(e);
     }
 
     private void updateFlags() {
@@ -283,7 +290,6 @@
             meterEnabled = false;
             timeEnabled = false;
             dumpEnabled = false;
-            setLogEnabled(false);
 
             // Be pragmatic: provide a default log stream to prevent a crash if the stream is not
             // set while logging
@@ -293,24 +299,20 @@
             timeEnabled = config.isTimeEnabled();
             dumpEnabled = config.isDumpEnabled();
             output = config.output();
-            setLogEnabled(config.isLogEnabled());
+            if (config.isLogEnabled()) {
+                setLogEnabled(true);
+            }
         }
     }
 
     private RuntimeException interceptException(final Throwable e) {
         final DebugConfig config = getConfig();
         if (config != null) {
-            return scope("InterceptException", null, new Callable<RuntimeException>() {
-
-                @Override
-                public RuntimeException call() throws Exception {
-                    try {
-                        return config.interceptException(e);
-                    } catch (Throwable t) {
-                        return new RuntimeException("Exception while intercepting exception", t);
-                    }
-                }
-            }, false, null, new Object[]{e});
+            try (DebugScope s = scope("InterceptException", false, null, e)) {
+                return config.interceptException(e);
+            } catch (Throwable t) {
+                return new RuntimeException("Exception while intercepting exception", t);
+            }
         }
         return null;
     }
@@ -332,7 +334,7 @@
         if (this.qualifiedName.length() > 0) {
             newQualifiedName = this.qualifiedName + SCOPE_SEP + newName;
         }
-        DebugScope result = new DebugScope(newName, newQualifiedName, this, newContext);
+        DebugScope result = new DebugScope(newName, newQualifiedName, this, false, newContext);
         return result;
     }
 
@@ -355,7 +357,7 @@
 
                     private void selectScope() {
                         while (currentScope != null && currentScope.context.length <= objectIndex) {
-                            currentScope = currentScope.parent;
+                            currentScope = currentScope.sandbox ? null : currentScope.parent;
                             objectIndex = 0;
                         }
                     }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Mon Dec 02 12:45:18 2013 +0100
@@ -75,6 +75,11 @@
     NodeChangedListener usagesDroppedToZeroListener;
     private final HashMap<CacheEntry, Node> cachedNodes = new HashMap<>();
 
+    /**
+     * Determines if external nodes will use {@link Graph}'s canonicalization cache.
+     */
+    public static final boolean CacheExternalNodesInGraph = Boolean.parseBoolean(System.getProperty("graal.cacheExternalNodesInGraph", "false"));
+
     private static final class CacheEntry {
 
         private final Node node;
@@ -343,7 +348,7 @@
     }
 
     /**
-     * Looks for a node <i>similar</i> to {@code node}. If not found, {@code node} is added to the
+     * Looks for a node <i>similar</i> to {@code node}. If not found, {@code node} is added to a
      * cache in this graph used to canonicalize nodes.
      * <p>
      * Note that node must implement {@link ValueNumberable} and must be an
@@ -351,9 +356,12 @@
      * 
      * @return a node similar to {@code node} if one exists, otherwise {@code node}
      */
-    public <T extends Node> T uniqueWithoutAdd(T node) {
+    public <T extends Node> T uniqueExternal(T node) {
         assert node.isExternal() : node;
         assert node instanceof ValueNumberable : node;
+        if (!CacheExternalNodesInGraph) {
+            return node;
+        }
         return uniqueHelper(node, false);
     }
 
@@ -380,6 +388,7 @@
     }
 
     Node findNodeInCache(Node node) {
+        assert !node.isExternal() || CacheExternalNodesInGraph;
         CacheEntry key = new CacheEntry(node);
         Node result = cachedNodes.get(key);
         if (result != null && result.isDeleted()) {
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Mon Dec 02 12:45:18 2013 +0100
@@ -712,7 +712,7 @@
     }
 
     /**
-     * Determines if a given node is {@linkplain Graph#uniqueWithoutAdd(Node) unique} within a given
+     * Determines if a given node is {@linkplain Graph#uniqueExternal(Node) unique} within a given
      * graph if the node is non-null and {@linkplain #isExternal() external}.
      * 
      * @param node node to check
@@ -721,7 +721,7 @@
      *         {@link VerificationError}
      */
     public static boolean verifyUniqueIfExternal(Node node, Graph graph) {
-        if (node != null && node.isExternal()) {
+        if (node != null && node.isExternal() && Graph.CacheExternalNodesInGraph) {
             Node cached = graph.findNodeInCache(node);
             node.assertTrue(cached == node, "external node does not match canonical node %s", cached);
         }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Mon Dec 02 12:45:18 2013 +0100
@@ -158,13 +158,17 @@
      */
     private final boolean isSimplifiable;
 
-    private NodeClass(Class<?> clazz) {
+    public NodeClass(Class<?> clazz) {
+        this(clazz, new DefaultCalcOffset(), null, 0);
+    }
+
+    public NodeClass(Class<?> clazz, CalcOffset calcOffset, int[] presetIterableIds, int presetIterableId) {
         super(clazz);
         assert NODE_CLASS.isAssignableFrom(clazz);
         this.isCanonicalizable = Canonicalizable.class.isAssignableFrom(clazz);
         this.isSimplifiable = Simplifiable.class.isAssignableFrom(clazz);
 
-        FieldScanner scanner = new FieldScanner(new DefaultCalcOffset());
+        FieldScanner scanner = new FieldScanner(calcOffset);
         scanner.scan(clazz);
 
         directInputCount = scanner.inputOffsets.size();
@@ -200,7 +204,10 @@
         }
         this.nameTemplate = newNameTemplate == null ? newShortName : newNameTemplate;
         this.shortName = newShortName;
-        if (IterableNodeType.class.isAssignableFrom(clazz)) {
+        if (presetIterableIds != null) {
+            this.iterableIds = presetIterableIds;
+            this.iterableId = presetIterableId;
+        } else if (IterableNodeType.class.isAssignableFrom(clazz)) {
             ITERABLE_NODE_TYPES.increment();
             this.iterableId = nextIterableId++;
             List<NodeClass> existingClasses = new LinkedList<>();
@@ -931,6 +938,8 @@
                 Node newInput = duplicationReplacement.replacement(input, true);
                 node.updateUsages(null, newInput);
                 assert Node.verifyUniqueIfExternal(newInput, node.graph());
+                assert newInput == null || fieldTypes.get(inputOffsets[index]).isAssignableFrom(newInput.getClass()) : "Can not assign " + newInput.getClass() + " to " +
+                                fieldTypes.get(inputOffsets[index]) + " in " + node;
                 putNode(node, inputOffsets[index], newInput);
             }
             index++;
@@ -946,6 +955,8 @@
             if (successor != null) {
                 Node newSucc = duplicationReplacement.replacement(successor, false);
                 node.updatePredecessor(null, newSucc);
+                assert newSucc == null || fieldTypes.get(successorOffsets[index]).isAssignableFrom(newSucc.getClass()) : fieldTypes.get(successorOffsets[index]) + " is not compatible with " +
+                                newSucc.getClass();
                 putNode(node, successorOffsets[index], newSucc);
             }
             index++;
@@ -1374,7 +1385,7 @@
 
             public Node replacement(Node node, boolean isInput) {
                 if (node.isExternal() && node instanceof ValueNumberable) {
-                    return graph.uniqueWithoutAdd(node);
+                    return graph.uniqueExternal(node);
                 }
                 Node target = newNodes.get(node);
                 if (target == null) {
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java	Mon Dec 02 12:45:18 2013 +0100
@@ -84,7 +84,7 @@
     }
 
     protected Replacements createReplacements(HotSpotGraalRuntime runtime, Assumptions assumptions, Providers p) {
-        return new HotSpotReplacementsImpl(p, runtime.getConfig(), assumptions);
+        return new HotSpotReplacementsImpl(p, runtime.getConfig(), assumptions, p.getCodeCache().getTarget());
     }
 
     protected AMD64HotSpotForeignCallsProvider createForeignCalls(HotSpotGraalRuntime runtime, HotSpotMetaAccessProvider metaAccess, HotSpotCodeCacheProvider codeCache,
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java	Mon Dec 02 12:45:18 2013 +0100
@@ -36,6 +36,7 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.*;
 
@@ -61,11 +62,29 @@
         register(new HotSpotForeignCallLinkage(EXCEPTION_HANDLER, 0L, PRESERVES_REGISTERS, LEAF, null, exceptionCc, NOT_REEXECUTABLE, ANY_LOCATION));
         register(new HotSpotForeignCallLinkage(EXCEPTION_HANDLER_IN_CALLER, JUMP_ADDRESS, PRESERVES_REGISTERS, LEAF, exceptionCc, null, NOT_REEXECUTABLE, ANY_LOCATION));
 
+        // When the java.ext.dirs property is modified then the crypto classes might not be found.
+        // If that's the case we ignore the ClassNotFoundException and continue since we cannot
+        // replace a non-existing method anyway.
+        try {
+            // These stubs do callee saving
+            registerForeignCall(ENCRYPT_BLOCK, config.aescryptEncryptBlockStub, NativeCall, PRESERVES_REGISTERS, LEAF, NOT_REEXECUTABLE, ANY_LOCATION);
+            registerForeignCall(DECRYPT_BLOCK, config.aescryptDecryptBlockStub, NativeCall, PRESERVES_REGISTERS, LEAF, NOT_REEXECUTABLE, ANY_LOCATION);
+        } catch (GraalInternalError e) {
+            if (!(e.getCause() instanceof ClassNotFoundException)) {
+                throw e;
+            }
+        }
+        try {
+            // These stubs do callee saving
+            registerForeignCall(ENCRYPT, config.cipherBlockChainingEncryptAESCryptStub, NativeCall, PRESERVES_REGISTERS, LEAF, NOT_REEXECUTABLE, ANY_LOCATION);
+            registerForeignCall(DECRYPT, config.cipherBlockChainingDecryptAESCryptStub, NativeCall, PRESERVES_REGISTERS, LEAF, NOT_REEXECUTABLE, ANY_LOCATION);
+        } catch (GraalInternalError e) {
+            if (!(e.getCause() instanceof ClassNotFoundException)) {
+                throw e;
+            }
+        }
+
         // These stubs do callee saving
-        registerForeignCall(ENCRYPT_BLOCK, config.aescryptEncryptBlockStub, NativeCall, PRESERVES_REGISTERS, LEAF, NOT_REEXECUTABLE, ANY_LOCATION);
-        registerForeignCall(DECRYPT_BLOCK, config.aescryptDecryptBlockStub, NativeCall, PRESERVES_REGISTERS, LEAF, NOT_REEXECUTABLE, ANY_LOCATION);
-        registerForeignCall(ENCRYPT, config.cipherBlockChainingEncryptAESCryptStub, NativeCall, PRESERVES_REGISTERS, LEAF, NOT_REEXECUTABLE, ANY_LOCATION);
-        registerForeignCall(DECRYPT, config.cipherBlockChainingDecryptAESCryptStub, NativeCall, PRESERVES_REGISTERS, LEAF, NOT_REEXECUTABLE, ANY_LOCATION);
         registerForeignCall(UPDATE_BYTES_CRC32, config.updateBytesCRC32Stub, NativeCall, PRESERVES_REGISTERS, LEAF, NOT_REEXECUTABLE, ANY_LOCATION);
 
         super.initialize(providers, config);
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILCompilationResult.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILCompilationResult.java	Mon Dec 02 12:45:18 2013 +0100
@@ -26,8 +26,6 @@
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 
 import java.lang.reflect.*;
-import java.util.logging.*;
-
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.code.CallingConvention.Type;
 import com.oracle.graal.api.meta.*;
@@ -71,30 +69,6 @@
         return installedCode;
     }
 
-    private static final String propPkgName = HSAILCompilationResult.class.getPackage().getName();
-    private static Level logLevel;
-    private static ConsoleHandler consoleHandler;
-    public static Logger logger;
-    static {
-        logger = Logger.getLogger(propPkgName);
-        logLevel = Level.FINE;
-        // This block configures the logger with handler and formatter.
-        consoleHandler = new ConsoleHandler();
-        logger.addHandler(consoleHandler);
-        logger.setUseParentHandlers(false);
-        SimpleFormatter formatter = new SimpleFormatter() {
-
-            @SuppressWarnings("sync-override")
-            @Override
-            public String format(LogRecord record) {
-                return (record.getMessage() + "\n");
-            }
-        };
-        consoleHandler.setFormatter(formatter);
-        logger.setLevel(logLevel);
-        consoleHandler.setLevel(logLevel);
-    }
-
     static final HSAILHotSpotBackend backend;
     static {
         // Look for installed HSAIL backend
@@ -185,9 +159,6 @@
         }
         // Now that we have the target lambda, compile it.
         HSAILCompilationResult hsailCompResult = HSAILCompilationResult.getHSAILCompilationResult(lambdaMethod);
-        if (hsailCompResult != null) {
-            hsailCompResult.dumpCompilationResult();
-        }
         return hsailCompResult;
     }
 
@@ -224,9 +195,9 @@
         } catch (GraalInternalError e) {
             String partialCode = backend.getPartialCodeString();
             if (partialCode != null && !partialCode.equals("")) {
-                logger.fine("-------------------\nPartial Code Generation:\n--------------------");
-                logger.fine(partialCode);
-                logger.fine("-------------------\nEnd of Partial Code Generation\n--------------------");
+                Debug.log("-------------------\nPartial Code Generation:\n--------------------");
+                Debug.log(partialCode);
+                Debug.log("-------------------\nEnd of Partial Code Generation\n--------------------");
             }
             throw e;
         }
@@ -251,9 +222,4 @@
         return new String(getTargetCode(), 0, getTargetCodeSize());
     }
 
-    public void dumpCompilationResult() {
-        logger.fine("targetCodeSize=" + getTargetCodeSize());
-        logger.fine(getHSAILCode());
-    }
-
 }
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend.java	Mon Dec 02 12:45:18 2013 +0100
@@ -56,7 +56,6 @@
         paramTypeMap.put("HotSpotResolvedPrimitiveType<float>", "f32");
         paramTypeMap.put("HotSpotResolvedPrimitiveType<double>", "f64");
         paramTypeMap.put("HotSpotResolvedPrimitiveType<long>", "s64");
-
     }
 
     @Override
@@ -128,13 +127,16 @@
         codeBuffer = tasm.asm.codeBuffer;
         codeBuffer.emitString0("version 0:95: $full : $large;");
         codeBuffer.emitString("");
+
         Signature signature = method.getSignature();
         int sigParamCount = signature.getParameterCount(false);
         // We're subtracting 1 because we're not making the final gid as a parameter.
+
         int nonConstantParamCount = sigParamCount - 1;
         boolean isStatic = (Modifier.isStatic(method.getModifiers()));
         // Determine if this is an object lambda.
         boolean isObjectLambda = true;
+
         if (signature.getParameterType(nonConstantParamCount, null).getKind() == Kind.Int) {
             isObjectLambda = false;
         } else {
@@ -152,8 +154,8 @@
         JavaType[] paramtypes = new JavaType[totalParamCount];
         String[] paramNames = new String[totalParamCount];
         int pidx = 0;
+        MetaAccessProvider metaAccess = getProviders().getMetaAccess();
         for (int i = 0; i < totalParamCount; i++) {
-            MetaAccessProvider metaAccess = getProviders().getMetaAccess();
             if (i == 0 && !isStatic) {
                 paramtypes[i] = metaAccess.lookupJavaType(Object.class);
                 paramNames[i] = "%_this";
@@ -168,19 +170,26 @@
                 }
             }
         }
+
         codeBuffer.emitString0("// " + (isStatic ? "static" : "instance") + " method " + method);
         codeBuffer.emitString("");
         codeBuffer.emitString0("kernel &run (");
         codeBuffer.emitString("");
+
         FrameMap frameMap = tasm.frameMap;
         RegisterConfig regConfig = frameMap.registerConfig;
         // Build list of param types which does include the gid (for cc register mapping query).
         JavaType[] ccParamTypes = new JavaType[nonConstantParamCount + 1];
         // Include the gid.
         System.arraycopy(paramtypes, 0, ccParamTypes, 0, nonConstantParamCount);
-        // Last entry comes from the signature.
-        ccParamTypes[ccParamTypes.length - 1] = signature.getParameterType(sigParamCount - 1, null);
+
+        // Last entry is always int (its register gets used in the workitemabsid instruction)
+        // this is true even for object stream labmdas
+        if (sigParamCount > 0) {
+            ccParamTypes[ccParamTypes.length - 1] = metaAccess.lookupJavaType(int.class);
+        }
         CallingConvention cc = regConfig.getCallingConvention(JavaCallee, null, ccParamTypes, getTarget(), false);
+
         /**
          * Compute the hsail size mappings up to but not including the last non-constant parameter
          * (which is the gid).
@@ -196,6 +205,7 @@
         // Emit the kernel function parameters.
         for (int i = 0; i < totalParamCount; i++) {
             String str = "kernarg_" + paramHsailSizes[i] + " " + paramNames[i];
+
             if (i != totalParamCount - 1) {
                 str += ",";
             }
@@ -229,19 +239,45 @@
         codeBuffer.emitString(spillsegTemplate);
         // Emit object array load prologue here.
         if (isObjectLambda) {
-            final int arrayElementsOffset = 24;
+            boolean useCompressedOops = getRuntime().getConfig().useCompressedOops;
+            final int arrayElementsOffset = HotSpotGraalRuntime.getArrayBaseOffset(Kind.Object);
             String iterationObjArgReg = HSAIL.mapRegister(cc.getArgument(nonConstantParamCount - 1));
-            String tmpReg = workItemReg.replace("s", "d"); // "$d1";
+            // iterationObjArgReg will be the highest $d register in use (it is the last parameter)
+            // so tempReg can be the next higher $d register
+            String tmpReg = "$d" + (asRegister(cc.getArgument(nonConstantParamCount - 1)).encoding() + 1);
             // Convert gid to long.
             codeBuffer.emitString("cvt_u64_s32 " + tmpReg + ", " + workItemReg + "; // Convert gid to long");
-            // Adjust index for sizeof ref.
-            codeBuffer.emitString("mul_u64 " + tmpReg + ", " + tmpReg + ", " + 8 + "; // Adjust index for sizeof ref");
+            // Adjust index for sizeof ref. Where to pull this size from?
+            codeBuffer.emitString("mul_u64 " + tmpReg + ", " + tmpReg + ", " + (useCompressedOops ? 4 : 8) + "; // Adjust index for sizeof ref");
             // Adjust for actual data start.
             codeBuffer.emitString("add_u64 " + tmpReg + ", " + tmpReg + ", " + arrayElementsOffset + "; // Adjust for actual elements data start");
             // Add to array ref ptr.
             codeBuffer.emitString("add_u64 " + tmpReg + ", " + tmpReg + ", " + iterationObjArgReg + "; // Add to array ref ptr");
             // Load the object into the parameter reg.
-            codeBuffer.emitString("ld_global_u64 " + iterationObjArgReg + ", " + "[" + tmpReg + "]" + "; // Load from array element into parameter reg");
+            if (useCompressedOops) {
+
+                // Load u32 into the d 64 reg since it will become an object address
+                codeBuffer.emitString("ld_global_u32 " + tmpReg + ", " + "[" + tmpReg + "]" + "; // Load compressed ptr from array");
+
+                long narrowOopBase = getRuntime().getConfig().narrowOopBase;
+                long narrowOopShift = getRuntime().getConfig().narrowOopShift;
+
+                if (narrowOopBase == 0 && narrowOopShift == 0) {
+                    // No more calculation to do, mov to target register
+                    codeBuffer.emitString("mov_b64 " + iterationObjArgReg + ", " + tmpReg + "; // no shift or base addition");
+                } else {
+                    if (narrowOopBase == 0) {
+                        codeBuffer.emitString("shl_u64 " + iterationObjArgReg + ", " + tmpReg + ", " + narrowOopShift + "; // do narrowOopShift");
+                    } else if (narrowOopShift == 0) {
+                        codeBuffer.emitString("add_u64 " + iterationObjArgReg + ", " + tmpReg + ", " + narrowOopBase + "; // add narrowOopBase");
+                    } else {
+                        codeBuffer.emitString("mad_u64 " + iterationObjArgReg + ", " + tmpReg + ", " + (1 << narrowOopShift) + ", " + narrowOopBase + "; // shift and add narrowOopBase");
+                    }
+                }
+
+            } else {
+                codeBuffer.emitString("ld_global_u64 " + iterationObjArgReg + ", " + "[" + tmpReg + "]" + "; // Load from array element into parameter reg");
+            }
         }
         // Prologue done, Emit code for the LIR.
         lirGen.lir.emitCode(tasm);
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackendFactory.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackendFactory.java	Mon Dec 02 12:45:18 2013 +0100
@@ -48,7 +48,7 @@
         // to be valid for the entire run of the VM.
         Assumptions assumptions = new Assumptions(false);
         Providers p = new Providers(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, null);
-        Replacements replacements = new HSAILHotSpotReplacementsImpl(p, assumptions, host.getReplacements());
+        Replacements replacements = new HSAILHotSpotReplacementsImpl(p, assumptions, codeCache.getTarget(), host.getReplacements());
         HotSpotDisassemblerProvider disassembler = host.getDisassembler();
         HotSpotSuitesProvider suites = host.getSuites();
         HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers);
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotReplacementsImpl.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotReplacementsImpl.java	Mon Dec 02 12:45:18 2013 +0100
@@ -38,8 +38,8 @@
 
     private final Replacements host;
 
-    public HSAILHotSpotReplacementsImpl(Providers providers, Assumptions assumptions, Replacements host) {
-        super(providers, assumptions);
+    public HSAILHotSpotReplacementsImpl(Providers providers, Assumptions assumptions, TargetDescription target, Replacements host) {
+        super(providers, assumptions, target);
         this.host = host;
     }
 
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java	Mon Dec 02 12:45:18 2013 +0100
@@ -61,7 +61,7 @@
         // to be valid for the entire run of the VM.
         Assumptions assumptions = new Assumptions(false);
         Providers p = new Providers(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, null);
-        HotSpotReplacementsImpl replacements = new HotSpotReplacementsImpl(p, runtime.getConfig(), assumptions);
+        HotSpotReplacementsImpl replacements = new HotSpotReplacementsImpl(p, runtime.getConfig(), assumptions, target);
         HotSpotDisassemblerProvider disassembler = new HotSpotDisassemblerProvider(runtime);
         HotSpotSuitesProvider suites = new HotSpotSuitesProvider(runtime);
         HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers);
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/CompileTheWorldTest.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/CompileTheWorldTest.java	Mon Dec 02 12:45:18 2013 +0100
@@ -39,7 +39,7 @@
         boolean originalSetting = ExitVMOnException.getValue();
         // Compile a couple classes in rt.jar
         String file = System.getProperty("java.home") + "/lib/rt.jar";
-        new CompileTheWorld(file, 1, 5).compile();
+        new CompileTheWorld(file, 1, 5, false).compile();
         ExitVMOnException.setValue(originalSetting);
     }
 
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierAdditionTest.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierAdditionTest.java	Mon Dec 02 12:45:18 2013 +0100
@@ -34,6 +34,7 @@
 import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.compiler.test.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.hotspot.phases.*;
@@ -243,54 +244,53 @@
     }
 
     private void test(final String snippet, final int expectedBarriers) throws Exception, SecurityException {
-        Debug.scope("WriteBarrierAditionTest", new DebugDumpScope(snippet), new Runnable() {
+        try (Scope s = Debug.scope("WriteBarrierAdditionTest", new DebugDumpScope(snippet))) {
+            StructuredGraph graph = parse(snippet);
+            HighTierContext highContext = new HighTierContext(getProviders(), new Assumptions(false), null, getDefaultPhasePlan(), OptimisticOptimizations.ALL);
+            MidTierContext midContext = new MidTierContext(getProviders(), new Assumptions(false), getCodeCache().getTarget(), OptimisticOptimizations.ALL);
+            new InliningPhase(new InliningPhase.InlineEverythingPolicy(), new CanonicalizerPhase(true)).apply(graph, highContext);
+            new LoweringPhase(new CanonicalizerPhase(true)).apply(graph, highContext);
+            new GuardLoweringPhase().apply(graph, midContext);
+            new LoweringPhase(new CanonicalizerPhase(true)).apply(graph, midContext);
+            new WriteBarrierAdditionPhase().apply(graph);
+            Debug.dump(graph, "After Write Barrier Addition");
 
-            public void run() {
-                StructuredGraph graph = parse(snippet);
-                HighTierContext highContext = new HighTierContext(getProviders(), new Assumptions(false), null, getDefaultPhasePlan(), OptimisticOptimizations.ALL);
-                MidTierContext midContext = new MidTierContext(getProviders(), new Assumptions(false), getCodeCache().getTarget(), OptimisticOptimizations.ALL);
-                new InliningPhase(new InliningPhase.InlineEverythingPolicy(), new CanonicalizerPhase(true)).apply(graph, highContext);
-                new LoweringPhase(new CanonicalizerPhase(true)).apply(graph, highContext);
-                new GuardLoweringPhase().apply(graph, midContext);
-                new LoweringPhase(new CanonicalizerPhase(true)).apply(graph, midContext);
-                new WriteBarrierAdditionPhase().apply(graph);
-                Debug.dump(graph, "After Write Barrier Addition");
-
-                int barriers = 0;
+            int barriers = 0;
+            if (useG1GC()) {
+                barriers = graph.getNodes().filter(G1ReferentFieldReadBarrier.class).count() + graph.getNodes().filter(G1PreWriteBarrier.class).count() +
+                                graph.getNodes().filter(G1PostWriteBarrier.class).count();
+            } else {
+                barriers = graph.getNodes().filter(SerialWriteBarrier.class).count();
+            }
+            Assert.assertEquals(expectedBarriers, barriers);
+            for (WriteNode write : graph.getNodes().filter(WriteNode.class)) {
                 if (useG1GC()) {
-                    barriers = graph.getNodes().filter(G1ReferentFieldReadBarrier.class).count() + graph.getNodes().filter(G1PreWriteBarrier.class).count() +
-                                    graph.getNodes().filter(G1PostWriteBarrier.class).count();
+                    if (write.getBarrierType() != BarrierType.NONE) {
+                        Assert.assertEquals(1, write.successors().count());
+                        Assert.assertTrue(write.next() instanceof G1PostWriteBarrier);
+                        Assert.assertTrue(write.predecessor() instanceof G1PreWriteBarrier);
+                    }
                 } else {
-                    barriers = graph.getNodes().filter(SerialWriteBarrier.class).count();
-                }
-                Assert.assertEquals(expectedBarriers, barriers);
-                for (WriteNode write : graph.getNodes().filter(WriteNode.class)) {
-                    if (useG1GC()) {
-                        if (write.getBarrierType() != BarrierType.NONE) {
-                            Assert.assertEquals(1, write.successors().count());
-                            Assert.assertTrue(write.next() instanceof G1PostWriteBarrier);
-                            Assert.assertTrue(write.predecessor() instanceof G1PreWriteBarrier);
-                        }
-                    } else {
-                        if (write.getBarrierType() != BarrierType.NONE) {
-                            Assert.assertEquals(1, write.successors().count());
-                            Assert.assertTrue(write.next() instanceof SerialWriteBarrier);
-                        }
-                    }
-                }
-
-                for (ReadNode read : graph.getNodes().filter(ReadNode.class)) {
-                    if (read.getBarrierType() != BarrierType.NONE) {
-                        if (read.location() instanceof ConstantLocationNode) {
-                            Assert.assertEquals(referentOffset(), ((ConstantLocationNode) (read.location())).getDisplacement());
-                        }
-                        Assert.assertTrue(useG1GC());
-                        Assert.assertEquals(BarrierType.PRECISE, read.getBarrierType());
-                        Assert.assertTrue(read.next() instanceof G1ReferentFieldReadBarrier);
+                    if (write.getBarrierType() != BarrierType.NONE) {
+                        Assert.assertEquals(1, write.successors().count());
+                        Assert.assertTrue(write.next() instanceof SerialWriteBarrier);
                     }
                 }
             }
-        });
+
+            for (ReadNode read : graph.getNodes().filter(ReadNode.class)) {
+                if (read.getBarrierType() != BarrierType.NONE) {
+                    if (read.location() instanceof ConstantLocationNode) {
+                        Assert.assertEquals(referentOffset(), ((ConstantLocationNode) (read.location())).getDisplacement());
+                    }
+                    Assert.assertTrue(useG1GC());
+                    Assert.assertEquals(BarrierType.PRECISE, read.getBarrierType());
+                    Assert.assertTrue(read.next() instanceof G1ReferentFieldReadBarrier);
+                }
+            }
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
     }
 
     private void test2(final String snippet, Object a, Object b, Object c) throws Exception {
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierVerificationTest.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierVerificationTest.java	Mon Dec 02 12:45:18 2013 +0100
@@ -23,7 +23,6 @@
 package com.oracle.graal.hotspot.test;
 
 import java.util.*;
-import java.util.concurrent.*;
 
 import org.junit.*;
 
@@ -31,6 +30,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.test.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.debug.internal.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.nodes.*;
@@ -610,108 +610,100 @@
     }
 
     private void test(final String snippet, final int expectedBarriers, final int... removedBarrierIndices) {
-
-        AssertionError expectedError = Debug.scope("WriteBarrierVerificationTest", new DebugDumpScope(snippet), new Callable<AssertionError>() {
+        try (Scope d = Debug.scope("WriteBarrierVerificationTest", new DebugDumpScope(snippet))) {
+            final StructuredGraph graph = parse(snippet);
+            HighTierContext highTierContext = new HighTierContext(getProviders(), new Assumptions(false), null, getDefaultPhasePlan(), OptimisticOptimizations.ALL);
+            new InliningPhase(new CanonicalizerPhase(true)).apply(graph, highTierContext);
 
-            public AssertionError call() {
-                final StructuredGraph graph = parse(snippet);
-                HighTierContext highTierContext = new HighTierContext(getProviders(), new Assumptions(false), null, getDefaultPhasePlan(), OptimisticOptimizations.ALL);
-                new InliningPhase(new CanonicalizerPhase(true)).apply(graph, highTierContext);
+            MidTierContext midTierContext = new MidTierContext(getProviders(), new Assumptions(false), getCodeCache().getTarget(), OptimisticOptimizations.ALL);
 
-                MidTierContext midTierContext = new MidTierContext(getProviders(), new Assumptions(false), getCodeCache().getTarget(), OptimisticOptimizations.ALL);
+            new LoweringPhase(new CanonicalizerPhase(true)).apply(graph, highTierContext);
+            new GuardLoweringPhase().apply(graph, midTierContext);
+            new LoopSafepointInsertionPhase().apply(graph);
+            new LoweringPhase(new CanonicalizerPhase(true)).apply(graph, highTierContext);
 
-                new LoweringPhase(new CanonicalizerPhase(true)).apply(graph, highTierContext);
-                new GuardLoweringPhase().apply(graph, midTierContext);
-                new LoopSafepointInsertionPhase().apply(graph);
-                new LoweringPhase(new CanonicalizerPhase(true)).apply(graph, highTierContext);
-
-                new WriteBarrierAdditionPhase().apply(graph);
+            new WriteBarrierAdditionPhase().apply(graph);
 
-                int barriers = 0;
-                // First, the total number of expected barriers is checked.
-                HotSpotVMConfig config = HotSpotGraalRuntime.runtime().getConfig();
-                if (config.useG1GC) {
-                    barriers = graph.getNodes().filter(G1PreWriteBarrier.class).count() + graph.getNodes().filter(G1PostWriteBarrier.class).count() +
-                                    graph.getNodes().filter(G1ArrayRangePreWriteBarrier.class).count() + graph.getNodes().filter(G1ArrayRangePostWriteBarrier.class).count();
-                    Assert.assertTrue(expectedBarriers * 2 == barriers);
-                } else {
-                    barriers = graph.getNodes().filter(SerialWriteBarrier.class).count() + graph.getNodes().filter(SerialArrayRangeWriteBarrier.class).count();
-                    Assert.assertTrue(expectedBarriers == barriers);
-                }
-                // Iterate over all write nodes and remove barriers according to input indices.
-                NodeIteratorClosure<Boolean> closure = new NodeIteratorClosure<Boolean>() {
+            int barriers = 0;
+            // First, the total number of expected barriers is checked.
+            HotSpotVMConfig config = HotSpotGraalRuntime.runtime().getConfig();
+            if (config.useG1GC) {
+                barriers = graph.getNodes().filter(G1PreWriteBarrier.class).count() + graph.getNodes().filter(G1PostWriteBarrier.class).count() +
+                                graph.getNodes().filter(G1ArrayRangePreWriteBarrier.class).count() + graph.getNodes().filter(G1ArrayRangePostWriteBarrier.class).count();
+                Assert.assertTrue(expectedBarriers * 2 == barriers);
+            } else {
+                barriers = graph.getNodes().filter(SerialWriteBarrier.class).count() + graph.getNodes().filter(SerialArrayRangeWriteBarrier.class).count();
+                Assert.assertTrue(expectedBarriers == barriers);
+            }
+            // Iterate over all write nodes and remove barriers according to input indices.
+            NodeIteratorClosure<Boolean> closure = new NodeIteratorClosure<Boolean>() {
 
-                    @Override
-                    protected Boolean processNode(FixedNode node, Boolean currentState) {
-                        if (node instanceof WriteNode) {
-                            WriteNode write = (WriteNode) node;
-                            LocationIdentity obj = write.getLocationIdentity();
-                            if (obj instanceof ResolvedJavaField) {
-                                if (((ResolvedJavaField) obj).getName().equals("barrierIndex")) {
-                                    /*
-                                     * A "barrierIndex" variable was found and is checked against
-                                     * the input barrier array.
-                                     */
-                                    if (eliminateBarrier(write.value().asConstant().asInt(), removedBarrierIndices)) {
-                                        return true;
-                                    }
+                @Override
+                protected Boolean processNode(FixedNode node, Boolean currentState) {
+                    if (node instanceof WriteNode) {
+                        WriteNode write = (WriteNode) node;
+                        LocationIdentity obj = write.getLocationIdentity();
+                        if (obj instanceof ResolvedJavaField) {
+                            if (((ResolvedJavaField) obj).getName().equals("barrierIndex")) {
+                                /*
+                                 * A "barrierIndex" variable was found and is checked against the
+                                 * input barrier array.
+                                 */
+                                if (eliminateBarrier(write.value().asConstant().asInt(), removedBarrierIndices)) {
+                                    return true;
                                 }
                             }
-                        } else if (node instanceof SerialWriteBarrier || node instanceof G1PostWriteBarrier) {
-                            // Remove flagged write barriers.
-                            if (currentState) {
-                                graph.removeFixed(((FixedWithNextNode) node));
-                                return false;
-                            }
                         }
-                        return currentState;
+                    } else if (node instanceof SerialWriteBarrier || node instanceof G1PostWriteBarrier) {
+                        // Remove flagged write barriers.
+                        if (currentState) {
+                            graph.removeFixed(((FixedWithNextNode) node));
+                            return false;
+                        }
                     }
+                    return currentState;
+                }
 
-                    private boolean eliminateBarrier(int index, int[] map) {
-                        for (int i = 0; i < map.length; i++) {
-                            if (map[i] == index) {
-                                return true;
-                            }
+                private boolean eliminateBarrier(int index, int[] map) {
+                    for (int i = 0; i < map.length; i++) {
+                        if (map[i] == index) {
+                            return true;
                         }
-                        return false;
-                    }
-
-                    @Override
-                    protected Map<LoopExitNode, Boolean> processLoop(LoopBeginNode loop, Boolean initialState) {
-                        return ReentrantNodeIterator.processLoop(this, loop, initialState).exitStates;
-                    }
-
-                    @Override
-                    protected Boolean merge(MergeNode merge, List<Boolean> states) {
-                        return false;
                     }
+                    return false;
+                }
 
-                    @Override
-                    protected Boolean afterSplit(AbstractBeginNode node, Boolean oldState) {
-                        return false;
-                    }
-                };
+                @Override
+                protected Map<LoopExitNode, Boolean> processLoop(LoopBeginNode loop, Boolean initialState) {
+                    return ReentrantNodeIterator.processLoop(this, loop, initialState).exitStates;
+                }
+
+                @Override
+                protected Boolean merge(MergeNode merge, List<Boolean> states) {
+                    return false;
+                }
 
-                DebugConfig debugConfig = DebugScope.getConfig();
-                try {
-                    ReentrantNodeIterator.apply(closure, graph.start(), false, null);
-                    Debug.setConfig(Debug.fixedConfig(false, false, false, false, debugConfig.dumpHandlers(), debugConfig.output()));
-                    new WriteBarrierVerificationPhase().apply(graph);
-                } catch (AssertionError error) {
-                    /*
-                     * Catch assertion, test for expected one and re-throw in order to validate unit
-                     * test.
-                     */
-                    Assert.assertTrue(error.getMessage().contains("Write barrier must be present"));
-                    return error;
-                } finally {
-                    Debug.setConfig(debugConfig);
+                @Override
+                protected Boolean afterSplit(AbstractBeginNode node, Boolean oldState) {
+                    return false;
                 }
-                return null;
+            };
+
+            DebugConfig debugConfig = DebugScope.getConfig();
+            DebugConfig fixedConfig = Debug.fixedConfig(false, false, false, false, debugConfig.dumpHandlers(), debugConfig.output());
+            try (DebugConfigScope s = Debug.setConfig(fixedConfig)) {
+                ReentrantNodeIterator.apply(closure, graph.start(), false, null);
+                new WriteBarrierVerificationPhase().apply(graph);
+            } catch (AssertionError error) {
+                /*
+                 * Catch assertion, test for expected one and re-throw in order to validate unit
+                 * test.
+                 */
+                Assert.assertTrue(error.getMessage().contains("Write barrier must be present"));
+                throw error;
             }
-        });
-        if (expectedError != null) {
-            throw expectedError;
+        } catch (Throwable e) {
+            throw Debug.handle(e);
         }
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Mon Dec 02 12:45:18 2013 +0100
@@ -37,6 +37,7 @@
 import com.oracle.graal.compiler.CompilerThreadFactory.CompilerThread;
 import com.oracle.graal.compiler.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.debug.internal.*;
 import com.oracle.graal.hotspot.bridge.*;
 import com.oracle.graal.hotspot.meta.*;
@@ -142,32 +143,29 @@
             CompilationResult result = null;
             TTY.Filter filter = new TTY.Filter(PrintFilter.getValue(), method);
             long start = System.currentTimeMillis();
-            try {
-                result = Debug.scope("Compiling", new DebugDumpScope(String.valueOf(id), true), new Callable<CompilationResult>() {
-
-                    @Override
-                    public CompilationResult call() throws Exception {
-                        GraphCache graphCache = backend.getRuntime().getGraphCache();
-                        if (graphCache != null) {
-                            graphCache.removeStaleGraphs();
-                        }
+            try (Scope s = Debug.scope("Compiling", new DebugDumpScope(String.valueOf(id), true))) {
+                GraphCache graphCache = backend.getRuntime().getGraphCache();
+                if (graphCache != null) {
+                    graphCache.removeStaleGraphs();
+                }
 
-                        HotSpotProviders providers = backend.getProviders();
-                        Replacements replacements = providers.getReplacements();
-                        graph = replacements.getMethodSubstitution(method);
-                        if (graph == null || entryBCI != INVOCATION_ENTRY_BCI) {
-                            graph = new StructuredGraph(method, entryBCI);
-                        } else {
-                            // Compiling method substitution - must clone the graph
-                            graph = graph.copy();
-                        }
-                        InlinedBytecodes.add(method.getCodeSize());
-                        CallingConvention cc = getCallingConvention(providers.getCodeCache(), Type.JavaCallee, graph.method(), false);
-                        Suites suites = providers.getSuites().getDefaultSuites();
-                        return GraalCompiler.compileGraph(graph, cc, method, providers, backend, backend.getTarget(), graphCache, plan, optimisticOpts, method.getSpeculationLog(), suites,
-                                        new CompilationResult());
-                    }
-                });
+                HotSpotProviders providers = backend.getProviders();
+                Replacements replacements = providers.getReplacements();
+                graph = replacements.getMethodSubstitution(method);
+                if (graph == null || entryBCI != INVOCATION_ENTRY_BCI) {
+                    graph = new StructuredGraph(method, entryBCI);
+                } else {
+                    // Compiling method substitution - must clone the graph
+                    graph = graph.copy();
+                }
+                InlinedBytecodes.add(method.getCodeSize());
+                CallingConvention cc = getCallingConvention(providers.getCodeCache(), Type.JavaCallee, graph.method(), false);
+                Suites suites = providers.getSuites().getDefaultSuites();
+                result = GraalCompiler.compileGraph(graph, cc, method, providers, backend, backend.getTarget(), graphCache, plan, optimisticOpts, method.getSpeculationLog(), suites,
+                                new CompilationResult());
+
+            } catch (Throwable e) {
+                throw Debug.handle(e);
             } finally {
                 filter.remove();
                 final boolean printAfterCompilation = PrintAfterCompilation.getValue() && !TTY.isSuppressed();
@@ -200,12 +198,13 @@
                 System.exit(-1);
             }
         } finally {
-            if (config.ciTime && installedCode != null) {
+            if ((config.ciTime || config.ciTimeEach) && installedCode != null) {
                 long processedBytes = InlinedBytecodes.getCurrentValue() - previousInlinedBytecodes;
                 long time = CompilationTime.getCurrentValue() - previousCompilationTime;
                 TimeUnit timeUnit = CompilationTime.getTimeUnit();
-                VMToCompiler vm2c = backend.getRuntime().getVMToCompiler();
-                vm2c.notifyCompilationDone(id, method, entryBCI != INVOCATION_ENTRY_BCI, (int) processedBytes, time, timeUnit, installedCode);
+                long timeUnitsPerSecond = timeUnit.convert(1, TimeUnit.SECONDS);
+                CompilerToVM c2vm = backend.getRuntime().getCompilerToVM();
+                c2vm.notifyCompilationStatistics(id, method, entryBCI != INVOCATION_ENTRY_BCI, (int) processedBytes, time, timeUnitsPerSecond, installedCode);
             }
 
             assert method.isQueuedForCompilation();
@@ -230,21 +229,19 @@
 
     private HotSpotInstalledCode installMethod(final CompilationResult compResult) {
         final HotSpotCodeCacheProvider codeCache = backend.getProviders().getCodeCache();
-        return Debug.scope("CodeInstall", new Object[]{new DebugDumpScope(String.valueOf(id), true), codeCache, method}, new Callable<HotSpotInstalledCode>() {
-
-            @Override
-            public HotSpotInstalledCode call() {
-                HotSpotInstalledCode installedCode = codeCache.installMethod(method, entryBCI, compResult);
-                if (Debug.isDumpEnabled()) {
-                    Debug.dump(new Object[]{compResult, installedCode}, "After code installation");
-                }
-                if (Debug.isLogEnabled()) {
-                    Debug.log("%s", backend.getProviders().getDisassembler().disassemble(installedCode));
-                }
-                return installedCode;
+        HotSpotInstalledCode installedCode = null;
+        try (Scope s = Debug.scope("CodeInstall", new DebugDumpScope(String.valueOf(id), true), codeCache, method)) {
+            installedCode = codeCache.installMethod(method, entryBCI, compResult);
+            if (Debug.isDumpEnabled()) {
+                Debug.dump(new Object[]{compResult, installedCode}, "After code installation");
             }
-
-        });
+            if (Debug.isLogEnabled()) {
+                Debug.log("%s", backend.getProviders().getDisassembler().disassemble(installedCode));
+            }
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+        return installedCode;
     }
 
     private boolean tryToChangeStatus(CompilationStatus from, CompilationStatus to) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java	Mon Dec 02 12:45:18 2013 +0100
@@ -68,13 +68,15 @@
     private int compiledMethodsCounter = 0;
     private long compileTime = 0;
 
+    private boolean verbose;
+
     /**
      * Create a compile-the-world instance with default values from
      * {@link GraalOptions#CompileTheWorld}, {@link GraalOptions#CompileTheWorldStartAt} and
      * {@link GraalOptions#CompileTheWorldStopAt}.
      */
     public CompileTheWorld() {
-        this(CompileTheWorld.getValue(), CompileTheWorldStartAt.getValue(), CompileTheWorldStopAt.getValue());
+        this(CompileTheWorld.getValue(), CompileTheWorldStartAt.getValue(), CompileTheWorldStopAt.getValue(), true);
     }
 
     /**
@@ -84,13 +86,18 @@
      * @param startAt index of the class file to start compilation at
      * @param stopAt index of the class file to stop compilation at
      */
-    public CompileTheWorld(String files, int startAt, int stopAt) {
+    public CompileTheWorld(String files, int startAt, int stopAt, boolean verbose) {
         this.files = files;
         this.startAt = startAt;
         this.stopAt = stopAt;
+        this.verbose = verbose;
 
-        // We don't want the VM to exit when a method fails to compile.
+        // We don't want the VM to exit when a method fails to compile...
         ExitVMOnException.setValue(false);
+
+        // ...but we want to see exceptions.
+        PrintBailout.setValue(true);
+        PrintStackTraceOnException.setValue(true);
     }
 
     /**
@@ -123,6 +130,20 @@
         }
     }
 
+    public void println() {
+        println("");
+    }
+
+    public void println(String format, Object... args) {
+        println(String.format(format, args));
+    }
+
+    public void println(String s) {
+        if (verbose) {
+            TTY.println(s);
+        }
+    }
+
     /**
      * Compile all methods in all classes in the Zip/Jar files passed.
      * 
@@ -137,13 +158,13 @@
 
             // For now we only compile all methods in all classes in zip/jar files.
             if (!entry.endsWith(".zip") && !entry.endsWith(".jar")) {
-                TTY.println("CompileTheWorld : Skipped classes in " + entry);
-                TTY.println();
+                println("CompileTheWorld : Skipped classes in " + entry);
+                println();
                 continue;
             }
 
-            TTY.println("CompileTheWorld : Compiling all classes in " + entry);
-            TTY.println();
+            println("CompileTheWorld : Compiling all classes in " + entry);
+            println();
 
             URL url = new URL("jar", "", "file:" + entry + "!/");
             ClassLoader loader = new URLClassLoader(new URL[]{url});
@@ -178,13 +199,13 @@
                         }
                     } catch (Throwable t) {
                         // If something went wrong during pre-loading we just ignore it.
-                        TTY.println("Preloading failed for (%d) %s", classFileCounter, className);
+                        println("Preloading failed for (%d) %s", classFileCounter, className);
                     }
 
                     // Are we compiling this class?
                     HotSpotMetaAccessProvider metaAccess = runtime.getHostProviders().getMetaAccess();
                     if (classFileCounter >= startAt) {
-                        TTY.println("CompileTheWorld (%d) : %s", classFileCounter, className);
+                        println("CompileTheWorld (%d) : %s", classFileCounter, className);
 
                         // Enqueue each constructor/method in the class for compilation.
                         for (Constructor<?> constructor : javaClass.getDeclaredConstructors()) {
@@ -201,14 +222,14 @@
                         }
                     }
                 } catch (Throwable t) {
-                    TTY.println("CompileTheWorld (%d) : Skipping %s", classFileCounter, className);
+                    println("CompileTheWorld (%d) : Skipping %s", classFileCounter, className);
                 }
             }
             jarFile.close();
         }
 
-        TTY.println();
-        TTY.println("CompileTheWorld : Done (%d classes, %d methods, %d ms)", classFileCounter, compiledMethodsCounter, compileTime);
+        println();
+        println("CompileTheWorld : Done (%d classes, %d methods, %d ms)", classFileCounter, compiledMethodsCounter, compileTime);
     }
 
     /**
@@ -223,7 +244,7 @@
             method.reprofile();  // makes the method also not-entrant
         } catch (Throwable t) {
             // Catch everything and print a message
-            TTY.println("CompileTheWorld (%d) : Error compiling method: %s", classFileCounter, MetaUtil.format("%H.%n(%p):%r", method));
+            println("CompileTheWorld (%d) : Error compiling method: %s", classFileCounter, MetaUtil.format("%H.%n(%p):%r", method));
             t.printStackTrace(TTY.cachedOut);
         }
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java	Mon Dec 02 12:45:18 2013 +0100
@@ -209,8 +209,15 @@
         if (config.compileTheWorldStopAt != Integer.MAX_VALUE) {
             GraalOptions.CompileTheWorldStopAt.setValue(config.compileTheWorldStopAt);
         }
-        GraalOptions.HotSpotPrintCompilation.setValue(config.printCompilation);
-        GraalOptions.HotSpotPrintInlining.setValue(config.printInlining);
+
+        // Only set HotSpotPrintCompilation and HotSpotPrintInlining if they still have their
+        // default value (false).
+        if (GraalOptions.HotSpotPrintCompilation.getValue() == false) {
+            GraalOptions.HotSpotPrintCompilation.setValue(config.printCompilation);
+        }
+        if (GraalOptions.HotSpotPrintInlining.getValue() == false) {
+            GraalOptions.HotSpotPrintInlining.setValue(config.printInlining);
+        }
 
         if (Boolean.valueOf(System.getProperty("graal.printconfig"))) {
             printConfig(config);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java	Mon Dec 02 12:45:18 2013 +0100
@@ -28,6 +28,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.nodes.spi.*;
 
@@ -51,24 +52,21 @@
 
         // Install intrinsics.
         if (Intrinsify.getValue()) {
-            Debug.scope("RegisterReplacements", new Object[]{new DebugDumpScope("RegisterReplacements")}, new Runnable() {
-
-                @Override
-                public void run() {
-
-                    Replacements replacements = providers.getReplacements();
-                    ServiceLoader<ReplacementsProvider> sl = ServiceLoader.loadInstalled(ReplacementsProvider.class);
-                    for (ReplacementsProvider replacementsProvider : sl) {
-                        replacementsProvider.registerReplacements(providers.getMetaAccess(), lowerer, replacements, providers.getCodeCache().getTarget());
-                    }
-                    if (BootstrapReplacements.getValue()) {
-                        for (ResolvedJavaMethod method : replacements.getAllReplacements()) {
-                            replacements.getMacroSubstitution(method);
-                            replacements.getMethodSubstitution(method);
-                        }
+            try (Scope s = Debug.scope("RegisterReplacements", new DebugDumpScope("RegisterReplacements"))) {
+                Replacements replacements = providers.getReplacements();
+                ServiceLoader<ReplacementsProvider> sl = ServiceLoader.loadInstalled(ReplacementsProvider.class);
+                for (ReplacementsProvider replacementsProvider : sl) {
+                    replacementsProvider.registerReplacements(providers.getMetaAccess(), lowerer, replacements, providers.getCodeCache().getTarget());
+                }
+                if (BootstrapReplacements.getValue()) {
+                    for (ResolvedJavaMethod method : replacements.getAllReplacements()) {
+                        replacements.getMacroSubstitution(method);
+                        replacements.getMethodSubstitution(method);
                     }
                 }
-            });
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            }
         }
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptions.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptions.java	Mon Dec 02 12:45:18 2013 +0100
@@ -35,7 +35,6 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.logging.*;
-import com.oracle.graal.java.*;
 import com.oracle.graal.options.*;
 import com.oracle.graal.phases.common.*;
 
@@ -220,11 +219,10 @@
      * Called from VM code once all Graal command line options have been processed by
      * {@link #setOption(String)}.
      * 
-     * @param ciTime the value of the CITime HotSpot VM option
+     * @param timeCompilations true if the CITime or CITimeEach HotSpot VM options are set
      */
-    public static void finalizeOptions(boolean ciTime) {
-        if (ciTime) {
-            unconditionallyEnableTimerOrMetric(GraphBuilderPhase.class, "BytecodesParsed");
+    public static void finalizeOptions(boolean timeCompilations) {
+        if (timeCompilations) {
             unconditionallyEnableTimerOrMetric(InliningUtil.class, "InlinedBytecodes");
             unconditionallyEnableTimerOrMetric(CompilationTask.class, "CompilationTime");
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java	Mon Dec 02 12:45:18 2013 +0100
@@ -40,8 +40,8 @@
 
     private final HotSpotVMConfig config;
 
-    public HotSpotReplacementsImpl(Providers providers, HotSpotVMConfig config, Assumptions assumptions) {
-        super(providers, assumptions);
+    public HotSpotReplacementsImpl(Providers providers, HotSpotVMConfig config, Assumptions assumptions, TargetDescription target) {
+        super(providers, assumptions, target);
         this.config = config;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Mon Dec 02 12:45:18 2013 +0100
@@ -738,16 +738,6 @@
 
     @HotSpotVMConstant(name = "GRAAL_COUNTERS_SIZE", optional = true) @Stable public int graalCountersSize;
 
-    @HotSpotVMField(name = "CompilerStatistics::_standard", get = HotSpotVMField.Type.OFFSET) @Stable public long compilerStatisticsStandardOffset;
-    @HotSpotVMField(name = "CompilerStatistics::_osr", get = HotSpotVMField.Type.OFFSET) @Stable public long compilerStatisticsOsrOffset;
-    @HotSpotVMField(name = "CompilerStatistics::_nmethods_size", get = HotSpotVMField.Type.OFFSET) @Stable public long compilerStatisticsNmethodsSizeOffset;
-    @HotSpotVMField(name = "CompilerStatistics::_nmethods_code_size", get = HotSpotVMField.Type.OFFSET) @Stable public long compilerStatisticsNmethodsCodeSizeOffset;
-    @HotSpotVMField(name = "CompilerStatistics::Data::_bytes", get = HotSpotVMField.Type.OFFSET) @Stable public long compilerStatisticsDataBytesOffset;
-    @HotSpotVMField(name = "CompilerStatistics::Data::_time", get = HotSpotVMField.Type.OFFSET) @Stable public long compilerStatisticsDataTimeOffset;
-    @HotSpotVMField(name = "CompilerStatistics::Data::_count", get = HotSpotVMField.Type.OFFSET) @Stable public long compilerStatisticsDataCountOffset;
-    @HotSpotVMField(name = "elapsedTimer::_counter", get = HotSpotVMField.Type.OFFSET) @Stable public long elapsedTimerCounterOffset;
-    @Stable public long elapsedTimerFrequency;
-
     /**
      * This field is used to pass exception objects into and out of the runtime system during
      * exception handling for compiled code.
@@ -1056,6 +1046,20 @@
     @HotSpotVMField(name = "DataLayout::_cells[0]", get = HotSpotVMField.Type.OFFSET) @Stable public int dataLayoutCellsOffset;
     @HotSpotVMConstant(name = "DataLayout::cell_size") @Stable public int dataLayoutCellSize;
 
+    @HotSpotVMConstant(name = "DataLayout::no_tag") @Stable public int dataLayoutNoTag;
+    @HotSpotVMConstant(name = "DataLayout::bit_data_tag") @Stable public int dataLayoutBitDataTag;
+    @HotSpotVMConstant(name = "DataLayout::counter_data_tag") @Stable public int dataLayoutCounterDataTag;
+    @HotSpotVMConstant(name = "DataLayout::jump_data_tag") @Stable public int dataLayoutJumpDataTag;
+    @HotSpotVMConstant(name = "DataLayout::receiver_type_data_tag") @Stable public int dataLayoutReceiverTypeDataTag;
+    @HotSpotVMConstant(name = "DataLayout::virtual_call_data_tag") @Stable public int dataLayoutVirtualCallDataTag;
+    @HotSpotVMConstant(name = "DataLayout::ret_data_tag") @Stable public int dataLayoutRetDataTag;
+    @HotSpotVMConstant(name = "DataLayout::branch_data_tag") @Stable public int dataLayoutBranchDataTag;
+    @HotSpotVMConstant(name = "DataLayout::multi_branch_data_tag") @Stable public int dataLayoutMultiBranchDataTag;
+    @HotSpotVMConstant(name = "DataLayout::arg_info_data_tag") @Stable public int dataLayoutArgInfoDataTag;
+    @HotSpotVMConstant(name = "DataLayout::call_type_data_tag") @Stable public int dataLayoutCallTypeDataTag;
+    @HotSpotVMConstant(name = "DataLayout::virtual_call_type_data_tag") @Stable public int dataLayoutVirtualCallTypeDataTag;
+    @HotSpotVMConstant(name = "DataLayout::parameters_type_data_tag") @Stable public int dataLayoutParametersTypeDataTag;
+
     @HotSpotVMFlag(name = "BciProfileWidth") @Stable public int bciProfileWidth;
     @HotSpotVMFlag(name = "TypeProfileWidth") @Stable public int typeProfileWidth;
     @HotSpotVMFlag(name = "MethodProfileWidth") @Stable public int methodProfileWidth;
@@ -1139,6 +1143,7 @@
     @HotSpotVMConstant(name = "Deoptimization::Reason_div0_check") @Stable public int deoptReasonDiv0Check;
     @HotSpotVMConstant(name = "Deoptimization::Reason_constraint") @Stable public int deoptReasonConstraint;
     @HotSpotVMConstant(name = "Deoptimization::Reason_loop_limit_check") @Stable public int deoptReasonLoopLimitCheck;
+    @HotSpotVMConstant(name = "Deoptimization::Reason_aliasing") @Stable public int deoptReasonAliasing;
 
     @HotSpotVMConstant(name = "Deoptimization::Action_none") @Stable public int deoptActionNone;
     @HotSpotVMConstant(name = "Deoptimization::Action_maybe_recompile") @Stable public int deoptActionMaybeRecompile;
@@ -1152,6 +1157,11 @@
     @HotSpotVMConstant(name = "vmIntrinsics::_linkToSpecial") @Stable public int vmIntrinsicLinkToSpecial;
     @HotSpotVMConstant(name = "vmIntrinsics::_linkToInterface") @Stable public int vmIntrinsicLinkToInterface;
 
+    @HotSpotVMConstant(name = "GraalEnv::ok") @Stable public int codeInstallResultOk;
+    @HotSpotVMConstant(name = "GraalEnv::dependencies_failed") @Stable public int codeInstallResultDependenciesFailed;
+    @HotSpotVMConstant(name = "GraalEnv::cache_full") @Stable public int codeInstallResultCacheFull;
+    @HotSpotVMConstant(name = "GraalEnv::code_too_large") @Stable public int codeInstallResultCodeTooLarge;
+
     public boolean check() {
         for (Field f : getClass().getDeclaredFields()) {
             int modifiers = f.getModifiers();
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java	Mon Dec 02 12:45:18 2013 +0100
@@ -27,6 +27,7 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.*;
 
@@ -132,9 +133,49 @@
 
     Object lookupAppendixInPool(HotSpotResolvedObjectType pool, int cpi, byte opcode);
 
-    // Must be kept in sync with enum in graalEnv.hpp
     public enum CodeInstallResult {
-        OK, DEPENDENCIES_FAILED, CACHE_FULL, CODE_TOO_LARGE
+        OK("ok"), DEPENDENCIES_FAILED("dependencies failed"), CACHE_FULL("code cache is full"), CODE_TOO_LARGE("code is too large");
+
+        private int value;
+        private String message;
+
+        private CodeInstallResult(String name) {
+            HotSpotVMConfig config = HotSpotGraalRuntime.runtime().getConfig();
+            switch (name) {
+                case "ok":
+                    this.value = config.codeInstallResultOk;
+                    break;
+                case "dependencies failed":
+                    this.value = config.codeInstallResultDependenciesFailed;
+                    break;
+                case "code cache is full":
+                    this.value = config.codeInstallResultCacheFull;
+                    break;
+                case "code is too large":
+                    this.value = config.codeInstallResultCodeTooLarge;
+                    break;
+                default:
+                    throw GraalInternalError.shouldNotReachHere("unknown enum name " + name);
+            }
+            this.message = name;
+        }
+
+        /**
+         * Returns the enum object for the given value.
+         */
+        public static CodeInstallResult getEnum(int value) {
+            for (CodeInstallResult e : values()) {
+                if (e.value == value) {
+                    return e;
+                }
+            }
+            throw GraalInternalError.shouldNotReachHere("unknown enum value " + value);
+        }
+
+        @Override
+        public String toString() {
+            return message;
+        }
     }
 
     /**
@@ -146,6 +187,22 @@
      */
     CodeInstallResult installCode(HotSpotCompiledCode compiledCode, HotSpotInstalledCode code, SpeculationLog cache);
 
+    /**
+     * Notifies the VM of statistics for a completed compilation.
+     * 
+     * @param id the identifier of the compilation
+     * @param method the method compiled
+     * @param osr specifies if the compilation was for on-stack-replacement
+     * @param processedBytecodes the number of bytecodes processed during the compilation, including
+     *            the bytecodes of all inlined methods
+     * @param time the amount time spent compiling {@code method}
+     * @param timeUnitsPerSecond the granularity of the units for the {@code time} value
+     * @param installedCode the nmethod installed as a result of the compilation
+     */
+    void notifyCompilationStatistics(int id, HotSpotResolvedJavaMethod method, boolean osr, int processedBytecodes, long time, long timeUnitsPerSecond, HotSpotInstalledCode installedCode);
+
+    void resetCompilationStatistics();
+
     void initializeConfiguration(HotSpotVMConfig config);
 
     JavaMethod resolveMethod(HotSpotResolvedObjectType klass, String name, String signature);
@@ -187,13 +244,6 @@
 
     String disassembleCodeBlob(long codeBlob);
 
-    /**
-     * Gets a copy of the machine code for a CodeBlob.
-     * 
-     * @return the machine code for {@code codeBlob} if it is valid, null otherwise
-     */
-    byte[] getCode(long codeBlob);
-
     StackTraceElement getStackTraceElement(long metaspaceMethod, int bci);
 
     Object executeCompiledMethod(Object arg1, Object arg2, Object arg3, HotSpotInstalledCode hotspotInstalledCode) throws InvalidInstalledCodeException;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java	Mon Dec 02 12:45:18 2013 +0100
@@ -39,7 +39,7 @@
 
     @Override
     public CodeInstallResult installCode(HotSpotCompiledCode compiledCode, HotSpotInstalledCode code, SpeculationLog speculationLog) {
-        return CodeInstallResult.values()[installCode0(compiledCode, code, (speculationLog == null) ? null : speculationLog.getRawMap())];
+        return CodeInstallResult.getEnum(installCode0(compiledCode, code, (speculationLog == null) ? null : speculationLog.getRawMap()));
     }
 
     @Override
@@ -133,9 +133,6 @@
     public synchronized native String disassembleCodeBlob(long codeBlob);
 
     @Override
-    public native byte[] getCode(long codeBlob);
-
-    @Override
     public native StackTraceElement getStackTraceElement(long metaspaceMethod, int bci);
 
     @Override
@@ -176,6 +173,11 @@
         return executeCompiledMethodIntrinsic(arg1, arg2, arg3, hotspotInstalledCode);
     }
 
+    public synchronized native void notifyCompilationStatistics(int id, HotSpotResolvedJavaMethod method, boolean osr, int processedBytecodes, long time, long timeUnitsPerSecond,
+                    HotSpotInstalledCode installedCode);
+
+    public native void resetCompilationStatistics();
+
     /**
      * Direct call to the given nmethod with three object arguments and an object return value. This
      * method does not have an implementation on the C++ side, but its entry points (from
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompiler.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompiler.java	Mon Dec 02 12:45:18 2013 +0100
@@ -24,7 +24,6 @@
 package com.oracle.graal.hotspot.bridge;
 
 import java.io.*;
-import java.util.concurrent.*;
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.hotspot.debug.*;
@@ -41,23 +40,9 @@
      */
     void compileMethod(long metaspaceMethod, HotSpotResolvedObjectType holder, int entryBCI, boolean blocking);
 
-    /**
-     * Notifies this object of statistics for a completed compilation.
-     * 
-     * @param id the identifier of the compilation
-     * @param method the method compiled
-     * @param osr specifies if the compilation was for on-stack-replacement
-     * @param processedBytecodes the number of bytecodes processed during the compilation, including
-     *            the bytecodes of all inlined methods
-     * @param time the amount time spent compiling {@code method}
-     * @param timeUnit the units of {@code time}
-     * @param installedCode the nmethod installed as a result of the compilation
-     */
-    void notifyCompilationDone(int id, HotSpotResolvedJavaMethod method, boolean osr, int processedBytecodes, long time, TimeUnit timeUnit, HotSpotInstalledCode installedCode);
-
     void shutdownCompiler() throws Exception;
 
-    void startCompiler(boolean bootstrapEnabled, long statsAddress) throws Throwable;
+    void startCompiler(boolean bootstrapEnabled) throws Throwable;
 
     void bootstrap() throws Throwable;
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Mon Dec 02 12:45:18 2013 +0100
@@ -26,7 +26,6 @@
 import static com.oracle.graal.compiler.GraalDebugConfig.*;
 import static com.oracle.graal.graph.UnsafeAccess.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
-import static java.util.concurrent.TimeUnit.*;
 
 import java.io.*;
 import java.lang.reflect.*;
@@ -101,8 +100,6 @@
 
     private long compilerStartTime;
 
-    private long compilerStatistics;
-
     public VMToCompilerImpl(HotSpotGraalRuntime runtime) {
         this.runtime = runtime;
 
@@ -123,7 +120,7 @@
         assert unsafe.getObject(mirror, offset) == type;
     }
 
-    public void startCompiler(boolean bootstrapEnabled, long compilerStatisticsAddress) throws Throwable {
+    public void startCompiler(boolean bootstrapEnabled) throws Throwable {
 
         FastNodeClassRegistry.initialize();
 
@@ -150,7 +147,7 @@
             }
         }
 
-        compilerStatistics = compilerStatisticsAddress;
+        runtime.getCompilerToVM();
 
         TTY.initialize(log);
 
@@ -318,7 +315,7 @@
 
         if (ResetDebugValuesAfterBootstrap.getValue()) {
             printDebugValues("bootstrap", true);
-            resetCompilerStatistics();
+            runtime.getCompilerToVM().resetCompilationStatistics();
         }
         phaseTransition("bootstrap");
 
@@ -600,64 +597,6 @@
         }
     }
 
-    private TimeUnit elapsedTimerTimeUnit;
-
-    private TimeUnit getElapsedTimerTimeUnit() {
-        if (elapsedTimerTimeUnit == null) {
-            long freq = runtime.getConfig().elapsedTimerFrequency;
-            for (TimeUnit tu : TimeUnit.values()) {
-                if (tu.toSeconds(freq) == 1) {
-                    elapsedTimerTimeUnit = tu;
-                    break;
-                }
-            }
-            assert elapsedTimerTimeUnit != null;
-        }
-        return elapsedTimerTimeUnit;
-    }
-
-    public synchronized void notifyCompilationDone(int id, HotSpotResolvedJavaMethod method, boolean osr, int processedBytecodes, long time, TimeUnit timeUnit, HotSpotInstalledCode installedCode) {
-        HotSpotVMConfig config = runtime.getConfig();
-        long dataAddress = compilerStatistics + (osr ? config.compilerStatisticsOsrOffset : config.compilerStatisticsStandardOffset);
-
-        long timeAddress = dataAddress + config.compilerStatisticsDataTimeOffset + config.elapsedTimerCounterOffset;
-        long previousElapsedTime = unsafe.getLong(timeAddress);
-        long elapsedTime = getElapsedTimerTimeUnit().convert(time, timeUnit);
-        unsafe.putLong(timeAddress, previousElapsedTime + elapsedTime);
-
-        long bytesAddress = dataAddress + config.compilerStatisticsDataBytesOffset;
-        int currentBytes = unsafe.getInt(bytesAddress);
-        unsafe.putInt(bytesAddress, currentBytes + processedBytecodes);
-
-        long countAddress = dataAddress + config.compilerStatisticsDataCountOffset;
-        int currentCount = unsafe.getInt(countAddress);
-        unsafe.putInt(countAddress, currentCount + 1);
-
-        long nmethodsSizeAddress = compilerStatistics + config.compilerStatisticsNmethodsSizeOffset;
-        int currentSize = unsafe.getInt(nmethodsSizeAddress);
-        unsafe.putInt(nmethodsSizeAddress, currentSize + installedCode.getSize());
-
-        long nmethodsCodeSizeAddress = compilerStatistics + config.compilerStatisticsNmethodsCodeSizeOffset;
-        int currentCodeSize = unsafe.getInt(nmethodsCodeSizeAddress);
-        unsafe.putInt(nmethodsCodeSizeAddress, currentCodeSize + (int) installedCode.getCodeSize());
-
-        if (config.ciTimeEach) {
-            TTY.println(String.format("%-6d {%s: %d ms, %d bytes}", id, osr ? "osr" : "standard", MILLISECONDS.convert(time, timeUnit), processedBytecodes));
-        }
-    }
-
-    private static void resetCompilerStatisticsData(HotSpotVMConfig config, long dataAddress) {
-        unsafe.putInt(dataAddress + config.compilerStatisticsDataBytesOffset, 0);
-        unsafe.putInt(dataAddress + config.compilerStatisticsDataCountOffset, 0);
-        unsafe.putLong(dataAddress + config.compilerStatisticsDataTimeOffset + config.elapsedTimerCounterOffset, 0L);
-    }
-
-    private void resetCompilerStatistics() {
-        HotSpotVMConfig config = runtime.getConfig();
-        resetCompilerStatisticsData(config, compilerStatistics + config.compilerStatisticsStandardOffset);
-        resetCompilerStatisticsData(config, compilerStatistics + config.compilerStatisticsOsrOffset);
-    }
-
     @Override
     public JavaMethod createUnresolvedJavaMethod(String name, String signature, JavaType holder) {
         return new HotSpotMethodUnresolved(name, signature, holder);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java	Mon Dec 02 12:45:18 2013 +0100
@@ -520,6 +520,8 @@
             boxingSnippets.lower((BoxNode) n, tool);
         } else if (n instanceof UnboxNode) {
             boxingSnippets.lower((UnboxNode) n, tool);
+        } else if (n instanceof DeoptimizeNode || n instanceof UnwindNode) {
+            /* No lowering, we generate LIR directly for these nodes. */
         } else {
             assert false : "Node implementing Lowerable not handled: " + n;
             throw GraalInternalError.shouldNotReachHere();
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMetaAccessProvider.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMetaAccessProvider.java	Mon Dec 02 12:45:18 2013 +0100
@@ -187,6 +187,8 @@
                 return runtime.getConfig().deoptReasonConstraint;
             case LoopLimitCheck:
                 return runtime.getConfig().deoptReasonLoopLimitCheck;
+            case Aliasing:
+                return runtime.getConfig().deoptReasonAliasing;
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
@@ -221,6 +223,8 @@
             return DeoptimizationReason.RuntimeConstraint;
         } else if (reason == runtime.getConfig().deoptReasonLoopLimitCheck) {
             return DeoptimizationReason.LoopLimitCheck;
+        } else if (reason == runtime.getConfig().deoptReasonAliasing) {
+            return DeoptimizationReason.Aliasing;
         } else {
             throw GraalInternalError.shouldNotReachHere(Integer.toHexString(reason));
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodData.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodData.java	Mon Dec 02 12:45:18 2013 +0100
@@ -24,6 +24,7 @@
 
 import static com.oracle.graal.graph.UnsafeAccess.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+import static java.lang.String.*;
 
 import java.util.*;
 
@@ -45,8 +46,20 @@
     private static final HotSpotMethodDataAccessor NO_DATA_EXCEPTION_POSSIBLY_NOT_RECORDED_ACCESSOR = new NoMethodData(TriState.UNKNOWN);
 
     // sorted by tag
-    private static final HotSpotMethodDataAccessor[] PROFILE_DATA_ACCESSORS = {null, new BitData(), new CounterData(), new JumpData(), new TypeCheckData(), new VirtualCallData(), new RetData(),
-                    new BranchData(), new MultiBranchData(), new ArgInfoData()};
+    // @formatter:off
+    private static final HotSpotMethodDataAccessor[] PROFILE_DATA_ACCESSORS = {
+        null,
+        new BitData(),
+        new CounterData(),
+        new JumpData(),
+        new TypeCheckData(),
+        new VirtualCallData(),
+        new RetData(),
+        new BranchData(),
+        new MultiBranchData(),
+        new ArgInfoData()
+    };
+    // @formatter:on
 
     /**
      * Reference to the C++ MethodData object.
@@ -96,7 +109,11 @@
         if (position >= normalDataSize + extraDataSize) {
             return null;
         }
-        return getData(position);
+        HotSpotMethodDataAccessor data = getData(position);
+        if (data != null) {
+            return data;
+        }
+        return data;
     }
 
     public static HotSpotMethodDataAccessor getNoDataAccessor(boolean exceptionPossiblyNotRecorded) {
@@ -170,10 +187,46 @@
         return cells * config.dataLayoutCellSize;
     }
 
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        String nl = String.format("%n");
+        String nlIndent = String.format("%n%38s", "");
+        if (hasNormalData()) {
+            int pos = 0;
+            HotSpotMethodDataAccessor data;
+            while ((data = getNormalData(pos)) != null) {
+                if (pos != 0) {
+                    sb.append(nl);
+                }
+                int bci = data.getBCI(this, pos);
+                sb.append(String.format("%-6d bci: %-6d%-20s", pos, bci, data.getClass().getSimpleName()));
+                sb.append(data.appendTo(new StringBuilder(), this, pos).toString().replace(nl, nlIndent));
+                pos = pos + data.getSize(this, pos);
+            }
+        }
+
+        if (hasExtraData()) {
+            int pos = getExtraDataBeginOffset();
+            HotSpotMethodDataAccessor data;
+            while ((data = getExtraData(pos)) != null) {
+                if (pos == getExtraDataBeginOffset()) {
+                    sb.append(nl).append("--- Extra data:");
+                }
+                int bci = data.getBCI(this, pos);
+                sb.append(String.format("%n%-6d bci: %-6d%-20s", pos, bci, data.getClass().getSimpleName()));
+                sb.append(data.appendTo(new StringBuilder(), this, pos).toString().replace(nl, nlIndent));
+                pos = pos + data.getSize(this, pos);
+            }
+
+        }
+        return sb.toString();
+    }
+
     private abstract static class AbstractMethodData implements HotSpotMethodDataAccessor {
 
         /**
-         * Corresponds to DS_RECOMPILE_BIT defined in deoptimization.cpp.
+         * Corresponds to {@code exception_seen_flag}.
          */
         private static final int EXCEPTIONS_MASK = 0x2;
 
@@ -245,17 +298,18 @@
         protected int getDynamicSize(@SuppressWarnings("unused") HotSpotMethodData data, @SuppressWarnings("unused") int position) {
             return 0;
         }
+
+        public abstract StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos);
     }
 
     private static class NoMethodData extends AbstractMethodData {
 
-        private static final int NO_DATA_TAG = 0;
         private static final int NO_DATA_SIZE = cellIndexToOffset(0);
 
         private final TriState exceptionSeen;
 
         protected NoMethodData(TriState exceptionSeen) {
-            super(NO_DATA_TAG, NO_DATA_SIZE);
+            super(runtime().getConfig().dataLayoutNoTag, NO_DATA_SIZE);
             this.exceptionSeen = exceptionSeen;
         }
 
@@ -268,16 +322,20 @@
         public TriState getExceptionSeen(HotSpotMethodData data, int position) {
             return exceptionSeen;
         }
+
+        @Override
+        public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) {
+            return sb;
+        }
     }
 
     private static class BitData extends AbstractMethodData {
 
-        private static final int BIT_DATA_TAG = 1;
         private static final int BIT_DATA_SIZE = cellIndexToOffset(0);
         private static final int BIT_DATA_NULL_SEEN_FLAG = 0x01;
 
         private BitData() {
-            super(BIT_DATA_TAG, BIT_DATA_SIZE);
+            super(runtime().getConfig().dataLayoutBitDataTag, BIT_DATA_SIZE);
         }
 
         protected BitData(int tag, int staticSize) {
@@ -288,16 +346,20 @@
         public TriState getNullSeen(HotSpotMethodData data, int position) {
             return TriState.get((getFlags(data, position) & BIT_DATA_NULL_SEEN_FLAG) != 0);
         }
+
+        @Override
+        public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) {
+            return sb.append(format("exception_seen(%s)", getExceptionSeen(data, pos)));
+        }
     }
 
     private static class CounterData extends BitData {
 
-        private static final int COUNTER_DATA_TAG = 2;
         private static final int COUNTER_DATA_SIZE = cellIndexToOffset(1);
         private static final int COUNTER_DATA_COUNT_OFFSET = cellIndexToOffset(0);
 
         public CounterData() {
-            super(COUNTER_DATA_TAG, COUNTER_DATA_SIZE);
+            super(runtime().getConfig().dataLayoutCounterDataTag, COUNTER_DATA_SIZE);
         }
 
         protected CounterData(int tag, int staticSize) {
@@ -312,17 +374,21 @@
         protected int getCounterValue(HotSpotMethodData data, int position) {
             return data.readUnsignedIntAsSignedInt(position, COUNTER_DATA_COUNT_OFFSET);
         }
+
+        @Override
+        public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) {
+            return sb.append(format("count(%d)", getCounterValue(data, pos)));
+        }
     }
 
     private static class JumpData extends AbstractMethodData {
 
-        private static final int JUMP_DATA_TAG = 3;
         private static final int JUMP_DATA_SIZE = cellIndexToOffset(2);
         protected static final int TAKEN_COUNT_OFFSET = cellIndexToOffset(0);
         protected static final int TAKEN_DISPLACEMENT_OFFSET = cellIndexToOffset(1);
 
         public JumpData() {
-            super(JUMP_DATA_TAG, JUMP_DATA_SIZE);
+            super(runtime().getConfig().dataLayoutJumpDataTag, JUMP_DATA_SIZE);
         }
 
         protected JumpData(int tag, int staticSize) {
@@ -339,10 +405,28 @@
             return data.readUnsignedIntAsSignedInt(position, TAKEN_COUNT_OFFSET);
         }
 
-        @SuppressWarnings("unused")
         public int getTakenDisplacement(HotSpotMethodData data, int position) {
             return data.readInt(position, TAKEN_DISPLACEMENT_OFFSET);
         }
+
+        @Override
+        public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) {
+            return sb.append(format("taken(%d) displacement(%d)", getExecutionCount(data, pos), getTakenDisplacement(data, pos)));
+        }
+    }
+
+    static class RawItemProfile<T> {
+        final int entries;
+        final T[] items;
+        final long[] counts;
+        final long totalCount;
+
+        public RawItemProfile(int entries, T[] items, long[] counts, long totalCount) {
+            this.entries = entries;
+            this.items = items;
+            this.counts = counts;
+            this.totalCount = totalCount;
+        }
     }
 
     private abstract static class AbstractTypeData extends CounterData {
@@ -359,6 +443,10 @@
 
         @Override
         public JavaTypeProfile getTypeProfile(HotSpotMethodData data, int position) {
+            return createTypeProfile(getNullSeen(data, position), getRawTypeProfile(data, position));
+        }
+
+        private RawItemProfile<ResolvedJavaType> getRawTypeProfile(HotSpotMethodData data, int position) {
             int typeProfileWidth = config.typeProfileWidth;
 
             ResolvedJavaType[] types = new ResolvedJavaType[typeProfileWidth];
@@ -373,35 +461,34 @@
                     long count = data.readUnsignedInt(position, getTypeCountOffset(i));
                     totalCount += count;
                     counts[entries] = count;
-
                     entries++;
                 }
             }
 
             totalCount += getTypesNotRecordedExecutionCount(data, position);
-            return createTypeProfile(getNullSeen(data, position), types, counts, totalCount, entries);
+            return new RawItemProfile<>(entries, types, counts, totalCount);
         }
 
         protected abstract long getTypesNotRecordedExecutionCount(HotSpotMethodData data, int position);
 
-        private static JavaTypeProfile createTypeProfile(TriState nullSeen, ResolvedJavaType[] types, long[] counts, long totalCount, int entries) {
-            if (entries <= 0 || totalCount <= 0) {
+        private static JavaTypeProfile createTypeProfile(TriState nullSeen, RawItemProfile<ResolvedJavaType> profile) {
+            if (profile.entries <= 0 || profile.totalCount <= 0) {
                 return null;
             }
 
-            ProfiledType[] ptypes = new ProfiledType[entries];
+            ProfiledType[] ptypes = new ProfiledType[profile.entries];
             double totalProbability = 0.0;
-            for (int i = 0; i < entries; i++) {
-                double p = counts[i];
-                p = p / totalCount;
+            for (int i = 0; i < profile.entries; i++) {
+                double p = profile.counts[i];
+                p = p / profile.totalCount;
                 totalProbability += p;
-                ptypes[i] = new ProfiledType(types[i], p);
+                ptypes[i] = new ProfiledType(profile.items[i], p);
             }
 
             Arrays.sort(ptypes);
 
-            double notRecordedTypeProbability = entries < config.typeProfileWidth ? 0.0 : Math.min(1.0, Math.max(0.0, 1.0 - totalProbability));
-            assert notRecordedTypeProbability == 0 || entries == config.typeProfileWidth;
+            double notRecordedTypeProbability = profile.entries < config.typeProfileWidth ? 0.0 : Math.min(1.0, Math.max(0.0, 1.0 - totalProbability));
+            assert notRecordedTypeProbability == 0 || profile.entries == config.typeProfileWidth;
             return new JavaTypeProfile(nullSeen, notRecordedTypeProbability, ptypes);
         }
 
@@ -412,15 +499,26 @@
         protected static int getTypeCountOffset(int row) {
             return TYPE_DATA_FIRST_TYPE_COUNT_OFFSET + row * TYPE_DATA_ROW_SIZE;
         }
+
+        @Override
+        public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) {
+            RawItemProfile<ResolvedJavaType> profile = getRawTypeProfile(data, pos);
+            TriState nullSeen = getNullSeen(data, pos);
+            sb.append(format("count(%d) null_seen(%s) nonprofiled_count(%d) entries(%d)", getCounterValue(data, pos), nullSeen, getTypesNotRecordedExecutionCount(data, pos), profile.entries));
+            for (int i = 0; i < profile.entries; i++) {
+                long count = profile.counts[i];
+                sb.append(format("%n  %s (%d, %4.2f)", MetaUtil.toJavaName(profile.items[i]), count, (double) count / profile.totalCount));
+            }
+            return sb;
+        }
     }
 
     private static class TypeCheckData extends AbstractTypeData {
 
-        private static final int TYPE_CHECK_DATA_TAG = 4;
         private static final int TYPE_CHECK_DATA_SIZE = cellIndexToOffset(2) + TYPE_DATA_ROW_SIZE * config.typeProfileWidth;
 
         public TypeCheckData() {
-            super(TYPE_CHECK_DATA_TAG, TYPE_CHECK_DATA_SIZE);
+            super(runtime().getConfig().dataLayoutReceiverTypeDataTag, TYPE_CHECK_DATA_SIZE);
         }
 
         @Override
@@ -436,13 +534,12 @@
 
     private static class VirtualCallData extends AbstractTypeData {
 
-        private static final int VIRTUAL_CALL_DATA_TAG = 5;
         private static final int VIRTUAL_CALL_DATA_SIZE = cellIndexToOffset(2) + TYPE_DATA_ROW_SIZE * (config.typeProfileWidth + config.methodProfileWidth);
         private static final int VIRTUAL_CALL_DATA_FIRST_METHOD_OFFSET = TYPE_DATA_FIRST_TYPE_OFFSET + TYPE_DATA_ROW_SIZE * config.typeProfileWidth;
         private static final int VIRTUAL_CALL_DATA_FIRST_METHOD_COUNT_OFFSET = TYPE_DATA_FIRST_TYPE_COUNT_OFFSET + TYPE_DATA_ROW_SIZE * config.typeProfileWidth;
 
         public VirtualCallData() {
-            super(VIRTUAL_CALL_DATA_TAG, VIRTUAL_CALL_DATA_SIZE);
+            super(runtime().getConfig().dataLayoutVirtualCallDataTag, VIRTUAL_CALL_DATA_SIZE);
         }
 
         @Override
@@ -469,6 +566,10 @@
 
         @Override
         public JavaMethodProfile getMethodProfile(HotSpotMethodData data, int position) {
+            return createMethodProfile(getRawMethodProfile(data, position));
+        }
+
+        private static RawItemProfile<ResolvedJavaMethod> getRawMethodProfile(HotSpotMethodData data, int position) {
             int profileWidth = config.methodProfileWidth;
 
             ResolvedJavaMethod[] methods = new ResolvedJavaMethod[profileWidth];
@@ -489,27 +590,27 @@
             }
 
             totalCount += getMethodsNotRecordedExecutionCount(data, position);
-            return createMethodProfile(methods, counts, totalCount, entries);
+            return new RawItemProfile<>(entries, methods, counts, totalCount);
         }
 
-        private static JavaMethodProfile createMethodProfile(ResolvedJavaMethod[] methods, long[] counts, long totalCount, int entries) {
-            if (entries <= 0 || totalCount <= 0) {
+        private static JavaMethodProfile createMethodProfile(RawItemProfile<ResolvedJavaMethod> profile) {
+            if (profile.entries <= 0 || profile.totalCount <= 0) {
                 return null;
             }
 
-            ProfiledMethod[] pmethods = new ProfiledMethod[entries];
+            ProfiledMethod[] pmethods = new ProfiledMethod[profile.entries];
             double totalProbability = 0.0;
-            for (int i = 0; i < entries; i++) {
-                double p = counts[i];
-                p = p / totalCount;
+            for (int i = 0; i < profile.entries; i++) {
+                double p = profile.counts[i];
+                p = p / profile.totalCount;
                 totalProbability += p;
-                pmethods[i] = new ProfiledMethod(methods[i], p);
+                pmethods[i] = new ProfiledMethod(profile.items[i], p);
             }
 
             Arrays.sort(pmethods);
 
-            double notRecordedMethodProbability = entries < config.methodProfileWidth ? 0.0 : Math.min(1.0, Math.max(0.0, 1.0 - totalProbability));
-            assert notRecordedMethodProbability == 0 || entries == config.methodProfileWidth;
+            double notRecordedMethodProbability = profile.entries < config.methodProfileWidth ? 0.0 : Math.min(1.0, Math.max(0.0, 1.0 - totalProbability));
+            assert notRecordedMethodProbability == 0 || profile.entries == config.methodProfileWidth;
             return new JavaMethodProfile(notRecordedMethodProbability, pmethods);
         }
 
@@ -520,27 +621,36 @@
         private static int getMethodCountOffset(int row) {
             return VIRTUAL_CALL_DATA_FIRST_METHOD_COUNT_OFFSET + row * TYPE_DATA_ROW_SIZE;
         }
+
+        @Override
+        public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) {
+            RawItemProfile<ResolvedJavaMethod> profile = getRawMethodProfile(data, pos);
+            super.appendTo(sb.append(format("exception_seen(%s) ", getExceptionSeen(data, pos))), data, pos).append(format("%nmethod_entries(%d)", profile.entries));
+            for (int i = 0; i < profile.entries; i++) {
+                long count = profile.counts[i];
+                sb.append(format("%n  %s (%d, %4.2f)", MetaUtil.format("%H.%n(%p)", profile.items[i]), count, (double) count / profile.totalCount));
+            }
+            return sb;
+        }
     }
 
     private static class RetData extends CounterData {
 
-        private static final int RET_DATA_TAG = 6;
         private static final int RET_DATA_ROW_SIZE = cellsToBytes(3);
         private static final int RET_DATA_SIZE = cellIndexToOffset(1) + RET_DATA_ROW_SIZE * config.bciProfileWidth;
 
         public RetData() {
-            super(RET_DATA_TAG, RET_DATA_SIZE);
+            super(runtime().getConfig().dataLayoutRetDataTag, RET_DATA_SIZE);
         }
     }
 
     private static class BranchData extends JumpData {
 
-        private static final int BRANCH_DATA_TAG = 7;
         private static final int BRANCH_DATA_SIZE = cellIndexToOffset(3);
         private static final int NOT_TAKEN_COUNT_OFFSET = cellIndexToOffset(2);
 
         public BranchData() {
-            super(BRANCH_DATA_TAG, BRANCH_DATA_SIZE);
+            super(runtime().getConfig().dataLayoutBranchDataTag, BRANCH_DATA_SIZE);
         }
 
         @Override
@@ -557,6 +667,14 @@
             long count = data.readUnsignedInt(position, TAKEN_COUNT_OFFSET) + data.readUnsignedInt(position, NOT_TAKEN_COUNT_OFFSET);
             return truncateLongToInt(count);
         }
+
+        @Override
+        public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) {
+            long taken = data.readUnsignedInt(pos, TAKEN_COUNT_OFFSET);
+            long notTaken = data.readUnsignedInt(pos, NOT_TAKEN_COUNT_OFFSET);
+            double takenProbability = getBranchTakenProbability(data, pos);
+            return sb.append(format("taken(%d, %4.2f) not_taken(%d, %4.2f) displacement(%d)", taken, takenProbability, notTaken, 1.0D - takenProbability, getTakenDisplacement(data, pos)));
+        }
     }
 
     private static class ArrayData extends AbstractMethodData {
@@ -576,11 +694,15 @@
         protected static int getLength(HotSpotMethodData data, int position) {
             return data.readInt(position, ARRAY_DATA_LENGTH_OFFSET);
         }
+
+        @Override
+        public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) {
+            return sb.append(format("length(%d)", getLength(data, pos)));
+        }
     }
 
     private static class MultiBranchData extends ArrayData {
 
-        private static final int MULTI_BRANCH_DATA_TAG = 8;
         private static final int MULTI_BRANCH_DATA_SIZE = cellIndexToOffset(1);
         private static final int MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS = 2;
         private static final int MULTI_BRANCH_DATA_ROW_SIZE = cellsToBytes(MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS);
@@ -588,7 +710,7 @@
         private static final int MULTI_BRANCH_DATA_FIRST_DISPLACEMENT_OFFSET = ARRAY_DATA_START_OFFSET + cellsToBytes(1);
 
         public MultiBranchData() {
-            super(MULTI_BRANCH_DATA_TAG, MULTI_BRANCH_DATA_SIZE);
+            super(runtime().getConfig().dataLayoutMultiBranchDataTag, MULTI_BRANCH_DATA_SIZE);
         }
 
         @Override
@@ -650,19 +772,27 @@
             return MULTI_BRANCH_DATA_FIRST_COUNT_OFFSET + index * MULTI_BRANCH_DATA_ROW_SIZE;
         }
 
-        @SuppressWarnings("unused")
         private static int getDisplacementOffset(int index) {
             return MULTI_BRANCH_DATA_FIRST_DISPLACEMENT_OFFSET + index * MULTI_BRANCH_DATA_ROW_SIZE;
         }
+
+        @Override
+        public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) {
+            int entries = getLength(data, pos) / MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS;
+            sb.append(format("entries(%d)", entries));
+            for (int i = 0; i < entries; i++) {
+                sb.append(format("%n  %d: count(%d) displacement(%d)", i, data.readUnsignedInt(pos, getCountOffset(i)), data.readUnsignedInt(pos, getDisplacementOffset(i))));
+            }
+            return sb;
+        }
     }
 
     private static class ArgInfoData extends ArrayData {
 
-        private static final int ARG_INFO_DATA_TAG = 9;
         private static final int ARG_INFO_DATA_SIZE = cellIndexToOffset(1);
 
         public ArgInfoData() {
-            super(ARG_INFO_DATA_TAG, ARG_INFO_DATA_SIZE);
+            super(runtime().getConfig().dataLayoutArgInfoDataTag, ARG_INFO_DATA_SIZE);
         }
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodDataAccessor.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodDataAccessor.java	Mon Dec 02 12:45:18 2013 +0100
@@ -66,4 +66,6 @@
     TriState getNullSeen(HotSpotMethodData data, int position);
 
     int getExecutionCount(HotSpotMethodData data, int position);
+
+    StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java	Mon Dec 02 12:45:18 2013 +0100
@@ -34,6 +34,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.meta.ProfilingInfo.TriState;
+import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.debug.*;
@@ -282,6 +283,8 @@
         return getCompiledCodeSize() > 0;
     }
 
+    private static final String TraceMethodDataFilter = System.getProperty("graal.traceMethodDataFilter");
+
     @Override
     public ProfilingInfo getProfilingInfo() {
         ProfilingInfo info;
@@ -290,6 +293,10 @@
             long metaspaceMethodData = unsafeReadWord(metaspaceMethod + runtime().getConfig().methodDataOffset);
             if (metaspaceMethodData != 0) {
                 methodData = new HotSpotMethodData(metaspaceMethodData);
+                if (TraceMethodDataFilter != null && MetaUtil.format("%H.%n", this).contains(TraceMethodDataFilter)) {
+                    TTY.println("Raw method data for " + MetaUtil.format("%H.%n(%p)", this) + ":");
+                    TTY.println(methodData.toString());
+                }
             }
         }
 
@@ -364,6 +371,15 @@
         return false;
     }
 
+    public boolean isDefault() {
+        if (isConstructor()) {
+            return false;
+        }
+        // Copied from java.lang.Method.isDefault()
+        int mask = Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC;
+        return ((getModifiers() & mask) == Modifier.PUBLIC) && getDeclaringClass().isInterface();
+    }
+
     @Override
     public Type[] getGenericParameterTypes() {
         if (isConstructor()) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java	Mon Dec 02 12:45:18 2013 +0100
@@ -37,7 +37,7 @@
  * is locked (ensuring the GC sees and updates the object) so it must come after any null pointer
  * check on the object.
  */
-public final class BeginLockScopeNode extends AbstractStateSplit implements LIRGenLowerable, MonitorEnter, MemoryCheckpoint.Single {
+public final class BeginLockScopeNode extends AbstractMemoryCheckpoint implements LIRGenLowerable, MonitorEnter, MemoryCheckpoint.Single {
 
     private int lockDepth;
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DirectCompareAndSwapNode.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DirectCompareAndSwapNode.java	Mon Dec 02 12:45:18 2013 +0100
@@ -95,4 +95,12 @@
      */
     @NodeIntrinsic
     public static native Word compareAndSwap(Object object, long offset, Word expectedValue, Word newValue, @ConstantNodeParameter LocationIdentity locationIdentity);
+
+    public MemoryCheckpoint asMemoryCheckpoint() {
+        return this;
+    }
+
+    public MemoryPhiNode asMemoryPhi() {
+        return null;
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EndLockScopeNode.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EndLockScopeNode.java	Mon Dec 02 12:45:18 2013 +0100
@@ -33,7 +33,7 @@
  * Intrinsic for closing a {@linkplain BeginLockScopeNode scope} binding a stack-based lock with an
  * object.
  */
-public final class EndLockScopeNode extends AbstractStateSplit implements LIRGenLowerable, MonitorExit, MemoryCheckpoint.Single {
+public final class EndLockScopeNode extends AbstractMemoryCheckpoint implements LIRGenLowerable, MonitorExit, MemoryCheckpoint.Single {
 
     public EndLockScopeNode() {
         super(StampFactory.forVoid());
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/StubForeignCallNode.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/StubForeignCallNode.java	Mon Dec 02 12:45:18 2013 +0100
@@ -83,4 +83,12 @@
         }
         return super.toString(verbosity);
     }
+
+    public MemoryCheckpoint asMemoryCheckpoint() {
+        return this;
+    }
+
+    public MemoryPhiNode asMemoryPhi() {
+        return null;
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopyNode.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopyNode.java	Mon Dec 02 12:45:18 2013 +0100
@@ -24,10 +24,9 @@
 
 import static com.oracle.graal.compiler.GraalCompiler.*;
 
-import java.util.concurrent.*;
-
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.loop.phases.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
@@ -76,14 +75,11 @@
         }
         Kind componentKind = srcType.getComponentType().getKind();
         final ResolvedJavaMethod snippetMethod = tool.getMetaAccess().lookupJavaMethod(ArrayCopySnippets.getSnippetForKind(componentKind));
-        return Debug.scope("ArrayCopySnippet", snippetMethod, new Callable<StructuredGraph>() {
-
-            @Override
-            public StructuredGraph call() throws Exception {
-                return replacements.getSnippet(snippetMethod);
-            }
-        });
-
+        try (Scope s = Debug.scope("ArrayCopySnippet", snippetMethod)) {
+            return replacements.getSnippet(snippetMethod);
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
     }
 
     private static void unrollFixedLengthLoop(StructuredGraph snippetGraph, int length, LoweringTool tool) {
@@ -93,8 +89,7 @@
         }
         // the canonicalization before loop unrolling is needed to propagate the length into
         // additions, etc.
-        PhaseContext context = new PhaseContext(tool.getMetaAccess(), tool.getCodeCache(), tool.getConstantReflection(), tool.getForeignCalls(), tool.getLowerer(), tool.assumptions(),
-                        tool.getReplacements());
+        PhaseContext context = new PhaseContext(tool.getMetaAccess(), tool.getConstantReflection(), tool.getLowerer(), tool.getReplacements(), tool.assumptions());
         new CanonicalizerPhase(true).apply(snippetGraph, context);
         new LoopFullUnrollPhase(new CanonicalizerPhase(true)).apply(snippetGraph, context);
         new CanonicalizerPhase(true).apply(snippetGraph, context);
@@ -110,26 +105,23 @@
         StructuredGraph snippetGraph = selectSnippet(tool, replacements);
         if (snippetGraph == null) {
             final ResolvedJavaMethod snippetMethod = tool.getMetaAccess().lookupJavaMethod(ArrayCopySnippets.genericArraycopySnippet);
-            snippetGraph = Debug.scope("ArrayCopySnippet", snippetMethod, new Callable<StructuredGraph>() {
-
-                @Override
-                public StructuredGraph call() throws Exception {
-                    return replacements.getSnippet(snippetMethod).copy();
-                }
-            });
+            snippetGraph = null;
+            try (Scope s = Debug.scope("ArrayCopySnippet", snippetMethod)) {
+                snippetGraph = replacements.getSnippet(snippetMethod).copy();
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            }
             replaceSnippetInvokes(snippetGraph);
         } else {
             assert snippetGraph != null : "ArrayCopySnippets should be installed";
             snippetGraph = snippetGraph.copy();
             if (getLength().isConstant() && getLength().asConstant().asInt() <= GraalOptions.MaximumEscapeAnalysisArrayLength.getValue()) {
                 final StructuredGraph copy = snippetGraph;
-                Debug.scope("ArrayCopySnippetSpecialization", snippetGraph.method(), new Runnable() {
-
-                    @Override
-                    public void run() {
-                        unrollFixedLengthLoop(copy, getLength().asConstant().asInt(), tool);
-                    }
-                });
+                try (Scope s = Debug.scope("ArrayCopySnippetSpecialization", snippetGraph.method())) {
+                    unrollFixedLengthLoop(copy, getLength().asConstant().asInt(), tool);
+                } catch (Throwable e) {
+                    throw Debug.handle(e);
+                }
             }
         }
         return lowerReplacement(snippetGraph, tool);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java	Mon Dec 02 12:45:18 2013 +0100
@@ -69,7 +69,7 @@
         return AESCryptSubstitutions.AESCryptClass;
     }
 
-    @MethodSubstitution(isStatic = false)
+    @MethodSubstitution(isStatic = false, optional = true)
     static void encrypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) {
         Object embeddedCipher = UnsafeLoadNode.load(rcvr, embeddedCipherOffset, Kind.Object, embeddedCipherLocationIdentity);
         if (getAESCryptClass().isInstance(embeddedCipher)) {
@@ -79,7 +79,7 @@
         }
     }
 
-    @MethodSubstitution(isStatic = false)
+    @MethodSubstitution(isStatic = false, optional = true)
     static void decrypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) {
         Object embeddedCipher = UnsafeLoadNode.load(rcvr, embeddedCipherOffset, Kind.Object, embeddedCipherLocationIdentity);
         if (in != out && getAESCryptClass().isInstance(embeddedCipher)) {
@@ -89,6 +89,28 @@
         }
     }
 
+    @MethodSubstitution(value = "encrypt", isStatic = false, optional = true)
+    static int encryptInt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) {
+        Object embeddedCipher = UnsafeLoadNode.load(rcvr, embeddedCipherOffset, Kind.Object, embeddedCipherLocationIdentity);
+        if (getAESCryptClass().isInstance(embeddedCipher)) {
+            crypt(rcvr, in, inOffset, inLength, out, outOffset, embeddedCipher, true);
+            return inLength;
+        } else {
+            return encryptInt(rcvr, in, inOffset, inLength, out, outOffset);
+        }
+    }
+
+    @MethodSubstitution(value = "decrypt", isStatic = false, optional = true)
+    static int decryptInt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) {
+        Object embeddedCipher = UnsafeLoadNode.load(rcvr, embeddedCipherOffset, Kind.Object, embeddedCipherLocationIdentity);
+        if (in != out && getAESCryptClass().isInstance(embeddedCipher)) {
+            crypt(rcvr, in, inOffset, inLength, out, outOffset, embeddedCipher, false);
+            return inLength;
+        } else {
+            return decryptInt(rcvr, in, inOffset, inLength, out, outOffset);
+        }
+    }
+
     private static void crypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset, Object embeddedCipher, boolean encrypt) {
         Object kObject = UnsafeLoadNode.load(embeddedCipher, AESCryptSubstitutions.kOffset, Kind.Object, AESCryptSubstitutions.kLocationIdentity);
         Object rObject = UnsafeLoadNode.load(rcvr, rOffset, Kind.Object, rLocationIdentity);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Mon Dec 02 12:45:18 2013 +0100
@@ -246,12 +246,12 @@
                 new_seqInit.inc();
                 explodeLoop();
                 for (int offset = instanceHeaderSize(); offset < size; offset += wordSize()) {
-                    memory.writeWord(offset, Word.zero(), INIT_LOCATION);
+                    memory.initializeWord(offset, Word.zero(), INIT_LOCATION);
                 }
             } else {
                 new_loopInit.inc();
                 for (int offset = instanceHeaderSize(); offset < size; offset += wordSize()) {
-                    memory.writeWord(offset, Word.zero(), INIT_LOCATION);
+                    memory.initializeWord(offset, Word.zero(), INIT_LOCATION);
                 }
             }
         }
@@ -270,7 +270,7 @@
         initializeObjectHeader(memory, prototypeMarkWord, hub);
         if (fillContents) {
             for (int offset = headerSize; offset < allocationSize; offset += wordSize()) {
-                memory.writeWord(offset, Word.zero(), INIT_LOCATION);
+                memory.initializeWord(offset, Word.zero(), INIT_LOCATION);
             }
         }
         return memory.toObject();
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java	Mon Dec 02 12:45:18 2013 +0100
@@ -25,11 +25,11 @@
 import static com.oracle.graal.compiler.GraalCompiler.*;
 
 import java.lang.reflect.*;
-import java.util.concurrent.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
@@ -65,13 +65,12 @@
                 if (method != null) {
                     final ResolvedJavaMethod snippetMethod = tool.getMetaAccess().lookupJavaMethod(method);
                     final Replacements replacements = tool.getReplacements();
-                    StructuredGraph snippetGraph = Debug.scope("ArrayCopySnippet", snippetMethod, new Callable<StructuredGraph>() {
-
-                        @Override
-                        public StructuredGraph call() throws Exception {
-                            return replacements.getSnippet(snippetMethod);
-                        }
-                    });
+                    StructuredGraph snippetGraph = null;
+                    try (Scope s = Debug.scope("ArrayCopySnippet", snippetMethod)) {
+                        snippetGraph = replacements.getSnippet(snippetMethod);
+                    } catch (Throwable e) {
+                        throw Debug.handle(e);
+                    }
 
                     assert snippetGraph != null : "ObjectCloneSnippets should be installed";
                     return lowerReplacement(snippetGraph.copy(), tool);
@@ -80,7 +79,7 @@
                 type = getConcreteType(getObject().stamp(), tool.assumptions(), tool.getMetaAccess());
                 if (type != null) {
                     StructuredGraph newGraph = new StructuredGraph();
-                    LocalNode local = newGraph.add(new LocalNode(0, getObject().stamp()));
+                    LocalNode local = newGraph.unique(new LocalNode(0, getObject().stamp()));
                     NewInstanceNode newInstance = newGraph.add(new NewInstanceNode(type, true));
                     newGraph.addAfterFixed(newGraph.start(), newInstance);
                     ReturnNode returnNode = newGraph.add(new ReturnNode(newInstance));
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/TypeCheckSnippetUtils.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/TypeCheckSnippetUtils.java	Mon Dec 02 12:45:18 2013 +0100
@@ -30,7 +30,6 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.replacements.*;
@@ -122,7 +121,7 @@
         }
     }
 
-    static Hints createHints(TypeCheckHints hints, MetaAccessProvider metaAccess, boolean positiveOnly, Graph graph) {
+    static Hints createHints(TypeCheckHints hints, MetaAccessProvider metaAccess, boolean positiveOnly, StructuredGraph graph) {
         ConstantNode[] hubs = new ConstantNode[hints.hints.length];
         boolean[] isPositive = new boolean[hints.hints.length];
         int index = 0;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java	Mon Dec 02 12:45:18 2013 +0100
@@ -317,7 +317,7 @@
 
     private void inline(InvokeNode invoke) {
         ResolvedJavaMethod method = ((MethodCallTargetNode) invoke.callTarget()).targetMethod();
-        ReplacementsImpl repl = new ReplacementsImpl(providers, new Assumptions(false));
+        ReplacementsImpl repl = new ReplacementsImpl(providers, new Assumptions(false), providers.getCodeCache().getTarget());
         StructuredGraph calleeGraph = repl.makeGraph(method, null, null, false);
         InliningUtil.inline(invoke, calleeGraph, false);
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java	Mon Dec 02 12:45:18 2013 +0100
@@ -25,13 +25,13 @@
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 
 import java.util.*;
-import java.util.concurrent.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.debug.internal.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
@@ -135,53 +135,47 @@
      */
     public synchronized InstalledCode getCode(final Backend backend) {
         if (code == null) {
-            Debug.sandbox("CompilingStub", new Object[]{providers.getCodeCache(), debugScopeContext()}, DebugScope.getConfig(), new Runnable() {
-
-                @Override
-                public void run() {
+            try (Scope d = Debug.sandbox("CompilingStub", DebugScope.getConfig(), providers.getCodeCache(), debugScopeContext())) {
+                final StructuredGraph graph = getGraph();
+                if (!(graph.start() instanceof StubStartNode)) {
+                    StubStartNode newStart = graph.add(new StubStartNode(Stub.this));
+                    newStart.setStateAfter(graph.start().stateAfter());
+                    graph.replaceFixed(graph.start(), newStart);
+                }
 
-                    final StructuredGraph graph = getGraph();
-                    if (!(graph.start() instanceof StubStartNode)) {
-                        StubStartNode newStart = graph.add(new StubStartNode(Stub.this));
-                        newStart.setStateAfter(graph.start().stateAfter());
-                        graph.replaceFixed(graph.start(), newStart);
-                    }
-
-                    PhasePlan phasePlan = new PhasePlan();
-                    ForeignCallsProvider foreignCalls = providers.getForeignCalls();
-                    MetaAccessProvider metaAccess = providers.getMetaAccess();
-                    CodeCacheProvider codeCache = providers.getCodeCache();
-                    GraphBuilderPhase graphBuilderPhase = new GraphBuilderPhase(metaAccess, foreignCalls, GraphBuilderConfiguration.getDefault(), OptimisticOptimizations.ALL);
-                    phasePlan.addPhase(PhasePosition.AFTER_PARSING, graphBuilderPhase);
-                    // The stub itself needs the incoming calling convention.
-                    CallingConvention incomingCc = linkage.getIncomingCallingConvention();
-                    final CompilationResult compResult = GraalCompiler.compileGraph(graph, incomingCc, getInstalledCodeOwner(), providers, backend, codeCache.getTarget(), null, phasePlan,
-                                    OptimisticOptimizations.ALL, new SpeculationLog(), providers.getSuites().getDefaultSuites(), new CompilationResult());
+                PhasePlan phasePlan = new PhasePlan();
+                ForeignCallsProvider foreignCalls = providers.getForeignCalls();
+                MetaAccessProvider metaAccess = providers.getMetaAccess();
+                CodeCacheProvider codeCache = providers.getCodeCache();
+                GraphBuilderPhase graphBuilderPhase = new GraphBuilderPhase(metaAccess, foreignCalls, GraphBuilderConfiguration.getDefault(), OptimisticOptimizations.ALL);
+                phasePlan.addPhase(PhasePosition.AFTER_PARSING, graphBuilderPhase);
+                // The stub itself needs the incoming calling convention.
+                CallingConvention incomingCc = linkage.getIncomingCallingConvention();
+                final CompilationResult compResult = GraalCompiler.compileGraph(graph, incomingCc, getInstalledCodeOwner(), providers, backend, codeCache.getTarget(), null, phasePlan,
+                                OptimisticOptimizations.ALL, new SpeculationLog(), providers.getSuites().getDefaultSuites(), new CompilationResult());
 
-                    assert destroyedRegisters != null;
-                    code = Debug.scope("CodeInstall", new Callable<InstalledCode>() {
-
-                        @Override
-                        public InstalledCode call() {
-                            Stub stub = Stub.this;
-                            HotSpotRuntimeStub installedCode = new HotSpotRuntimeStub(stub);
-                            HotSpotCompiledCode hsCompResult = new HotSpotCompiledRuntimeStub(stub, compResult);
-                            CodeInstallResult result = runtime().getCompilerToVM().installCode(hsCompResult, installedCode, null);
-                            if (result != CodeInstallResult.OK) {
-                                throw new GraalInternalError("Error installing stub %s: %s", Stub.this, result);
-                            }
-                            if (Debug.isDumpEnabled()) {
-                                Debug.dump(new Object[]{compResult, installedCode}, "After code installation");
-                            }
-                            if (Debug.isLogEnabled()) {
-                                Debug.log("%s", providers.getDisassembler().disassemble(installedCode));
-                            }
-                            return installedCode;
-                        }
-                    });
-
+                assert destroyedRegisters != null;
+                try (Scope s = Debug.scope("CodeInstall")) {
+                    Stub stub = Stub.this;
+                    HotSpotRuntimeStub installedCode = new HotSpotRuntimeStub(stub);
+                    HotSpotCompiledCode hsCompResult = new HotSpotCompiledRuntimeStub(stub, compResult);
+                    CodeInstallResult result = runtime().getCompilerToVM().installCode(hsCompResult, installedCode, null);
+                    if (result != CodeInstallResult.OK) {
+                        throw new GraalInternalError("Error installing stub %s: %s", Stub.this, result);
+                    }
+                    if (Debug.isDumpEnabled()) {
+                        Debug.dump(new Object[]{compResult, installedCode}, "After code installation");
+                    }
+                    if (Debug.isLogEnabled()) {
+                        Debug.log("%s", providers.getDisassembler().disassemble(installedCode));
+                    }
+                    code = installedCode;
+                } catch (Throwable e) {
+                    throw Debug.handle(e);
                 }
-            });
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            }
             assert code != null : "error installing stub " + this;
         }
         return code;
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java	Mon Dec 02 12:45:18 2013 +0100
@@ -31,6 +31,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.bytecode.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.nodes.*;
 
 /**
@@ -210,13 +211,11 @@
             this.log("Before LivenessAnalysis");
         }
         if (OptLivenessAnalysis.getValue()) {
-            Debug.scope("LivenessAnalysis", new Runnable() {
-
-                @Override
-                public void run() {
-                    computeLiveness();
-                }
-            });
+            try (Scope s = Debug.scope("LivenessAnalysis")) {
+                computeLiveness();
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            }
         }
     }
 
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java	Mon Dec 02 12:45:18 2013 +0100
@@ -438,7 +438,7 @@
         }
     }
 
-    private void storeStack(int i, ValueNode x) {
+    public void storeStack(int i, ValueNode x) {
         assert x == null || x.isAlive() && (stack[i] == null || x.kind() == stack[i].kind()) : "Method does not handle changes from one-slot to two-slot values or non-alive values";
         stack[i] = x;
     }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Mon Dec 02 12:45:18 2013 +0100
@@ -159,6 +159,10 @@
         return currentGraph;
     }
 
+    protected ResolvedJavaMethod getMethod() {
+        return method;
+    }
+
     public GraphBuilderPhase(MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts) {
         this.graphBuilderConfig = graphBuilderConfig;
         this.optimisticOpts = optimisticOpts;
@@ -207,12 +211,14 @@
         return map;
     }
 
-    private void build() {
+    protected void build() {
         if (PrintProfilingInformation.getValue()) {
-            TTY.println("Profiling info for " + method);
+            TTY.println("Profiling info for " + MetaUtil.format("%H.%n(%p)", method));
             TTY.println(MetaUtil.indent(MetaUtil.profileToString(profilingInfo, method, CodeUtil.NEW_LINE), "  "));
         }
 
+        Indent indent = Debug.logAndIndent(false, "build graph for %s", method.toString());
+
         // compute the block map, setup exception handlers and get the entrypoint(s)
         BciBlockMapping blockMap = createBlockMap();
         loopHeaders = blockMap.loopHeaders;
@@ -271,6 +277,7 @@
                 n.safeDelete();
             }
         }
+        indent.outdent();
     }
 
     private Block unwindBlock(int bci) {
@@ -864,12 +871,16 @@
     void genNewInstance(int cpi) {
         JavaType type = lookupType(cpi, NEW);
         if (type instanceof ResolvedJavaType && ((ResolvedJavaType) type).isInitialized()) {
-            frameState.apush(append(new NewInstanceNode((ResolvedJavaType) type, true)));
+            frameState.apush(append(createNewInstance((ResolvedJavaType) type, true)));
         } else {
             handleUnresolvedNewInstance(type);
         }
     }
 
+    protected NewInstanceNode createNewInstance(ResolvedJavaType type, boolean fillContents) {
+        return new NewInstanceNode(type, fillContents);
+    }
+
     /**
      * Gets the kind of array elements for the array type code that appears in a
      * {@link Bytecodes#NEWARRAY} bytecode.
@@ -905,20 +916,24 @@
     private void genNewPrimitiveArray(int typeCode) {
         Class<?> clazz = arrayTypeCodeToClass(typeCode);
         ResolvedJavaType elementType = metaAccess.lookupJavaType(clazz);
-        frameState.apush(append(new NewArrayNode(elementType, frameState.ipop(), true)));
+        frameState.apush(append(createNewArray(elementType, frameState.ipop(), true)));
     }
 
     private void genNewObjectArray(int cpi) {
         JavaType type = lookupType(cpi, ANEWARRAY);
         ValueNode length = frameState.ipop();
         if (type instanceof ResolvedJavaType) {
-            frameState.apush(append(new NewArrayNode((ResolvedJavaType) type, length, true)));
+            frameState.apush(append(createNewArray((ResolvedJavaType) type, length, true)));
         } else {
             handleUnresolvedNewObjectArray(type, length);
         }
 
     }
 
+    protected NewArrayNode createNewArray(ResolvedJavaType elementType, ValueNode length, boolean fillContents) {
+        return new NewArrayNode(elementType, length, fillContents);
+    }
+
     private void genNewMultiArray(int cpi) {
         JavaType type = lookupType(cpi, MULTIANEWARRAY);
         int rank = stream().readUByte(bci() + 3);
@@ -1187,16 +1202,21 @@
                 args[0] = TypeProfileProxyNode.create(args[0], profile);
             }
         }
-        MethodCallTargetNode callTarget = currentGraph.add(new MethodCallTargetNode(invokeKind, targetMethod, args, returnType));
+        MethodCallTargetNode callTarget = currentGraph.add(createMethodCallTarget(invokeKind, targetMethod, args, returnType));
         createInvokeNode(callTarget, resultType);
     }
 
+    protected MethodCallTargetNode createMethodCallTarget(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, JavaType returnType) {
+        return new MethodCallTargetNode(invokeKind, targetMethod, args, returnType);
+    }
+
     protected Invoke createInvokeNode(CallTargetNode callTarget, Kind resultType) {
         // be conservative if information was not recorded (could result in endless recompiles
         // otherwise)
         if (graphBuilderConfig.omitAllExceptionEdges() || (optimisticOpts.useExceptionProbability() && profilingInfo.getExceptionSeen(bci()) == TriState.FALSE)) {
-            frameState.pushReturn(resultType, append(new InvokeNode(callTarget, bci())));
-            return new InvokeNode(callTarget, bci());
+            InvokeNode invoke = new InvokeNode(callTarget, bci());
+            frameState.pushReturn(resultType, append(invoke));
+            return invoke;
         } else {
             DispatchBeginNode exceptionEdge = handleException(null, bci());
             InvokeWithExceptionNode invoke = append(new InvokeWithExceptionNode(callTarget, exceptionEdge, bci()));
@@ -1573,7 +1593,7 @@
             Debug.log("Ignoring block %s", block);
             return;
         }
-        Debug.log("Parsing block %s  firstInstruction: %s  loopHeader: %b", block, block.firstInstruction, block.isLoopHeader);
+        Indent indent = Debug.logAndIndent("Parsing block %s  firstInstruction: %s  loopHeader: %b", block, block.firstInstruction, block.isLoopHeader);
 
         lastInstr = block.firstInstruction;
         frameState = block.entryState;
@@ -1600,6 +1620,7 @@
             frameState.setRethrowException(false);
             iterateBytecodesForBlock(block);
         }
+        indent.outdent();
     }
 
     private void connectLoopEndToBegin() {
@@ -1636,15 +1657,15 @@
         ValueNode x = returnKind == Kind.Void ? null : frameState.pop(returnKind);
         assert frameState.stackSize() == 0;
 
+        if (graphBuilderConfig.eagerInfopointMode()) {
+            append(new InfopointNode(InfopointReason.METHOD_END, frameState.create(bci())));
+        }
+
         synchronizedEpilogue(FrameState.AFTER_BCI, x);
         if (frameState.lockDepth() != 0) {
             throw new BailoutException("unbalanced monitors");
         }
 
-        if (graphBuilderConfig.eagerInfopointMode()) {
-            append(new InfopointNode(InfopointReason.METHOD_END, frameState.create(FrameState.AFTER_BCI)));
-        }
-
         append(new ReturnNode(x));
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/ConvertCompare.java	Mon Dec 02 12:45:18 2013 +0100
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.jtt.optimize;
+
+import com.oracle.graal.jtt.*;
+import org.junit.*;
+
+public class ConvertCompare extends JTTTest {
+    public static boolean test(int a, float d) {
+        return a == (double) d;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 0, 2.87f);
+    }
+}
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64AddressValue.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64AddressValue.java	Mon Dec 02 12:45:18 2013 +0100
@@ -51,6 +51,8 @@
         this.index = index;
         this.scale = scale;
         this.displacement = displacement;
+
+        assert scale != null;
     }
 
     private static Register toRegister(AllocatableValue value) {
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java	Mon Dec 02 12:45:18 2013 +0100
@@ -118,7 +118,7 @@
         }
 
         public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) {
-            if (state == null && value.equals(address.base) && address.index == Value.ILLEGAL && address.displacement >= 0 && address.displacement < implicitNullCheckLimit) {
+            if (state == null && value.equals(address.base) && address.index.equals(Value.ILLEGAL) && address.displacement >= 0 && address.displacement < implicitNullCheckLimit) {
                 state = nullCheckState;
                 return true;
             }
--- a/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILArithmetic.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILArithmetic.java	Mon Dec 02 12:45:18 2013 +0100
@@ -403,6 +403,7 @@
                 masm.emitForceBitwise("or", dst, src1, src2);
                 break;
             case IREM:
+            case LREM:
                 masm.emit("rem", dst, src1, src2);
                 break;
             default:
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValueClass.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValueClass.java	Mon Dec 02 12:45:18 2013 +0100
@@ -61,11 +61,15 @@
     private final long[] componentOffsets;
     private final EnumSet<OperandFlag>[] componentFlags;
 
+    public CompositeValueClass(Class<? extends CompositeValue> clazz) {
+        this(clazz, new DefaultCalcOffset());
+    }
+
     @SuppressWarnings("unchecked")
-    public CompositeValueClass(Class<? extends CompositeValue> clazz) {
+    public CompositeValueClass(Class<? extends CompositeValue> clazz, CalcOffset calcOffset) {
         super(clazz);
 
-        ValueFieldScanner scanner = new ValueFieldScanner(new DefaultCalcOffset());
+        ValueFieldScanner scanner = new ValueFieldScanner(calcOffset);
         scanner.scan(clazz);
 
         OperandModeAnnotation mode = scanner.valueAnnotations.get(CompositeValue.Component.class);
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstructionClass.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstructionClass.java	Mon Dec 02 12:45:18 2013 +0100
@@ -73,12 +73,16 @@
     private String opcodeConstant;
     private long opcodeOffset;
 
+    public LIRInstructionClass(Class<? extends LIRInstruction> clazz) {
+        this(clazz, new DefaultCalcOffset());
+    }
+
     @SuppressWarnings("unchecked")
-    public LIRInstructionClass(Class<? extends LIRInstruction> clazz) {
+    public LIRInstructionClass(Class<? extends LIRInstruction> clazz, CalcOffset calcOffset) {
         super(clazz);
         assert INSTRUCTION_CLASS.isAssignableFrom(clazz);
 
-        InstructionFieldScanner scanner = new InstructionFieldScanner(new DefaultCalcOffset());
+        InstructionFieldScanner scanner = new InstructionFieldScanner(calcOffset);
         scanner.scan(clazz);
 
         OperandModeAnnotation mode = scanner.valueAnnotations.get(LIRInstruction.Use.class);
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java	Mon Dec 02 12:45:18 2013 +0100
@@ -28,7 +28,6 @@
 import com.oracle.graal.graph.Graph.DuplicationReplacement;
 import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.PhiNode.PhiType;
 import com.oracle.graal.nodes.VirtualState.NodeClosure;
 import com.oracle.graal.nodes.VirtualState.VirtualClosure;
 import com.oracle.graal.nodes.cfg.*;
@@ -313,7 +312,20 @@
                 final ValueNode replaceWith;
                 ProxyNode newVpn = getDuplicatedNode(vpn);
                 if (newVpn != null) {
-                    PhiNode phi = graph.addWithoutUnique(vpn.type() == PhiType.Value ? new PhiNode(vpn.kind(), merge) : new PhiNode(vpn.type(), merge, vpn.getIdentity()));
+                    PhiNode phi;
+                    switch (vpn.type()) {
+                        case Value:
+                            phi = graph.addWithoutUnique(new PhiNode(vpn.kind(), merge));
+                            break;
+                        case Guard:
+                            phi = graph.addWithoutUnique(new PhiNode(vpn.type(), merge));
+                            break;
+                        case Memory:
+                            phi = graph.addWithoutUnique(new MemoryPhiNode(merge, ((MemoryProxyNode) vpn).getLocationIdentity()));
+                            break;
+                        default:
+                            throw GraalInternalError.shouldNotReachHere();
+                    }
                     phi.addInput(vpn);
                     phi.addInput(newVpn);
                     replaceWith = phi;
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInside.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInside.java	Mon Dec 02 12:45:18 2013 +0100
@@ -166,6 +166,24 @@
         // TODO (gd) ?
     }
 
+    private static PhiNode patchPhi(StructuredGraph graph, PhiNode phi, MergeNode merge) {
+        PhiNode ret;
+        switch (phi.type()) {
+            case Value:
+                ret = new PhiNode(phi.kind(), merge);
+                break;
+            case Guard:
+                ret = new PhiNode(PhiType.Guard, merge);
+                break;
+            case Memory:
+                ret = new MemoryPhiNode(merge, ((MemoryPhiNode) phi).getLocationIdentity());
+                break;
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+        return graph.addWithoutUnique(ret);
+    }
+
     private void patchPeeling(LoopFragmentInside peel) {
         LoopBeginNode loopBegin = loop().loopBegin();
         StructuredGraph graph = loopBegin.graph();
@@ -180,7 +198,7 @@
             }
             // create a new phi (we don't patch the old one since some usages of the old one may
             // still be valid)
-            PhiNode newPhi = graph.addWithoutUnique(phi.type() == PhiType.Value ? new PhiNode(phi.kind(), loopBegin) : new PhiNode(phi.type(), loopBegin, phi.getIdentity()));
+            PhiNode newPhi = patchPhi(graph, phi, loopBegin);
             newPhi.addInput(first);
             for (LoopEndNode end : loopBegin.orderedLoopEnds()) {
                 newPhi.addInput(phi.valueAt(end));
@@ -270,7 +288,7 @@
             }
 
             for (final PhiNode phi : loopBegin.phis().snapshot()) {
-                final PhiNode firstPhi = graph.addWithoutUnique(phi.type() == PhiType.Value ? new PhiNode(phi.kind(), newExitMerge) : new PhiNode(phi.type(), newExitMerge, phi.getIdentity()));
+                final PhiNode firstPhi = patchPhi(graph, phi, newExitMerge);
                 for (AbstractEndNode end : newExitMerge.forwardEnds()) {
                     LoopEndNode loopEnd = reverseEnds.get(end);
                     ValueNode prim = prim(phi.valueAt(loopEnd));
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopsData.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopsData.java	Mon Dec 02 12:45:18 2013 +0100
@@ -23,9 +23,9 @@
 package com.oracle.graal.loop;
 
 import java.util.*;
-import java.util.concurrent.*;
 
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.cfg.*;
 
@@ -36,13 +36,12 @@
     private ControlFlowGraph cfg;
 
     public LoopsData(final StructuredGraph graph) {
-        cfg = Debug.scope("ControlFlowGraph", new Callable<ControlFlowGraph>() {
+        try (Scope s = Debug.scope("ControlFlowGraph")) {
+            cfg = ControlFlowGraph.compute(graph, true, true, true, true);
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
 
-            @Override
-            public ControlFlowGraph call() throws Exception {
-                return ControlFlowGraph.compute(graph, true, true, true, true);
-            }
-        });
         for (Loop lirLoop : cfg.getLoops()) {
             LoopEx ex = new LoopEx(lirLoop, this);
             lirLoopToEx.put(lirLoop, ex);
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformLowPhase.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformLowPhase.java	Mon Dec 02 12:45:18 2013 +0100
@@ -25,6 +25,7 @@
 import static com.oracle.graal.phases.GraalOptions.*;
 
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.NodeClass.NodeClassIterator;
 import com.oracle.graal.loop.*;
 import com.oracle.graal.nodes.*;
@@ -39,15 +40,13 @@
         if (graph.hasLoops()) {
             if (ReassociateInvariants.getValue()) {
                 final LoopsData dataReassociate = new LoopsData(graph);
-                Debug.scope("ReassociateInvariants", new Runnable() {
-
-                    @Override
-                    public void run() {
-                        for (LoopEx loop : dataReassociate.loops()) {
-                            loop.reassociateInvariants();
-                        }
+                try (Scope s = Debug.scope("ReassociateInvariants")) {
+                    for (LoopEx loop : dataReassociate.loops()) {
+                        loop.reassociateInvariants();
                     }
-                });
+                } catch (Throwable e) {
+                    throw Debug.handle(e);
+                }
             }
             if (LoopUnswitch.getValue()) {
                 boolean unswitched;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractFixedGuardNode.java	Mon Dec 02 12:45:18 2013 +0100
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.util.*;
+
+public abstract class AbstractFixedGuardNode extends DeoptimizingFixedWithNextNode implements Simplifiable, GuardingNode {
+
+    @Input private LogicNode condition;
+    private final DeoptimizationReason reason;
+    private final DeoptimizationAction action;
+    private boolean negated;
+
+    public LogicNode condition() {
+        return condition;
+    }
+
+    public void setCondition(LogicNode x) {
+        updateUsages(condition, x);
+        condition = x;
+    }
+
+    protected AbstractFixedGuardNode(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, boolean negated) {
+        super(StampFactory.dependency());
+        this.action = action;
+        this.negated = negated;
+        this.condition = condition;
+        this.reason = deoptReason;
+    }
+
+    public DeoptimizationReason getReason() {
+        return reason;
+    }
+
+    public DeoptimizationAction getAction() {
+        return action;
+    }
+
+    public boolean isNegated() {
+        return negated;
+    }
+
+    @Override
+    public String toString(Verbosity verbosity) {
+        if (verbosity == Verbosity.Name && negated) {
+            return "!" + super.toString(verbosity);
+        } else {
+            return super.toString(verbosity);
+        }
+    }
+
+    @Override
+    public void simplify(SimplifierTool tool) {
+        while (condition instanceof LogicNegationNode) {
+            LogicNegationNode negation = (LogicNegationNode) condition;
+            setCondition(negation.getInput());
+            negated = !negated;
+        }
+    }
+
+    public void lowerToIf() {
+        FixedNode next = next();
+        setNext(null);
+        DeoptimizeNode deopt = graph().add(new DeoptimizeNode(action, reason));
+        deopt.setDeoptimizationState(getDeoptimizationState());
+        IfNode ifNode;
+        AbstractBeginNode noDeoptSuccessor;
+        if (negated) {
+            ifNode = graph().add(new IfNode(condition, deopt, next, 0));
+            noDeoptSuccessor = ifNode.falseSuccessor();
+        } else {
+            ifNode = graph().add(new IfNode(condition, next, deopt, 1));
+            noDeoptSuccessor = ifNode.trueSuccessor();
+        }
+        ((FixedWithNextNode) predecessor()).setNext(ifNode);
+        this.replaceAtUsages(noDeoptSuccessor);
+        GraphUtil.killWithUnusedFloatingInputs(this);
+    }
+
+    @Override
+    public boolean canDeoptimize() {
+        return true;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractMemoryCheckpoint.java	Mon Dec 02 12:45:18 2013 +0100
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes;
+
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.type.*;
+
+/**
+ * Provides an implementation of {@link StateSplit}.
+ */
+public abstract class AbstractMemoryCheckpoint extends AbstractStateSplit implements MemoryCheckpoint {
+
+    protected AbstractMemoryCheckpoint(Stamp stamp) {
+        super(stamp);
+    }
+
+    protected AbstractMemoryCheckpoint(Stamp stamp, FrameState stateAfter) {
+        super(stamp, stateAfter);
+    }
+
+    public MemoryCheckpoint asMemoryCheckpoint() {
+        return this;
+    }
+
+    public MemoryPhiNode asMemoryPhi() {
+        return null;
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java	Mon Dec 02 12:45:18 2013 +0100
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.nodes;
 
+import static com.oracle.graal.graph.Graph.*;
+
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
@@ -42,19 +44,19 @@
 
     private final Constant value;
 
-    protected ConstantNode(Constant value) {
-        super(StampFactory.forConstant(value));
-        this.value = value;
-        ConstantNodes.increment();
+    private static ConstantNode createPrimitive(Constant value) {
+        assert value.getKind() != Kind.Object;
+        return new ConstantNode(value, StampFactory.forConstant(value));
     }
 
     /**
-     * Constructs a new ConstantNode representing the specified constant.
+     * Constructs a new node representing the specified constant.
      * 
      * @param value the constant
      */
-    protected ConstantNode(Constant value, MetaAccessProvider metaAccess) {
-        super(StampFactory.forConstant(value, metaAccess));
+    protected ConstantNode(Constant value, Stamp stamp) {
+        super(stamp);
+        assert stamp != null;
         this.value = value;
         ConstantNodes.increment();
     }
@@ -66,11 +68,13 @@
         return value;
     }
 
+    private static boolean ConstantNodesAreExternal = Boolean.parseBoolean(System.getProperty("graal.constantNodesAreExternal", "true"));
+
     /**
      * Used to measure the impact of ConstantNodes not recording their usages. This and all code
      * predicated on this value being true will be removed at some point.
      */
-    public static final boolean ConstantNodeRecordsUsages = Boolean.getBoolean("graal.constantNodeRecordsUsages");
+    public static final boolean ConstantNodeRecordsUsages = !ConstantNodesAreExternal && Boolean.getBoolean("graal.constantNodeRecordsUsages");
 
     @Override
     public boolean recordsUsages() {
@@ -79,17 +83,23 @@
 
     @Override
     public boolean isDeleted() {
+        if (!ConstantNodesAreExternal) {
+            return super.isDeleted();
+        }
         return false;
     }
 
     @Override
     public boolean isAlive() {
+        if (!ConstantNodesAreExternal) {
+            return super.isAlive();
+        }
         return true;
     }
 
     @Override
     public boolean isExternal() {
-        return true;
+        return ConstantNodesAreExternal;
     }
 
     /**
@@ -110,11 +120,15 @@
     }
 
     /**
-     * Gathers all the {@link ConstantNode}s that are inputs to the {@linkplain Graph#getNodes()
-     * live nodes} in a given graph. This is an expensive operation that should only be used in
-     * test/verification/AOT code.
+     * Gathers all the {@link ConstantNode}s that are inputs to the
+     * {@linkplain StructuredGraph#getNodes() live nodes} in a given graph. This is an expensive
+     * operation that should only be used in test/verification/AOT code.
      */
     public static NodeIterable<ConstantNode> getConstantNodes(StructuredGraph graph) {
+        if (!ConstantNodesAreExternal) {
+            return graph.getNodes().filter(ConstantNode.class);
+        }
+
         Map<ConstantNode, ConstantNode> result = new HashMap<>();
         for (Node node : graph.getNodes()) {
             for (Node input : node.inputs()) {
@@ -166,20 +180,25 @@
         return true;
     }
 
-    public static ConstantNode forConstant(Constant constant, MetaAccessProvider metaAccess, Graph graph) {
+    public static ConstantNode forConstant(Constant constant, MetaAccessProvider metaAccess, StructuredGraph graph) {
         if (constant.getKind().getStackKind() == Kind.Int && constant.getKind() != Kind.Int) {
             return forInt(constant.asInt(), graph);
-        } else if (constant.getKind() == Kind.Object) {
-            return unique(graph, new ConstantNode(constant, metaAccess));
+        }
+        if (ConstantNodesAreExternal && !CacheExternalNodesInGraph) {
+            Stamp stamp = constant.getKind() == Kind.Object ? StampFactory.forConstant(constant, metaAccess) : StampFactory.forConstant(constant);
+            return graph.asConstantNode(constant, stamp);
+        }
+        if (constant.getKind() == Kind.Object) {
+            return unique(graph, new ConstantNode(constant, StampFactory.forConstant(constant, metaAccess)));
         } else {
-            return unique(graph, new ConstantNode(constant));
+            return unique(graph, createPrimitive(constant));
         }
     }
 
     /**
      * Returns a node for a primitive constant.
      */
-    public static ConstantNode forPrimitive(Constant constant, Graph graph) {
+    public static ConstantNode forPrimitive(Constant constant, StructuredGraph graph) {
         assert constant.getKind() != Kind.Object;
         return forConstant(constant, null, graph);
     }
@@ -190,8 +209,11 @@
      * @param d the double value for which to create the instruction
      * @return a node for a double constant
      */
-    public static ConstantNode forDouble(double d, Graph graph) {
-        return unique(graph, new ConstantNode(Constant.forDouble(d)));
+    public static ConstantNode forDouble(double d, StructuredGraph graph) {
+        if (ConstantNodesAreExternal && !CacheExternalNodesInGraph) {
+            return graph.asConstantNode(Constant.forDouble(d), null);
+        }
+        return unique(graph, createPrimitive(Constant.forDouble(d)));
     }
 
     /**
@@ -200,8 +222,11 @@
      * @param f the float value for which to create the instruction
      * @return a node for a float constant
      */
-    public static ConstantNode forFloat(float f, Graph graph) {
-        return unique(graph, new ConstantNode(Constant.forFloat(f)));
+    public static ConstantNode forFloat(float f, StructuredGraph graph) {
+        if (ConstantNodesAreExternal && !CacheExternalNodesInGraph) {
+            return graph.asConstantNode(Constant.forFloat(f), null);
+        }
+        return unique(graph, createPrimitive(Constant.forFloat(f)));
     }
 
     /**
@@ -210,8 +235,11 @@
      * @param i the long value for which to create the instruction
      * @return a node for an long constant
      */
-    public static ConstantNode forLong(long i, Graph graph) {
-        return unique(graph, new ConstantNode(Constant.forLong(i)));
+    public static ConstantNode forLong(long i, StructuredGraph graph) {
+        if (ConstantNodesAreExternal && !CacheExternalNodesInGraph) {
+            return graph.asConstantNode(Constant.forLong(i), null);
+        }
+        return unique(graph, createPrimitive(Constant.forLong(i)));
     }
 
     /**
@@ -220,8 +248,11 @@
      * @param i the integer value for which to create the instruction
      * @return a node for an integer constant
      */
-    public static ConstantNode forInt(int i, Graph graph) {
-        return unique(graph, new ConstantNode(Constant.forInt(i)));
+    public static ConstantNode forInt(int i, StructuredGraph graph) {
+        if (ConstantNodesAreExternal && !CacheExternalNodesInGraph) {
+            return graph.asConstantNode(Constant.forInt(i), null);
+        }
+        return unique(graph, createPrimitive(Constant.forInt(i)));
     }
 
     /**
@@ -230,8 +261,11 @@
      * @param i the boolean value for which to create the instruction
      * @return a node representing the boolean
      */
-    public static ConstantNode forBoolean(boolean i, Graph graph) {
-        return unique(graph, new ConstantNode(Constant.forInt(i ? 1 : 0)));
+    public static ConstantNode forBoolean(boolean i, StructuredGraph graph) {
+        if (ConstantNodesAreExternal && !CacheExternalNodesInGraph) {
+            return graph.asConstantNode(i ? Constant.INT_1 : Constant.INT_0, null);
+        }
+        return unique(graph, createPrimitive(Constant.forInt(i ? 1 : 0)));
     }
 
     /**
@@ -240,8 +274,11 @@
      * @param i the byte value for which to create the instruction
      * @return a node representing the byte
      */
-    public static ConstantNode forByte(byte i, Graph graph) {
-        return unique(graph, new ConstantNode(Constant.forInt(i)));
+    public static ConstantNode forByte(byte i, StructuredGraph graph) {
+        if (ConstantNodesAreExternal && !CacheExternalNodesInGraph) {
+            return graph.asConstantNode(Constant.forInt(i), null);
+        }
+        return unique(graph, createPrimitive(Constant.forInt(i)));
     }
 
     /**
@@ -250,8 +287,11 @@
      * @param i the char value for which to create the instruction
      * @return a node representing the char
      */
-    public static ConstantNode forChar(char i, Graph graph) {
-        return unique(graph, new ConstantNode(Constant.forInt(i)));
+    public static ConstantNode forChar(char i, StructuredGraph graph) {
+        if (ConstantNodesAreExternal && !CacheExternalNodesInGraph) {
+            return graph.asConstantNode(Constant.forInt(i), null);
+        }
+        return unique(graph, createPrimitive(Constant.forInt(i)));
     }
 
     /**
@@ -260,8 +300,11 @@
      * @param i the short value for which to create the instruction
      * @return a node representing the short
      */
-    public static ConstantNode forShort(short i, Graph graph) {
-        return unique(graph, new ConstantNode(Constant.forInt(i)));
+    public static ConstantNode forShort(short i, StructuredGraph graph) {
+        if (ConstantNodesAreExternal && !CacheExternalNodesInGraph) {
+            return graph.asConstantNode(Constant.forInt(i), null);
+        }
+        return unique(graph, createPrimitive(Constant.forInt(i)));
     }
 
     /**
@@ -270,16 +313,24 @@
      * @param o the object value for which to create the instruction
      * @return a node representing the object
      */
-    public static ConstantNode forObject(Object o, MetaAccessProvider metaAccess, Graph graph) {
+    public static ConstantNode forObject(Object o, MetaAccessProvider metaAccess, StructuredGraph graph) {
         assert !(o instanceof Constant) : "wrapping a Constant into a Constant";
-        return unique(graph, new ConstantNode(Constant.forObject(o), metaAccess));
+        Constant constant = Constant.forObject(o);
+        if (ConstantNodesAreExternal && !CacheExternalNodesInGraph) {
+            return graph.asConstantNode(constant, StampFactory.forConstant(constant, metaAccess));
+        }
+        return unique(graph, new ConstantNode(constant, StampFactory.forConstant(constant, metaAccess)));
     }
 
-    private static ConstantNode unique(Graph graph, ConstantNode node) {
-        return graph.uniqueWithoutAdd(node);
+    private static ConstantNode unique(StructuredGraph graph, ConstantNode node) {
+        if (!ConstantNodesAreExternal) {
+            return graph.unique(node);
+        }
+        assert CacheExternalNodesInGraph;
+        return graph.uniqueExternal(node);
     }
 
-    public static ConstantNode forIntegerKind(Kind kind, long value, Graph graph) {
+    public static ConstantNode forIntegerKind(Kind kind, long value, StructuredGraph graph) {
         switch (kind) {
             case Byte:
             case Short:
@@ -292,7 +343,7 @@
         }
     }
 
-    public static ConstantNode forFloatingKind(Kind kind, double value, Graph graph) {
+    public static ConstantNode forFloatingKind(Kind kind, double value, StructuredGraph graph) {
         switch (kind) {
             case Float:
                 return ConstantNode.forFloat((float) value, graph);
@@ -303,7 +354,7 @@
         }
     }
 
-    public static ConstantNode defaultForKind(Kind kind, Graph graph) {
+    public static ConstantNode defaultForKind(Kind kind, StructuredGraph graph) {
         switch (kind) {
             case Boolean:
             case Byte:
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizeNode.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizeNode.java	Mon Dec 02 12:45:18 2013 +0100
@@ -27,7 +27,7 @@
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = "Deopt", nameTemplate = "Deopt {p#reason/s}")
-public class DeoptimizeNode extends AbstractDeoptimizeNode implements LIRLowerable {
+public class DeoptimizeNode extends AbstractDeoptimizeNode implements Lowerable, LIRLowerable {
 
     private final DeoptimizationAction action;
     private final DeoptimizationReason reason;
@@ -54,6 +54,11 @@
     }
 
     @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    @Override
     public void generate(LIRGeneratorTool gen) {
         gen.emitDeoptimize(gen.getMetaAccess().encodeDeoptActionAndReason(action, reason, speculationId), this);
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java	Mon Dec 02 12:45:18 2013 +0100
@@ -27,76 +27,31 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.nodes.util.*;
 
 @NodeInfo(nameTemplate = "FixedGuard(!={p#negated}) {p#reason/s}")
-public final class FixedGuardNode extends DeoptimizingFixedWithNextNode implements Simplifiable, Lowerable, IterableNodeType, GuardingNode {
-
-    @Input private LogicNode condition;
-    private final DeoptimizationReason reason;
-    private final DeoptimizationAction action;
-    private boolean negated;
-
-    public LogicNode condition() {
-        return condition;
-    }
-
-    public void setCondition(LogicNode x) {
-        updateUsages(condition, x);
-        condition = x;
-    }
+public final class FixedGuardNode extends AbstractFixedGuardNode implements Lowerable, IterableNodeType {
 
     public FixedGuardNode(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action) {
         this(condition, deoptReason, action, false);
     }
 
     public FixedGuardNode(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, boolean negated) {
-        super(StampFactory.dependency());
-        this.action = action;
-        this.negated = negated;
-        this.condition = condition;
-        this.reason = deoptReason;
-    }
-
-    public DeoptimizationReason getReason() {
-        return reason;
-    }
-
-    public DeoptimizationAction getAction() {
-        return action;
-    }
-
-    public boolean isNegated() {
-        return negated;
-    }
-
-    @Override
-    public String toString(Verbosity verbosity) {
-        if (verbosity == Verbosity.Name && negated) {
-            return "!" + super.toString(verbosity);
-        } else {
-            return super.toString(verbosity);
-        }
+        super(condition, deoptReason, action, negated);
     }
 
     @Override
     public void simplify(SimplifierTool tool) {
-        while (condition instanceof LogicNegationNode) {
-            LogicNegationNode negation = (LogicNegationNode) condition;
-            setCondition(negation.getInput());
-            negated = !negated;
-        }
+        super.simplify(tool);
 
-        if (condition instanceof LogicConstantNode) {
-            LogicConstantNode c = (LogicConstantNode) condition;
-            if (c.getValue() == negated) {
+        if (condition() instanceof LogicConstantNode) {
+            LogicConstantNode c = (LogicConstantNode) condition();
+            if (c.getValue() == isNegated()) {
                 FixedNode next = this.next();
                 if (next != null) {
                     tool.deleteBranch(next);
                 }
 
-                DeoptimizeNode deopt = graph().add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, reason));
+                DeoptimizeNode deopt = graph().add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, getReason()));
                 deopt.setDeoptimizationState(getDeoptimizationState());
                 setNext(deopt);
             }
@@ -113,22 +68,7 @@
             ValueAnchorNode newAnchor = graph().add(new ValueAnchorNode(guard.asNode()));
             graph().replaceFixedWithFixed(this, newAnchor);
         } else {
-            FixedNode next = next();
-            setNext(null);
-            DeoptimizeNode deopt = graph().add(new DeoptimizeNode(action, reason));
-            deopt.setDeoptimizationState(getDeoptimizationState());
-            IfNode ifNode;
-            AbstractBeginNode noDeoptSuccessor;
-            if (negated) {
-                ifNode = graph().add(new IfNode(condition, deopt, next, 0));
-                noDeoptSuccessor = ifNode.falseSuccessor();
-            } else {
-                ifNode = graph().add(new IfNode(condition, next, deopt, 1));
-                noDeoptSuccessor = ifNode.trueSuccessor();
-            }
-            ((FixedWithNextNode) predecessor()).setNext(ifNode);
-            this.replaceAtUsages(noDeoptSuccessor);
-            GraphUtil.killWithUnusedFloatingInputs(this);
+            lowerToIf();
         }
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java	Mon Dec 02 12:45:18 2013 +0100
@@ -25,6 +25,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -41,7 +42,7 @@
  * control flow would have reached the guarded node (without taking exceptions into account).
  */
 @NodeInfo(nameTemplate = "Guard(!={p#negated}) {p#reason/s}")
-public final class GuardNode extends FloatingGuardedNode implements Canonicalizable, IterableNodeType, GuardingNode, GuardedNode {
+public class GuardNode extends FloatingGuardedNode implements Canonicalizable, IterableNodeType, GuardingNode, GuardedNode {
 
     @Input private LogicNode condition;
     private final DeoptimizationReason reason;
@@ -104,6 +105,20 @@
         return this;
     }
 
+    public FixedWithNextNode lowerGuard() {
+        if (negated() && condition() instanceof IsNullNode) {
+            IsNullNode isNull = (IsNullNode) condition();
+            NullCheckNode nullCheck = graph().add(new NullCheckNode(isNull.object()));
+            setCondition(null);
+            if (isNull.usages().isEmpty()) {
+                isNull.safeDelete();
+            }
+            return nullCheck;
+        }
+
+        return null;
+    }
+
     public void negate() {
         negated = !negated;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java	Mon Dec 02 12:45:18 2013 +0100
@@ -87,7 +87,7 @@
     @Override
     public void virtualize(VirtualizerTool tool) {
         State state = tool.getObjectState(object);
-        if (state != null && state.getState() == EscapeState.Virtual && ObjectStamp.typeOrNull(this).isAssignableFrom(state.getVirtualObject().type())) {
+        if (state != null && state.getState() == EscapeState.Virtual && ObjectStamp.typeOrNull(this) != null && ObjectStamp.typeOrNull(this).isAssignableFrom(state.getVirtualObject().type())) {
             tool.replaceWithVirtual(state.getVirtualObject());
         }
     }
@@ -108,10 +108,12 @@
             if (c.getValue() == negated) {
                 // The guard always fails
                 return graph().add(new DeoptimizeNode(action, reason));
-            }
-
-            if (c.getValue() != negated && stamp().equals(object().stamp())) {
+            } else if (stamp().equals(object().stamp())) {
+                // The guard always succeeds, and does not provide new type information
                 return object;
+            } else {
+                // The guard always succeeds, and provides new type information
+                return graph().unique(new PiNode(object, stamp()));
             }
         }
         return this;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java	Mon Dec 02 12:45:18 2013 +0100
@@ -35,7 +35,7 @@
  * The {@code InvokeNode} represents all kinds of method calls.
  */
 @NodeInfo(nameTemplate = "Invoke#{p#targetMethod/s}")
-public final class InvokeNode extends AbstractStateSplit implements Invoke, LIRLowerable, MemoryCheckpoint.Single {
+public final class InvokeNode extends AbstractMemoryCheckpoint implements Invoke, LIRLowerable, MemoryCheckpoint.Single {
 
     @Input private CallTargetNode callTarget;
     @Input private FrameState deoptState;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Mon Dec 02 12:45:18 2013 +0100
@@ -253,4 +253,12 @@
             return stateAfter();
         }
     }
+
+    public MemoryCheckpoint asMemoryCheckpoint() {
+        return this;
+    }
+
+    public MemoryPhiNode asMemoryPhi() {
+        return null;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/KillingBeginNode.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/KillingBeginNode.java	Mon Dec 02 12:45:18 2013 +0100
@@ -46,4 +46,12 @@
     public LocationIdentity getLocationIdentity() {
         return locationIdentity;
     }
+
+    public MemoryCheckpoint asMemoryCheckpoint() {
+        return this;
+    }
+
+    public MemoryPhiNode asMemoryPhi() {
+        return null;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryMapNode.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryMapNode.java	Mon Dec 02 12:45:18 2013 +0100
@@ -23,8 +23,8 @@
 package com.oracle.graal.nodes;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.type.*;
 
 public abstract class MemoryMapNode extends FloatingNode {
@@ -33,5 +33,5 @@
         super(StampFactory.forVoid());
     }
 
-    public abstract Node getLastLocationAccess(LocationIdentity locationIdentity);
+    public abstract MemoryNode getLastLocationAccess(LocationIdentity locationIdentity);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryPhiNode.java	Mon Dec 02 12:45:18 2013 +0100
@@ -0,0 +1,51 @@
+/*
+ * 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;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.extended.*;
+
+/**
+ * The {@code PhiNode} represents the merging of dataflow in the memory graph.
+ */
+public class MemoryPhiNode extends PhiNode implements MemoryNode {
+
+    private final LocationIdentity identity;
+
+    public MemoryPhiNode(MergeNode merge, LocationIdentity identity) {
+        super(PhiType.Memory, merge);
+        this.identity = identity;
+    }
+
+    public LocationIdentity getLocationIdentity() {
+        return identity;
+    }
+
+    public MemoryCheckpoint asMemoryCheckpoint() {
+        return null;
+    }
+
+    public MemoryPhiNode asMemoryPhi() {
+        return this;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryProxyNode.java	Mon Dec 02 12:45:18 2013 +0100
@@ -0,0 +1,69 @@
+/*
+ * 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.graal.nodes;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.PhiNode.PhiType;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.spi.*;
+
+public class MemoryProxyNode extends ProxyNode implements MemoryProxy, LIRLowerable {
+
+    private final LocationIdentity identity;
+
+    public MemoryProxyNode(ValueNode value, AbstractBeginNode exit, LocationIdentity identity) {
+        super(value, exit, PhiType.Memory);
+        assert value instanceof MemoryNode;
+        this.identity = identity;
+    }
+
+    public LocationIdentity getLocationIdentity() {
+        return identity;
+    }
+
+    @Override
+    public void generate(LIRGeneratorTool generator) {
+    }
+
+    @Override
+    public boolean verify() {
+        assert value() instanceof MemoryNode;
+        return super.verify();
+    }
+
+    public static MemoryProxyNode forMemory(MemoryNode value, AbstractBeginNode exit, LocationIdentity location, StructuredGraph graph) {
+        return graph.unique(new MemoryProxyNode(ValueNodeUtil.asNode(value), exit, location));
+    }
+
+    public MemoryNode getOriginalMemoryNode() {
+        return (MemoryNode) value();
+    }
+
+    public MemoryCheckpoint asMemoryCheckpoint() {
+        return getOriginalMemoryNode().asMemoryCheckpoint();
+    }
+
+    public MemoryPhiNode asMemoryPhi() {
+        return getOriginalMemoryNode().asMemoryPhi();
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java	Mon Dec 02 12:45:18 2013 +0100
@@ -51,7 +51,6 @@
     @Input(notDataflow = true) private MergeNode merge;
     @Input private final NodeInputList<ValueNode> values = new NodeInputList<>(this);
     private final PhiType type;
-    private final LocationIdentity identity;
 
     /**
      * Create a value phi ({@link PhiType#Value}) with the specified kind.
@@ -68,7 +67,6 @@
         assert stamp != StampFactory.forVoid();
         this.type = PhiType.Value;
         this.merge = merge;
-        this.identity = null;
     }
 
     /**
@@ -77,12 +75,11 @@
      * @param type the type of the new phi
      * @param merge the merge that the new phi belongs to
      */
-    public PhiNode(PhiType type, MergeNode merge, LocationIdentity identity) {
+    public PhiNode(PhiType type, MergeNode merge) {
         super(type.stamp);
         assert type.stamp != null : merge + " " + type;
         this.type = type;
         this.merge = merge;
-        this.identity = identity;
     }
 
     public PhiType type() {
@@ -93,11 +90,6 @@
         return merge;
     }
 
-    public LocationIdentity getIdentity() {
-        assert type != PhiType.Value;
-        return identity;
-    }
-
     public void setMerge(MergeNode x) {
         updateUsages(merge, x);
         merge = x;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java	Mon Dec 02 12:45:18 2013 +0100
@@ -77,7 +77,7 @@
     @Override
     public void virtualize(VirtualizerTool tool) {
         State state = tool.getObjectState(object);
-        if (state != null && state.getState() == EscapeState.Virtual && ObjectStamp.typeOrNull(this).isAssignableFrom(state.getVirtualObject().type())) {
+        if (state != null && state.getState() == EscapeState.Virtual && ObjectStamp.typeOrNull(this) != null && ObjectStamp.typeOrNull(this).isAssignableFrom(state.getVirtualObject().type())) {
             tool.replaceWithVirtual(state.getVirtualObject());
         }
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ProxyNode.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ProxyNode.java	Mon Dec 02 12:45:18 2013 +0100
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.nodes;
 
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Node.ValueNumberable;
 import com.oracle.graal.graph.spi.*;
@@ -37,17 +36,15 @@
  * loop.
  */
 @NodeInfo(nameTemplate = "{p#type/s}Proxy")
-public class ProxyNode extends FloatingNode implements IterableNodeType, ValueNumberable, Canonicalizable, Virtualizable, LIRLowerable, ValueProxy, GuardingNode {
+public class ProxyNode extends FloatingNode implements IterableNodeType, ValueNumberable, Canonicalizable, Virtualizable, ValueProxy, GuardingNode {
 
     @Input(notDataflow = true) private AbstractBeginNode proxyPoint;
     @Input private ValueNode value;
     private final PhiType type;
-    private final LocationIdentity identity;
 
-    public ProxyNode(ValueNode value, AbstractBeginNode exit, PhiType type, LocationIdentity identity) {
+    public ProxyNode(ValueNode value, AbstractBeginNode exit, PhiType type) {
         super(type == PhiType.Value ? value.stamp() : type.stamp);
         this.type = type;
-        this.identity = identity;
         assert exit != null;
         this.proxyPoint = exit;
         this.value = value;
@@ -70,11 +67,6 @@
         return type;
     }
 
-    public LocationIdentity getIdentity() {
-        assert type != PhiType.Value;
-        return identity;
-    }
-
     @Override
     public boolean verify() {
         assert value != null;
@@ -84,11 +76,6 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool generator) {
-        assert type == PhiType.Memory;
-    }
-
-    @Override
     public Node canonical(CanonicalizerTool tool) {
         if (type == PhiType.Value && value.isConstant()) {
             return value;
@@ -107,15 +94,11 @@
     }
 
     public static ProxyNode forGuard(ValueNode value, AbstractBeginNode exit, StructuredGraph graph) {
-        return graph.unique(new ProxyNode(value, exit, PhiType.Guard, null));
+        return graph.unique(new ProxyNode(value, exit, PhiType.Guard));
     }
 
     public static ProxyNode forValue(ValueNode value, AbstractBeginNode exit, StructuredGraph graph) {
-        return graph.unique(new ProxyNode(value, exit, PhiType.Value, null));
-    }
-
-    public static ProxyNode forMemory(ValueNode value, AbstractBeginNode exit, LocationIdentity location, StructuredGraph graph) {
-        return graph.unique(new ProxyNode(value, exit, PhiType.Memory, location));
+        return graph.unique(new ProxyNode(value, exit, PhiType.Value));
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StartNode.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StartNode.java	Mon Dec 02 12:45:18 2013 +0100
@@ -34,4 +34,12 @@
     public LocationIdentity getLocationIdentity() {
         return LocationIdentity.ANY_LOCATION;
     }
+
+    public MemoryCheckpoint asMemoryCheckpoint() {
+        return this;
+    }
+
+    public MemoryPhiNode asMemoryPhi() {
+        return null;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Mon Dec 02 12:45:18 2013 +0100
@@ -29,6 +29,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
 
 /**
@@ -81,6 +82,38 @@
     private boolean isAfterFloatingReadPhase = false;
 
     /**
+     * Used to create canonical {@link ConstantNode}s for {@link Constant}s in this graph.
+     */
+    private Map<Constant, ConstantNode> constants;
+
+    /**
+     * Gets a node for a given constant that is unique/canonical within this graph.
+     * 
+     * @param stamp the stamp for an {@link Kind#Object} constant (ignored otherwise)
+     */
+    public ConstantNode asConstantNode(Constant constant, Stamp stamp) {
+        ConstantNode node;
+        if (constants == null) {
+            constants = new HashMap<>();
+            node = null;
+        } else {
+            node = constants.get(constant);
+        }
+        if (node == null) {
+            node = new ConstantNode(constant, stamp == null ? StampFactory.forConstant(constant) : stamp);
+            constants.put(constant, node);
+        }
+        return node;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <T extends Node> T uniqueExternal(T node) {
+        ConstantNode cn = (ConstantNode) node;
+        return (T) asConstantNode(cn.asConstant(), cn.stamp());
+    }
+
+    /**
      * Creates a new Graph containing a single {@link AbstractBeginNode} as the {@link #start()
      * start} node.
      */
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/UnwindNode.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/UnwindNode.java	Mon Dec 02 12:45:18 2013 +0100
@@ -29,7 +29,7 @@
 /**
  * Unwinds the current frame to an exception handler in the caller frame.
  */
-public final class UnwindNode extends ControlSinkNode implements LIRLowerable {
+public final class UnwindNode extends ControlSinkNode implements Lowerable, LIRLowerable {
 
     @Input private ValueNode exception;
 
@@ -44,6 +44,11 @@
     }
 
     @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    @Override
     public void generate(LIRGeneratorTool gen) {
         gen.emitUnwind(gen.operand(exception()));
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNodeUtil.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNodeUtil.java	Mon Dec 02 12:45:18 2013 +0100
@@ -27,6 +27,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Node.Verbosity;
+import com.oracle.graal.nodes.extended.*;
 
 public class ValueNodeUtil {
 
@@ -95,4 +96,12 @@
     public static String valueString(ValueNode value) {
         return (value == null) ? "-" : ("" + value.kind().getTypeChar() + value.toString(Verbosity.Id));
     }
+
+    public static ValueNode asNode(MemoryNode node) {
+        if (node == null) {
+            return null;
+        } else {
+            return node.asNode();
+        }
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java	Mon Dec 02 12:45:18 2013 +0100
@@ -136,7 +136,7 @@
         if (x() instanceof ConvertNode && y() instanceof ConvertNode) {
             ConvertNode convertX = (ConvertNode) x();
             ConvertNode convertY = (ConvertNode) y();
-            if (convertX.isLossless() && convertY.isLossless()) {
+            if (convertX.isLossless() && convertY.isLossless() && convertX.getFromKind() == convertY.getFromKind()) {
                 setX(convertX.value());
                 setY(convertY.value());
             }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ArrayRangeWriteNode.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ArrayRangeWriteNode.java	Mon Dec 02 12:45:18 2013 +0100
@@ -28,7 +28,7 @@
 /**
  * Base class for nodes that modify a range of an array.
  */
-public abstract class ArrayRangeWriteNode extends AbstractStateSplit {
+public abstract class ArrayRangeWriteNode extends AbstractMemoryCheckpoint {
 
     protected ArrayRangeWriteNode(Stamp stamp) {
         super(stamp);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatableAccessNode.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatableAccessNode.java	Mon Dec 02 12:45:18 2013 +0100
@@ -43,7 +43,7 @@
         super(object, location, stamp, barrierType, compressible);
     }
 
-    public abstract FloatingAccessNode asFloatingNode(ValueNode lastLocationAccess);
+    public abstract FloatingAccessNode asFloatingNode(MemoryNode lastLocationAccess);
 
     /**
      * AccessNodes can float only if their location identities are not ANY_LOCATION. Furthermore, in
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java	Mon Dec 02 12:45:18 2013 +0100
@@ -26,7 +26,6 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.PhiNode.PhiType;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -36,27 +35,27 @@
  */
 public final class FloatingReadNode extends FloatingAccessNode implements IterableNodeType, LIRLowerable, Canonicalizable {
 
-    @Input private Node lastLocationAccess;
+    @Input private MemoryNode lastLocationAccess;
 
-    public FloatingReadNode(ValueNode object, LocationNode location, Node lastLocationAccess, Stamp stamp) {
+    public FloatingReadNode(ValueNode object, LocationNode location, MemoryNode lastLocationAccess, Stamp stamp) {
         this(object, location, lastLocationAccess, stamp, null, BarrierType.NONE, false);
     }
 
-    public FloatingReadNode(ValueNode object, LocationNode location, Node lastLocationAccess, Stamp stamp, GuardingNode guard) {
+    public FloatingReadNode(ValueNode object, LocationNode location, MemoryNode lastLocationAccess, Stamp stamp, GuardingNode guard) {
         this(object, location, lastLocationAccess, stamp, guard, BarrierType.NONE, false);
     }
 
-    public FloatingReadNode(ValueNode object, LocationNode location, Node lastLocationAccess, Stamp stamp, GuardingNode guard, BarrierType barrierType, boolean compressible) {
+    public FloatingReadNode(ValueNode object, LocationNode location, MemoryNode lastLocationAccess, Stamp stamp, GuardingNode guard, BarrierType barrierType, boolean compressible) {
         super(object, location, stamp, guard, barrierType, compressible);
         this.lastLocationAccess = lastLocationAccess;
     }
 
-    public Node getLastLocationAccess() {
+    public MemoryNode getLastLocationAccess() {
         return lastLocationAccess;
     }
 
-    public void setLastLocationAccess(Node newlla) {
-        updateUsages(lastLocationAccess, newlla);
+    public void setLastLocationAccess(MemoryNode newlla) {
+        updateUsages(ValueNodeUtil.asNode(lastLocationAccess), ValueNodeUtil.asNode(newlla));
         lastLocationAccess = newlla;
     }
 
@@ -76,22 +75,10 @@
         return graph().add(new ReadNode(object(), nullCheckLocation(), stamp(), getGuard(), getBarrierType(), isCompressible()));
     }
 
-    private static boolean isMemoryCheckPoint(Node n) {
-        return n instanceof MemoryCheckpoint.Single || n instanceof MemoryCheckpoint.Multi;
-    }
-
-    private static boolean isMemoryPhi(Node n) {
-        return n instanceof PhiNode && ((PhiNode) n).type() == PhiType.Memory;
-    }
-
-    private static boolean isMemoryProxy(Node n) {
-        return n instanceof ProxyNode && ((ProxyNode) n).type() == PhiType.Memory;
-    }
-
     @Override
     public boolean verify() {
-        Node lla = getLastLocationAccess();
-        assert lla == null || isMemoryCheckPoint(lla) || isMemoryPhi(lla) || isMemoryProxy(lla) : "lastLocationAccess of " + this + " should be a MemoryCheckpoint, but is " + lla;
+        MemoryNode lla = getLastLocationAccess();
+        assert lla == null || lla.asMemoryCheckpoint() != null || lla.asMemoryPhi() != null : "lastLocationAccess of " + this + " should be a MemoryCheckpoint, but is " + lla;
         return super.verify();
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java	Mon Dec 02 12:45:18 2013 +0100
@@ -33,7 +33,7 @@
  * Node for a {@linkplain ForeignCallDescriptor foreign} call.
  */
 @NodeInfo(nameTemplate = "ForeignCall#{p#descriptor/s}")
-public class ForeignCallNode extends AbstractStateSplit implements LIRLowerable, DeoptimizingNode, MemoryCheckpoint.Multi {
+public class ForeignCallNode extends AbstractMemoryCheckpoint implements LIRLowerable, DeoptimizingNode, MemoryCheckpoint.Multi {
 
     @Input private final NodeInputList<ValueNode> arguments;
     private final ForeignCallsProvider foreignCalls;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java	Mon Dec 02 12:45:18 2013 +0100
@@ -61,7 +61,7 @@
 
     @Override
     public void lower(LoweringTool tool) {
-        if (graph().getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
+        if (graph().getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS || graph().getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
             tool.getLowerer().lower(this, tool);
         }
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MembarNode.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MembarNode.java	Mon Dec 02 12:45:18 2013 +0100
@@ -60,6 +60,14 @@
         generator.emitMembar(barriers);
     }
 
+    public MemoryCheckpoint asMemoryCheckpoint() {
+        return this;
+    }
+
+    public MemoryPhiNode asMemoryPhi() {
+        return null;
+    }
+
     @SuppressWarnings("unused")
     @NodeIntrinsic
     public static void memoryBarrier(@ConstantNodeParameter int barriers) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryAccess.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryAccess.java	Mon Dec 02 12:45:18 2013 +0100
@@ -23,7 +23,6 @@
 package com.oracle.graal.nodes.extended;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
 
 /**
  * This interface marks nodes that access some memory location, and that have an edge to the last
@@ -33,7 +32,7 @@
 
     LocationIdentity getLocationIdentity();
 
-    Node getLastLocationAccess();
+    MemoryNode getLastLocationAccess();
 
-    void setLastLocationAccess(Node lla);
+    void setLastLocationAccess(MemoryNode lla);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryCheckpoint.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryCheckpoint.java	Mon Dec 02 12:45:18 2013 +0100
@@ -31,7 +31,9 @@
  * represented by location identities (i.e. change a value at one or more locations that belong to
  * these location identities).
  */
-public interface MemoryCheckpoint {
+public interface MemoryCheckpoint extends MemoryNode {
+
+    FixedNode asNode();
 
     interface Single extends MemoryCheckpoint {
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryNode.java	Mon Dec 02 12:45:18 2013 +0100
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes.extended;
+
+import com.oracle.graal.nodes.*;
+
+/**
+ * This interface marks nodes that are part of the memory graph.
+ */
+public interface MemoryNode {
+
+    ValueNode asNode();
+
+    MemoryCheckpoint asMemoryCheckpoint();
+
+    MemoryPhiNode asMemoryPhi();
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java	Mon Dec 02 12:45:18 2013 +0100
@@ -43,6 +43,15 @@
         super(object, location, stamp, guard, barrierType, compressible);
     }
 
+    private ReadNode(ValueNode object, ValueNode location, ValueNode guard, BarrierType barrierType, boolean compressible) {
+        /*
+         * Used by node intrinsics. Really, you can trust me on that! Since the initial value for
+         * location is a parameter, i.e., a LocalNode, the constructor cannot use the declared type
+         * LocationNode.
+         */
+        super(object, location, StampFactory.forNodeIntrinsic(), (GuardingNode) guard, barrierType, compressible);
+    }
+
     @Override
     public void generate(LIRGeneratorTool gen) {
         Value address = location().generateAddress(gen, gen.operand(object()));
@@ -55,7 +64,7 @@
     }
 
     @Override
-    public FloatingAccessNode asFloatingNode(ValueNode lastLocationAccess) {
+    public FloatingAccessNode asFloatingNode(MemoryNode lastLocationAccess) {
         return graph().unique(new FloatingReadNode(object(), location(), lastLocationAccess, stamp(), getGuard(), getBarrierType(), isCompressible()));
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java	Mon Dec 02 12:45:18 2013 +0100
@@ -34,7 +34,11 @@
  * allows unsafe casts "sideways" in the type hierarchy. It does not allow to "drop" type
  * information, i.e., an unsafe cast is removed if the input object has a more precise or equal type
  * than the type this nodes casts to.
+ * 
+ * @deprecated use {@link PiNode}.
  */
+
+@Deprecated
 public class UnsafeCastNode extends FloatingGuardedNode implements LIRLowerable, Virtualizable, GuardingNode, IterableNodeType, Canonicalizable, ValueProxy {
 
     @Input private ValueNode object;
@@ -88,7 +92,7 @@
     @Override
     public void virtualize(VirtualizerTool tool) {
         State state = tool.getObjectState(object);
-        if (state != null && state.getState() == EscapeState.Virtual && ObjectStamp.typeOrNull(this).isAssignableFrom(state.getVirtualObject().type())) {
+        if (state != null && state.getState() == EscapeState.Virtual && ObjectStamp.typeOrNull(this) != null && ObjectStamp.typeOrNull(this).isAssignableFrom(state.getVirtualObject().type())) {
             tool.replaceWithVirtual(state.getVirtualObject());
         }
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java	Mon Dec 02 12:45:18 2013 +0100
@@ -111,6 +111,14 @@
         return stateAfter;
     }
 
+    public MemoryCheckpoint asMemoryCheckpoint() {
+        return this;
+    }
+
+    public MemoryPhiNode asMemoryPhi() {
+        return null;
+    }
+
     // specialized on value type until boxing/unboxing is sorted out in intrinsification
 
     @SuppressWarnings("unused")
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java	Mon Dec 02 12:45:18 2013 +0100
@@ -45,6 +45,16 @@
         return stateAfter;
     }
 
+    @Override
+    public FrameState getState() {
+        if (stateAfter != null) {
+            assert super.getState() == null;
+            return stateAfter;
+        } else {
+            return super.getState();
+        }
+    }
+
     public void setStateAfter(FrameState x) {
         assert x == null || x.isAlive() : "frame state must be in a graph";
         updateUsages(stateAfter, x);
@@ -92,13 +102,14 @@
         return location().getLocationIdentity();
     }
 
-    public Node getLastLocationAccess() {
-        return lastLocationAccess;
+    public MemoryNode getLastLocationAccess() {
+        return (MemoryNode) lastLocationAccess;
     }
 
-    public void setLastLocationAccess(Node lla) {
-        updateUsages(lastLocationAccess, lla);
-        lastLocationAccess = lla;
+    public void setLastLocationAccess(MemoryNode lla) {
+        Node newLla = ValueNodeUtil.asNode(lla);
+        updateUsages(lastLocationAccess, newLla);
+        lastLocationAccess = newLla;
     }
 
     @Override
@@ -116,4 +127,12 @@
             }
         }
     }
+
+    public MemoryCheckpoint asMemoryCheckpoint() {
+        return this;
+    }
+
+    public MemoryPhiNode asMemoryPhi() {
+        return null;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java	Mon Dec 02 12:45:18 2013 +0100
@@ -33,7 +33,7 @@
  * The Java bytecode specification allows non-balanced locking. Graal does not handle such cases and
  * throws a {@link BailoutException} instead during graph building.
  */
-public abstract class AccessMonitorNode extends AbstractStateSplit implements MemoryCheckpoint {
+public abstract class AccessMonitorNode extends AbstractMemoryCheckpoint implements MemoryCheckpoint {
 
     @Input private ValueNode object;
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java	Mon Dec 02 12:45:18 2013 +0100
@@ -34,7 +34,7 @@
  * Represents an atomic compare-and-swap operation The result is a boolean that contains whether the
  * value matched the expected value.
  */
-public class CompareAndSwapNode extends AbstractStateSplit implements Lowerable, MemoryCheckpoint.Single {
+public class CompareAndSwapNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single {
 
     @Input private ValueNode object;
     @Input private ValueNode offset;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java	Mon Dec 02 12:45:18 2013 +0100
@@ -101,4 +101,12 @@
         assertTrue(stateAfter() != null || stamp() == StampFactory.forVoid(), "an exception handler needs a frame state");
         return super.verify();
     }
+
+    public MemoryCheckpoint asMemoryCheckpoint() {
+        return this;
+    }
+
+    public MemoryPhiNode asMemoryPhi() {
+        return null;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoweredCompareAndSwapNode.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoweredCompareAndSwapNode.java	Mon Dec 02 12:45:18 2013 +0100
@@ -75,4 +75,12 @@
     public void generate(LIRGeneratorTool gen) {
         gen.visitCompareAndSwap(this, location().generateAddress(gen, gen.operand(object())));
     }
+
+    public MemoryCheckpoint asMemoryCheckpoint() {
+        return this;
+    }
+
+    public MemoryPhiNode asMemoryPhi() {
+        return null;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java	Mon Dec 02 12:45:18 2013 +0100
@@ -34,8 +34,6 @@
  */
 public class NewArrayNode extends AbstractNewArrayNode implements VirtualizableAllocation {
 
-    private final ResolvedJavaType elementType;
-
     /**
      * Constructs a new NewArrayNode.
      * 
@@ -46,7 +44,6 @@
      */
     public NewArrayNode(ResolvedJavaType elementType, ValueNode length, boolean fillContents) {
         super(StampFactory.exactNonNull(elementType.getArrayClass()), length, fillContents);
-        this.elementType = elementType;
     }
 
     /**
@@ -55,7 +52,7 @@
      * @return the element type of the array
      */
     public ResolvedJavaType elementType() {
-        return elementType;
+        return ObjectStamp.typeOrNull(this).getComponentType();
     }
 
     @Override
@@ -64,14 +61,19 @@
             final int constantLength = length().asConstant().asInt();
             if (constantLength >= 0 && constantLength < tool.getMaximumEntryCount()) {
                 ValueNode[] state = new ValueNode[constantLength];
-                ConstantNode defaultForKind = constantLength == 0 ? null : ConstantNode.defaultForKind(elementType().getKind(), graph());
+                ConstantNode defaultForKind = constantLength == 0 ? null : defaultElementValue();
                 for (int i = 0; i < constantLength; i++) {
                     state[i] = defaultForKind;
                 }
-                VirtualObjectNode virtualObject = new VirtualArrayNode(elementType, constantLength);
+                VirtualObjectNode virtualObject = new VirtualArrayNode(elementType(), constantLength);
                 tool.createVirtualObject(virtualObject, state, null);
                 tool.replaceWithVirtual(virtualObject);
             }
         }
     }
+
+    /* Factored out in a separate method so that subclasses can override it. */
+    protected ConstantNode defaultElementValue() {
+        return ConstantNode.defaultForKind(elementType().getKind(), graph());
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java	Mon Dec 02 12:45:18 2013 +0100
@@ -36,7 +36,7 @@
  * The {@code NewInstanceNode} represents the allocation of an instance class object.
  */
 @NodeInfo(nameTemplate = "New {p#instanceClass/s}")
-public final class NewInstanceNode extends DeoptimizingFixedWithNextNode implements Canonicalizable, Lowerable, VirtualizableAllocation {
+public class NewInstanceNode extends DeoptimizingFixedWithNextNode implements Canonicalizable, Lowerable, VirtualizableAllocation {
 
     private final ResolvedJavaType instanceClass;
     private final boolean fillContents;
@@ -96,13 +96,18 @@
             ResolvedJavaField[] fields = virtualObject.getFields();
             ValueNode[] state = new ValueNode[fields.length];
             for (int i = 0; i < state.length; i++) {
-                state[i] = ConstantNode.defaultForKind(fields[i].getType().getKind(), graph());
+                state[i] = defaultFieldValue(fields[i]);
             }
             tool.createVirtualObject(virtualObject, state, null);
             tool.replaceWithVirtual(virtualObject);
         }
     }
 
+    /* Factored out in a separate method so that subclasses can override it. */
+    protected ConstantNode defaultFieldValue(ResolvedJavaField field) {
+        return ConstantNode.defaultForKind(field.getType().getKind(), graph());
+    }
+
     @Override
     public boolean canDeoptimize() {
         return true;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LoweringTool.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LoweringTool.java	Mon Dec 02 12:45:18 2013 +0100
@@ -33,14 +33,10 @@
 
     MetaAccessProvider getMetaAccess();
 
-    CodeCacheProvider getCodeCache();
-
     LoweringProvider getLowerer();
 
     ConstantReflectionProvider getConstantReflection();
 
-    ForeignCallsProvider getForeignCalls();
-
     Replacements getReplacements();
 
     GuardingNode createNullCheckGuard(GuardedNode guardedNode, ValueNode object);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MemoryProxy.java	Mon Dec 02 12:45:18 2013 +0100
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes.spi;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.extended.*;
+
+public interface MemoryProxy extends ValueProxy, MemoryNode {
+
+    LocationIdentity getLocationIdentity();
+
+    MemoryNode getOriginalMemoryNode();
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java	Mon Dec 02 12:45:18 2013 +0100
@@ -42,6 +42,19 @@
     StructuredGraph getSnippet(ResolvedJavaMethod method);
 
     /**
+     * Registers a method as snippet.
+     */
+    void registerSnippet(ResolvedJavaMethod method);
+
+    /**
+     * Prepares the copy of a snippet graph immediately after instantiation. This can be used to do
+     * node intrinsification for example.
+     * 
+     * @param snippetCopy The copy of the snippet graph.
+     */
+    void prepareSnippetCopyAfterInstantiation(StructuredGraph snippetCopy);
+
+    /**
      * Gets the graph that is a substitution for a given method.
      * 
      * @return the graph, if any, that is a substitution for {@code method}
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Mon Dec 02 12:45:18 2013 +0100
@@ -22,11 +22,10 @@
  */
 package com.oracle.graal.phases.common;
 
-import java.util.concurrent.*;
-
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Graph.Mark;
 import com.oracle.graal.graph.Graph.NodeChangedListener;
@@ -243,22 +242,20 @@
             if (nodeClass.isCanonicalizable()) {
                 assert !nodeClass.isSimplifiable();
                 METRIC_CANONICALIZATION_CONSIDERED_NODES.increment();
-                return Debug.scope("CanonicalizeNode", node, new Callable<Boolean>() {
-
-                    public Boolean call() {
-                        Node canonical = node.canonical(tool);
-                        return performReplacement(node, canonical);
-                    }
-                });
+                try (Scope s = Debug.scope("CanonicalizeNode", node)) {
+                    Node canonical = node.canonical(tool);
+                    return performReplacement(node, canonical);
+                } catch (Throwable e) {
+                    throw Debug.handle(e);
+                }
             } else if (nodeClass.isSimplifiable()) {
                 Debug.log("Canonicalizer: simplifying %s", node);
                 METRIC_SIMPLIFICATION_CONSIDERED_NODES.increment();
-                Debug.scope("SimplifyNode", node, new Runnable() {
-
-                    public void run() {
-                        node.simplify(tool);
-                    }
-                });
+                try (Scope s = Debug.scope("SimplifyNode", node)) {
+                    node.simplify(tool);
+                } catch (Throwable e) {
+                    throw Debug.handle(e);
+                }
             }
             return node.isDeleted();
         }
@@ -302,9 +299,8 @@
                     FixedNode fixed = (FixedNode) node;
                     if (canonical instanceof ControlSinkNode) {
                         // case 7
-                        FixedWithNextNode pred = (FixedWithNextNode) node.predecessor();
+                        fixed.predecessor().replaceFirstSuccessor(fixed, canonical);
                         GraphUtil.killCFG(fixed);
-                        pred.setNext((FixedNode) canonical);
                         return true;
                     } else {
                         assert fixed instanceof FixedWithNextNode;
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java	Mon Dec 02 12:45:18 2013 +0100
@@ -28,7 +28,6 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.PhiNode.PhiType;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.graph.*;
@@ -43,7 +42,7 @@
 
     public static class MemoryMapImpl extends MemoryMapNode {
 
-        private IdentityHashMap<LocationIdentity, ValueNode> lastMemorySnapshot;
+        private IdentityHashMap<LocationIdentity, MemoryNode> lastMemorySnapshot;
 
         public MemoryMapImpl(MemoryMapImpl memoryMap) {
             lastMemorySnapshot = new IdentityHashMap<>(memoryMap.lastMemorySnapshot);
@@ -59,8 +58,8 @@
         }
 
         @Override
-        public ValueNode getLastLocationAccess(LocationIdentity locationIdentity) {
-            ValueNode lastLocationAccess;
+        public MemoryNode getLastLocationAccess(LocationIdentity locationIdentity) {
+            MemoryNode lastLocationAccess;
             if (locationIdentity == FINAL_LOCATION) {
                 return null;
             } else {
@@ -198,7 +197,7 @@
         private static void processAccess(MemoryAccess access, MemoryMapImpl state) {
             LocationIdentity locationIdentity = access.getLocationIdentity();
             if (locationIdentity != LocationIdentity.ANY_LOCATION) {
-                ValueNode lastLocationAccess = state.getLastLocationAccess(locationIdentity);
+                MemoryNode lastLocationAccess = state.getLastLocationAccess(locationIdentity);
                 access.setLastLocationAccess(lastLocationAccess);
             }
         }
@@ -217,7 +216,7 @@
             if (identity == ANY_LOCATION) {
                 state.lastMemorySnapshot.clear();
             }
-            state.lastMemorySnapshot.put(identity, (ValueNode) checkpoint);
+            state.lastMemorySnapshot.put(identity, checkpoint);
         }
 
         private static void processFloatable(FloatableAccessNode accessNode, MemoryMapImpl state) {
@@ -225,7 +224,7 @@
             assert accessNode.getNullCheck() == false;
             LocationIdentity locationIdentity = accessNode.location().getLocationIdentity();
             if (accessNode.canFloat()) {
-                ValueNode lastLocationAccess = state.getLastLocationAccess(locationIdentity);
+                MemoryNode lastLocationAccess = state.getLastLocationAccess(locationIdentity);
                 FloatingAccessNode floatingNode = accessNode.asFloatingNode(lastLocationAccess);
                 floatingNode.setNullCheck(accessNode.getNullCheck());
                 ValueAnchorNode anchor = null;
@@ -251,22 +250,22 @@
             for (LocationIdentity key : keys) {
                 int mergedStatesCount = 0;
                 boolean isPhi = false;
-                ValueNode merged = null;
+                MemoryNode merged = null;
                 for (MemoryMapImpl state : states) {
-                    ValueNode last = state.getLastLocationAccess(key);
+                    MemoryNode last = state.getLastLocationAccess(key);
                     if (isPhi) {
-                        ((PhiNode) merged).addInput(last);
+                        merged.asMemoryPhi().addInput(ValueNodeUtil.asNode(last));
                     } else {
                         if (merged == last) {
                             // nothing to do
                         } else if (merged == null) {
                             merged = last;
                         } else {
-                            PhiNode phi = merge.graph().addWithoutUnique(new PhiNode(PhiType.Memory, merge, key));
+                            MemoryPhiNode phi = merge.graph().addWithoutUnique(new MemoryPhiNode(merge, key));
                             for (int j = 0; j < mergedStatesCount; j++) {
-                                phi.addInput(merged);
+                                phi.addInput(ValueNodeUtil.asNode(merged));
                             }
-                            phi.addInput(last);
+                            phi.addInput(ValueNodeUtil.asNode(last));
                             merged = phi;
                             isPhi = true;
                         }
@@ -290,7 +289,7 @@
                  * side it needs to choose by putting in the location identity on both successors.
                  */
                 InvokeWithExceptionNode invoke = (InvokeWithExceptionNode) node.predecessor();
-                result.lastMemorySnapshot.put(invoke.getLocationIdentity(), node);
+                result.lastMemorySnapshot.put(invoke.getLocationIdentity(), (MemoryCheckpoint) node);
             }
             return result;
         }
@@ -306,8 +305,8 @@
 
             Map<LocationIdentity, PhiNode> phis = new HashMap<>();
             for (LocationIdentity location : modifiedLocations) {
-                PhiNode phi = loop.graph().addWithoutUnique(new PhiNode(PhiType.Memory, loop, location));
-                phi.addInput(initialState.getLastLocationAccess(location));
+                MemoryPhiNode phi = loop.graph().addWithoutUnique(new MemoryPhiNode(loop, location));
+                phi.addInput(ValueNodeUtil.asNode(initialState.getLastLocationAccess(location)));
                 phis.put(location, phi);
                 initialState.lastMemorySnapshot.put(location, phi);
             }
@@ -319,16 +318,16 @@
                 for (Map.Entry<LocationIdentity, PhiNode> phiEntry : phis.entrySet()) {
                     LocationIdentity key = phiEntry.getKey();
                     PhiNode phi = phiEntry.getValue();
-                    phi.initializeValueAt(endIndex, entry.getValue().getLastLocationAccess(key));
+                    phi.initializeValueAt(endIndex, ValueNodeUtil.asNode(entry.getValue().getLastLocationAccess(key)));
                 }
             }
             for (Map.Entry<LoopExitNode, MemoryMapImpl> entry : loopInfo.exitStates.entrySet()) {
                 LoopExitNode exit = entry.getKey();
                 MemoryMapImpl state = entry.getValue();
                 for (LocationIdentity location : modifiedLocations) {
-                    ValueNode lastAccessAtExit = state.lastMemorySnapshot.get(location);
+                    MemoryNode lastAccessAtExit = state.lastMemorySnapshot.get(location);
                     if (lastAccessAtExit != null) {
-                        state.lastMemorySnapshot.put(location, ProxyNode.forMemory(lastAccessAtExit, exit, location, loop.graph()));
+                        state.lastMemorySnapshot.put(location, MemoryProxyNode.forMemory(lastAccessAtExit, exit, location, loop.graph()));
                     }
                 }
             }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java	Mon Dec 02 12:45:18 2013 +0100
@@ -142,8 +142,9 @@
         protected void processNode(Node node) {
             if (node instanceof GuardNode) {
                 GuardNode guard = (GuardNode) node;
-                if (guard.negated() && guard.condition() instanceof IsNullNode) {
-                    lowerToNullCheck(guard);
+                FixedWithNextNode lowered = guard.lowerGuard();
+                if (lowered != null) {
+                    replaceCurrent(lowered);
                 } else {
                     lowerToIf(guard);
                 }
@@ -171,15 +172,6 @@
             insert(ifNode, fastPath);
         }
 
-        private void lowerToNullCheck(GuardNode guard) {
-            IsNullNode isNull = (IsNullNode) guard.condition();
-            NullCheckNode nullCheck = guard.graph().add(new NullCheckNode(isNull.object()));
-            replaceCurrent(nullCheck);
-            if (isNull.usages().isEmpty()) {
-                isNull.safeDelete();
-            }
-        }
-
         private void insertLoopExits(DeoptimizeNode deopt) {
             Loop loop = block.getLoop();
             StructuredGraph graph = deopt.graph();
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java	Mon Dec 02 12:45:18 2013 +0100
@@ -26,11 +26,11 @@
 import static com.oracle.graal.phases.common.InliningPhase.Options.*;
 
 import java.util.*;
-import java.util.concurrent.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Graph.Mark;
 import com.oracle.graal.nodes.*;
@@ -47,6 +47,7 @@
 import com.oracle.graal.phases.common.InliningUtil.InliningPolicy;
 import com.oracle.graal.phases.graph.*;
 import com.oracle.graal.phases.tiers.*;
+import com.oracle.graal.phases.util.*;
 
 public class InliningPhase extends AbstractInliningPhase {
 
@@ -123,14 +124,11 @@
                     if (currentInvocation.processedGraphs() == currentInvocation.totalGraphs()) {
                         data.popInvocation();
                         final MethodInvocation parentInvoke = data.currentInvocation();
-                        Debug.scope("Inlining", data.inliningContext(), new Runnable() {
-
-                            @Override
-                            public void run() {
-                                tryToInline(data.currentGraph(), currentInvocation, parentInvoke, data.inliningDepth() + 1, context);
-                            }
-                        });
-
+                        try (Scope s = Debug.scope("Inlining", data.inliningContext())) {
+                            tryToInline(data.currentGraph(), currentInvocation, parentInvoke, data.inliningDepth() + 1, context);
+                        } catch (Throwable e) {
+                            throw Debug.handle(e);
+                        }
                     }
                 }
             }
@@ -185,7 +183,7 @@
         InlineInfo callee = calleeInfo.callee();
         try {
             List<Node> invokeUsages = callee.invoke().asNode().usages().snapshot();
-            callee.inline(context, callerAssumptions);
+            callee.inline(new Providers(context), callerAssumptions);
             callerAssumptions.record(calleeInfo.assumptions());
             metricInliningRuns.increment();
             Debug.dump(callerGraph, "after %s", callee);
@@ -245,44 +243,42 @@
             }
         }
 
-        return Debug.scope("InlineGraph", newGraph, new Callable<StructuredGraph>() {
-
-            @Override
-            public StructuredGraph call() throws Exception {
-                if (parseBytecodes) {
-                    parseBytecodes(newGraph, context);
-                }
+        try (Scope s = Debug.scope("InlineGraph", newGraph)) {
+            if (parseBytecodes) {
+                parseBytecodes(newGraph, context);
+            }
 
-                boolean callerHasMoreInformationAboutArguments = false;
-                NodeInputList<ValueNode> args = invoke.callTarget().arguments();
-                for (LocalNode localNode : newGraph.getNodes(LocalNode.class).snapshot()) {
-                    ValueNode arg = args.get(localNode.index());
-                    if (arg.isConstant()) {
-                        Constant constant = arg.asConstant();
-                        newGraph.replaceFloating(localNode, ConstantNode.forConstant(constant, context.getMetaAccess(), newGraph));
+            boolean callerHasMoreInformationAboutArguments = false;
+            NodeInputList<ValueNode> args = invoke.callTarget().arguments();
+            for (LocalNode localNode : newGraph.getNodes(LocalNode.class).snapshot()) {
+                ValueNode arg = args.get(localNode.index());
+                if (arg.isConstant()) {
+                    Constant constant = arg.asConstant();
+                    newGraph.replaceFloating(localNode, ConstantNode.forConstant(constant, context.getMetaAccess(), newGraph));
+                    callerHasMoreInformationAboutArguments = true;
+                } else {
+                    Stamp joinedStamp = localNode.stamp().join(arg.stamp());
+                    if (joinedStamp != null && !joinedStamp.equals(localNode.stamp())) {
+                        localNode.setStamp(joinedStamp);
                         callerHasMoreInformationAboutArguments = true;
-                    } else {
-                        Stamp joinedStamp = localNode.stamp().join(arg.stamp());
-                        if (joinedStamp != null && !joinedStamp.equals(localNode.stamp())) {
-                            localNode.setStamp(joinedStamp);
-                            callerHasMoreInformationAboutArguments = true;
-                        }
                     }
                 }
+            }
 
-                if (!callerHasMoreInformationAboutArguments) {
-                    // TODO (chaeubl): if args are not more concrete, inlining should be avoided
-                    // in most cases or we could at least use the previous graph size + invoke
-                    // probability to check the inlining
-                }
+            if (!callerHasMoreInformationAboutArguments) {
+                // TODO (chaeubl): if args are not more concrete, inlining should be avoided
+                // in most cases or we could at least use the previous graph size + invoke
+                // probability to check the inlining
+            }
 
-                if (OptCanonicalizer.getValue()) {
-                    canonicalizer.apply(newGraph, context);
-                }
+            if (OptCanonicalizer.getValue()) {
+                canonicalizer.apply(newGraph, context);
+            }
 
-                return newGraph;
-            }
-        });
+            return newGraph;
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
     }
 
     private static StructuredGraph getCachedGraph(ResolvedJavaMethod method, HighTierContext context) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Mon Dec 02 12:45:18 2013 +0100
@@ -26,10 +26,10 @@
 import static com.oracle.graal.api.meta.DeoptimizationReason.*;
 import static com.oracle.graal.nodes.type.StampFactory.*;
 import static com.oracle.graal.phases.GraalOptions.*;
+import static java.lang.reflect.Modifier.*;
 
 import java.lang.reflect.*;
 import java.util.*;
-import java.util.concurrent.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.code.Assumptions.Assumption;
@@ -37,6 +37,7 @@
 import com.oracle.graal.api.meta.JavaTypeProfile.ProfiledType;
 import com.oracle.graal.api.meta.ResolvedJavaType.Representation;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Graph.DuplicationReplacement;
 import com.oracle.graal.graph.Node.ValueNumberable;
@@ -172,12 +173,9 @@
     }
 
     public static void logInliningDecision(final String msg, final Object... args) {
-        Debug.scope(inliningDecisionsScopeString, new Runnable() {
-
-            public void run() {
-                Debug.log(msg, args);
-            }
-        });
+        try (Scope s = Debug.scope(inliningDecisionsScopeString)) {
+            Debug.log(msg, args);
+        }
     }
 
     private static boolean logNotInlinedMethod(Invoke invoke, String msg) {
@@ -219,12 +217,9 @@
     }
 
     public static boolean shouldLogInliningDecision() {
-        return Debug.scope(inliningDecisionsScopeString, new Callable<Boolean>() {
-
-            public Boolean call() {
-                return Debug.isLogEnabled();
-            }
-        });
+        try (Scope s = Debug.scope(inliningDecisionsScopeString)) {
+            return Debug.isLogEnabled();
+        }
     }
 
     private static String methodName(ResolvedJavaMethod method, Invoke invoke) {
@@ -434,6 +429,7 @@
             super(invoke);
             this.concrete = concrete;
             this.type = type;
+            assert type.isArray() || !isAbstract(type.getModifiers()) : type;
         }
 
         @Override
@@ -1137,6 +1133,7 @@
             }
 
             ResolvedJavaType type = ptypes[0].getType();
+            assert type.isArray() || !isAbstract(type.getModifiers());
             ResolvedJavaMethod concrete = type.resolveMethod(targetMethod);
             if (!checkTargetConditions(data, replacements, invoke, concrete, optimisticOpts)) {
                 return null;
@@ -1208,6 +1205,7 @@
                 if (index == -1) {
                     notRecordedTypeProbability += type.getProbability();
                 } else {
+                    assert type.getType().isArray() || !isAbstract(type.getType().getModifiers()) : type + " " + concrete;
                     usedTypes.add(type);
                     typesToConcretes.add(index);
                 }
@@ -1438,7 +1436,7 @@
                 if (!returnValue.isExternal()) {
                     returnValue = duplicates.get(returnValue);
                 } else if (returnValue instanceof ValueNumberable) {
-                    returnValue = graph.uniqueWithoutAdd(returnValue);
+                    returnValue = graph.uniqueExternal(returnValue);
                 }
             }
             invoke.asNode().replaceAtUsages(returnValue);
@@ -1502,12 +1500,7 @@
             InliningUtil.replaceInvokeCallTarget(invoke, graph, InvokeKind.Special, concrete);
         }
 
-        FixedWithNextNode macroNode;
-        try {
-            macroNode = macroNodeClass.getConstructor(Invoke.class).newInstance(invoke);
-        } catch (ReflectiveOperationException | IllegalArgumentException | SecurityException e) {
-            throw new GraalInternalError(e).addContext(invoke.asNode()).addContext("macroSubstitution", macroNodeClass);
-        }
+        FixedWithNextNode macroNode = createMacroNodeInstance(macroNodeClass, invoke);
 
         CallTargetNode callTarget = invoke.callTarget();
         if (invoke instanceof InvokeNode) {
@@ -1520,4 +1513,12 @@
         GraphUtil.killWithUnusedFloatingInputs(callTarget);
         return macroNode;
     }
+
+    private static FixedWithNextNode createMacroNodeInstance(Class<? extends FixedWithNextNode> macroNodeClass, Invoke invoke) throws GraalInternalError {
+        try {
+            return macroNodeClass.getConstructor(Invoke.class).newInstance(invoke);
+        } catch (ReflectiveOperationException | IllegalArgumentException | SecurityException e) {
+            throw new GraalInternalError(e).addContext(invoke.asNode()).addContext("macroSubstitution", macroNodeClass);
+        }
+    }
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java	Mon Dec 02 12:45:18 2013 +0100
@@ -64,11 +64,6 @@
         }
 
         @Override
-        public CodeCacheProvider getCodeCache() {
-            return context.getCodeCache();
-        }
-
-        @Override
         public ConstantReflectionProvider getConstantReflection() {
             return context.getConstantReflection();
         }
@@ -79,11 +74,6 @@
         }
 
         @Override
-        public ForeignCallsProvider getForeignCalls() {
-            return context.getForeignCalls();
-        }
-
-        @Override
         public LoweringProvider getLowerer() {
             return context.getLowerer();
         }
@@ -178,7 +168,7 @@
         Mark expectedMark = graph.getMark();
         lower(graph, context, 1);
         Mark mark = graph.getMark();
-        assert mark.equals(expectedMark) : graph + ": a second round in the current lowering phase introduced these new nodes: " + graph.getNewNodes(mark).snapshot();
+        assert mark.equals(expectedMark) : graph + ": a second round in the current lowering phase introduced these new nodes: " + graph.getNewNodes(expectedMark).snapshot();
         return true;
     }
 
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/OptimizeGuardAnchors.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/OptimizeGuardAnchors.java	Mon Dec 02 12:45:18 2013 +0100
@@ -72,7 +72,7 @@
             }
         }
         for (ControlSplitNode controlSplit : graph.getNodes(ControlSplitNode.class)) {
-            otpimizeAtControlSplit(controlSplit, cfg);
+            optimizeAtControlSplit(controlSplit, cfg);
         }
     }
 
@@ -84,7 +84,7 @@
         return anchor.getBeginNode();
     }
 
-    private static void otpimizeAtControlSplit(ControlSplitNode controlSplit, LazyCFG cfg) {
+    private static void optimizeAtControlSplit(ControlSplitNode controlSplit, LazyCFG cfg) {
         AbstractBeginNode successor = findMinimumUsagesSuccessor(controlSplit);
         int successorCount = controlSplit.successors().count();
         List<GuardNode> otherGuards = new ArrayList<>(successorCount - 1);
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ReadEliminationPhase.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ReadEliminationPhase.java	Mon Dec 02 12:45:18 2013 +0100
@@ -46,24 +46,24 @@
         return isWrites(n, n.getLastLocationAccess(), n.graph().createNodeBitMap());
     }
 
-    private static boolean isWrites(FloatingReadNode n, Node lastLocationAccess, NodeBitMap visited) {
+    private static boolean isWrites(FloatingReadNode n, MemoryNode lastLocationAccess, NodeBitMap visited) {
         if (lastLocationAccess == null) {
             return false;
         }
-        if (visited.isMarked(lastLocationAccess)) {
+        if (visited.isMarked(ValueNodeUtil.asNode(lastLocationAccess))) {
             return true; // dataflow loops must come from Phis assume them ok until proven wrong
         }
         if (lastLocationAccess instanceof ProxyNode) {
-            return isWrites(n, ((ProxyNode) lastLocationAccess).value(), visited);
+            return isWrites(n, (MemoryNode) ((ProxyNode) lastLocationAccess).value(), visited);
         }
         if (lastLocationAccess instanceof WriteNode) {
             WriteNode other = (WriteNode) lastLocationAccess;
             return other.object() == n.object() && other.location() == n.location();
         }
         if (lastLocationAccess instanceof PhiNode) {
-            visited.mark(lastLocationAccess);
+            visited.mark(ValueNodeUtil.asNode(lastLocationAccess));
             for (ValueNode value : ((PhiNode) lastLocationAccess).values()) {
-                if (!isWrites(n, value, visited)) {
+                if (!isWrites(n, (MemoryNode) value, visited)) {
                     return false;
                 }
             }
@@ -72,15 +72,15 @@
         return false;
     }
 
-    private static ValueNode getValue(FloatingReadNode n, Node lastLocationAccess, NodeMap<ValueNode> nodeMap) {
-        ValueNode exisiting = nodeMap.get(lastLocationAccess);
+    private static ValueNode getValue(FloatingReadNode n, MemoryNode lastLocationAccess, NodeMap<ValueNode> nodeMap) {
+        ValueNode exisiting = nodeMap.get(ValueNodeUtil.asNode(lastLocationAccess));
         if (exisiting != null) {
             return exisiting;
         }
-        if (lastLocationAccess instanceof ProxyNode) {
-            ProxyNode proxy = (ProxyNode) lastLocationAccess;
-            ValueNode value = getValue(n, proxy.value(), nodeMap);
-            return ProxyNode.forValue(value, proxy.proxyPoint(), (StructuredGraph) lastLocationAccess.graph());
+        if (lastLocationAccess instanceof MemoryProxyNode) {
+            MemoryProxyNode proxy = (MemoryProxyNode) lastLocationAccess;
+            ValueNode value = getValue(n, proxy.getOriginalMemoryNode(), nodeMap);
+            return ProxyNode.forValue(value, proxy.proxyPoint(), proxy.graph());
         }
         if (lastLocationAccess instanceof WriteNode) {
             return ((WriteNode) lastLocationAccess).value();
@@ -88,9 +88,9 @@
         if (lastLocationAccess instanceof PhiNode) {
             PhiNode phi = (PhiNode) lastLocationAccess;
             PhiNode newPhi = phi.graph().addWithoutUnique(new PhiNode(n.kind(), phi.merge()));
-            nodeMap.set(lastLocationAccess, newPhi);
+            nodeMap.set(phi, newPhi);
             for (ValueNode value : phi.values()) {
-                newPhi.addInput(getValue(n, value, nodeMap));
+                newPhi.addInput(getValue(n, (MemoryNode) value, nodeMap));
             }
             return newPhi;
         }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/BasePhase.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/BasePhase.java	Mon Dec 02 12:45:18 2013 +0100
@@ -25,6 +25,7 @@
 import java.util.regex.*;
 
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.debug.internal.*;
 import com.oracle.graal.nodes.*;
 
@@ -75,19 +76,15 @@
     }
 
     public final void apply(final StructuredGraph graph, final C context, final boolean dumpGraph) {
-        try (TimerCloseable a = phaseTimer.start()) {
-
-            Debug.scope(name, this, new Runnable() {
-
-                public void run() {
-                    BasePhase.this.run(graph, context);
-                    phaseMetric.increment();
-                    if (dumpGraph) {
-                        Debug.dump(graph, "After phase %s", name);
-                    }
-                    assert graph.verify();
-                }
-            });
+        try (TimerCloseable a = phaseTimer.start(); Scope s = Debug.scope(name, this)) {
+            BasePhase.this.run(graph, context);
+            phaseMetric.increment();
+            if (dumpGraph) {
+                Debug.dump(graph, "After phase %s", name);
+            }
+            assert graph.verify();
+        } catch (Throwable t) {
+            throw Debug.handle(t);
         }
     }
 
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Mon Dec 02 12:45:18 2013 +0100
@@ -148,9 +148,9 @@
     public static final OptionValue<Boolean> PrintBinaryGraphs = new OptionValue<>(true);
     @Option(help = "Output probabilities for fixed nodes during binary graph dumping")
     public static final OptionValue<Boolean> PrintGraphProbabilities = new OptionValue<>(false);
-    @Option(help = "Enables dumping to the C1Visualizer. Enabling this option implies PrintBackendCFG.")
+    @Option(help = "Enable dumping to the C1Visualizer. Enabling this option implies PrintBackendCFG.")
     public static final OptionValue<Boolean> PrintCFG = new OptionValue<>(false);
-    @Option(help = "Enables dumping LIR, register allocation and code generation info to the C1Visualizer.")
+    @Option(help = "Enable dumping LIR, register allocation and code generation info to the C1Visualizer.")
     public static final OptionValue<Boolean> PrintBackendCFG = new OptionValue<>(true);
     @Option(help = "")
     public static final OptionValue<Boolean> PrintIdealGraphFile = new OptionValue<>(false);
@@ -166,7 +166,7 @@
     public static final OptionValue<Boolean> PrintCompilation = new OptionValue<>(false);
     @Option(help = "")
     public static final OptionValue<Boolean> PrintAfterCompilation = new OptionValue<>(false);
-    @Option(help = "")
+    @Option(help = "Print profiling information when parsing a method's bytecode")
     public static final OptionValue<Boolean> PrintProfilingInformation = new OptionValue<>(false);
     @Option(help = "")
     public static final OptionValue<Boolean> PrintCodeBytes = new OptionValue<>(false);
@@ -180,7 +180,7 @@
     public static final OptionValue<Boolean> ExitVMOnException = new OptionValue<>(true);
     @Option(help = "")
     public static final OptionValue<Boolean> PrintStackTraceOnException = new OptionValue<>(false);
-    @Option(help = "Sets a phase after which the decompiler dumps the graph, -G:Dump= required")
+    @Option(help = "Set a phase after which the decompiler dumps the graph, -G:Dump= required")
     public static final OptionValue<String> DecompileAfterPhase = new OptionValue<>(null);
 
     // HotSpot command line options
@@ -258,7 +258,9 @@
     @Option(help = "")
     public static final OptionValue<Boolean> OptCanonicalizer = new OptionValue<>(true);
     @Option(help = "")
-     public static final OptionValue<Boolean> OptScheduleOutOfLoops = new OptionValue<>(true);
+    public static final OptionValue<Boolean> OptDeoptimizationGrouping = new OptionValue<>(true);
+    @Option(help = "")
+    public static final OptionValue<Boolean> OptScheduleOutOfLoops = new OptionValue<>(true);
     @Option(help = "")
     public static final OptionValue<Boolean> OptEliminateGuards = new OptionValue<>(true);
     @Option(help = "")
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Mon Dec 02 12:45:18 2013 +0100
@@ -33,7 +33,6 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Node.Verbosity;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.PhiNode.PhiType;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.nodes.extended.*;
@@ -286,14 +285,12 @@
         KillSet excludedLocations = new KillSet();
         if (block.getBeginNode() instanceof MergeNode) {
             MergeNode mergeNode = (MergeNode) block.getBeginNode();
-            for (PhiNode phi : mergeNode.usages().filter(PhiNode.class)) {
-                if (phi.type() == PhiType.Memory) {
-                    if (foundExcludeNode) {
-                        set.add(phi.getIdentity());
-                    } else {
-                        excludedLocations.add(phi.getIdentity());
-                        foundExcludeNode = phi == excludeNode;
-                    }
+            for (MemoryPhiNode phi : mergeNode.usages().filter(MemoryPhiNode.class)) {
+                if (foundExcludeNode) {
+                    set.add(phi.getLocationIdentity());
+                } else {
+                    excludedLocations.add(phi.getLocationIdentity());
+                    foundExcludeNode = phi == excludeNode;
                 }
             }
         }
@@ -403,8 +400,12 @@
         }
     }
 
-    private Block blockForFixedNode(Node n) {
-        Block b = cfg.getNodeToBlock().get(n);
+    private Block blockForMemoryNode(MemoryNode memory) {
+        MemoryNode current = memory;
+        while (current instanceof MemoryProxy) {
+            current = ((MemoryProxy) current).getOriginalMemoryNode();
+        }
+        Block b = cfg.getNodeToBlock().get(current.asNode());
         assert b != null : "all lastAccess locations should have a block assignment from CFG";
         return b;
     }
@@ -546,13 +547,11 @@
                 if (assertionEnabled()) {
                     if (scheduleRead) {
                         FloatingReadNode read = (FloatingReadNode) node;
-                        Node lastLocationAccess = read.getLastLocationAccess();
-                        Block upperBound = blockForFixedNode(lastLocationAccess);
-                        if (!blockForFixedNode(lastLocationAccess).dominates(block)) {
-                            assert false : String.format("out of loop movement voilated memory semantics for %s (location %s). moved to %s but upper bound is %s (earliest: %s, latest: %s)", read,
-                                            read.getLocationIdentity(), block, upperBound, earliestBlock, latest);
-                        }
-
+                        MemoryNode lastLocationAccess = read.getLastLocationAccess();
+                        Block upperBound = blockForMemoryNode(lastLocationAccess);
+                        assert upperBound.dominates(block) : String.format(
+                                        "out of loop movement voilated memory semantics for %s (location %s). moved to %s but upper bound is %s (earliest: %s, latest: %s)", read,
+                                        read.getLocationIdentity(), block, upperBound, earliestBlock, latest);
                     }
                 }
                 break;
@@ -599,7 +598,7 @@
         LocationIdentity locid = n.location().getLocationIdentity();
         assert locid != FINAL_LOCATION;
 
-        Block upperBoundBlock = blockForFixedNode(n.getLastLocationAccess());
+        Block upperBoundBlock = blockForMemoryNode(n.getLastLocationAccess());
         Block earliestBlock = earliestBlock(n);
         assert upperBoundBlock.dominates(earliestBlock) : "upper bound (" + upperBoundBlock + ") should dominate earliest (" + earliestBlock + ")";
 
@@ -630,7 +629,7 @@
                 if (currentBlock == upperBoundBlock) {
                     assert earliestBlock == upperBoundBlock;
                     // don't treat lastLocationAccess node as a kill for this read.
-                    closure = new NewMemoryScheduleClosure(n.getLastLocationAccess(), upperBoundBlock);
+                    closure = new NewMemoryScheduleClosure(ValueNodeUtil.asNode(n.getLastLocationAccess()), upperBoundBlock);
                 } else {
                     closure = new NewMemoryScheduleClosure();
                 }
@@ -646,7 +645,7 @@
             } else {
                 if (currentBlock == upperBoundBlock) {
                     assert earliestBlock == upperBoundBlock;
-                    KillSet ks = computeKillSet(upperBoundBlock, n.getLastLocationAccess());
+                    KillSet ks = computeKillSet(upperBoundBlock, ValueNodeUtil.asNode(n.getLastLocationAccess()));
                     if (ks.isKilled(locid)) {
                         return upperBoundBlock;
                     }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/HighTierContext.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/HighTierContext.java	Mon Dec 02 12:45:18 2013 +0100
@@ -23,6 +23,7 @@
 package com.oracle.graal.phases.tiers;
 
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.util.*;
@@ -34,13 +35,18 @@
     private final GraphCache cache;
     private final OptimisticOptimizations optimisticOpts;
 
-    public HighTierContext(Providers copyFrom, Assumptions assumptions, GraphCache cache, PhasePlan plan, OptimisticOptimizations optimisticOpts) {
-        super(copyFrom, assumptions);
+    public HighTierContext(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, LoweringProvider lowerer, Replacements replacements, Assumptions assumptions,
+                    GraphCache cache, PhasePlan plan, OptimisticOptimizations optimisticOpts) {
+        super(metaAccess, constantReflection, lowerer, replacements, assumptions);
         this.plan = plan;
         this.cache = cache;
         this.optimisticOpts = optimisticOpts;
     }
 
+    public HighTierContext(Providers providers, Assumptions assumptions, GraphCache cache, PhasePlan plan, OptimisticOptimizations optimisticOpts) {
+        this(providers.getMetaAccess(), providers.getConstantReflection(), providers.getLowerer(), providers.getReplacements(), assumptions, cache, plan, optimisticOpts);
+    }
+
     public PhasePlan getPhasePlan() {
         return plan;
     }
@@ -54,6 +60,6 @@
     }
 
     public HighTierContext replaceAssumptions(Assumptions newAssumptions) {
-        return new HighTierContext(this, newAssumptions, getGraphCache(), getPhasePlan(), getOptimisticOptimizations());
+        return new HighTierContext(getMetaAccess(), getConstantReflection(), getLowerer(), getReplacements(), newAssumptions, getGraphCache(), getPhasePlan(), getOptimisticOptimizations());
     }
 }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/PhaseContext.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/PhaseContext.java	Mon Dec 02 12:45:18 2013 +0100
@@ -27,19 +27,40 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.util.*;
 
-public class PhaseContext extends Providers {
+public class PhaseContext {
 
+    private final MetaAccessProvider metaAccess;
+    private final ConstantReflectionProvider constantReflection;
+    private final LoweringProvider lowerer;
+    private final Replacements replacements;
     private final Assumptions assumptions;
 
-    public PhaseContext(MetaAccessProvider metaAccess, CodeCacheProvider codeCache, ConstantReflectionProvider constantReflection, ForeignCallsProvider foreignCalls, LoweringProvider lowerer,
-                    Assumptions assumptions, Replacements replacements) {
-        super(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements);
+    public PhaseContext(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, LoweringProvider lowerer, Replacements replacements, Assumptions assumptions) {
+        this.metaAccess = metaAccess;
+        this.constantReflection = constantReflection;
+        this.lowerer = lowerer;
+        this.replacements = replacements;
         this.assumptions = assumptions;
     }
 
-    public PhaseContext(Providers copyFrom, Assumptions assumptions) {
-        super(copyFrom);
-        this.assumptions = assumptions;
+    public PhaseContext(Providers providers, Assumptions assumptions) {
+        this(providers.getMetaAccess(), providers.getConstantReflection(), providers.getLowerer(), providers.getReplacements(), assumptions);
+    }
+
+    public MetaAccessProvider getMetaAccess() {
+        return metaAccess;
+    }
+
+    public ConstantReflectionProvider getConstantReflection() {
+        return constantReflection;
+    }
+
+    public LoweringProvider getLowerer() {
+        return lowerer;
+    }
+
+    public Replacements getReplacements() {
+        return replacements;
     }
 
     public Assumptions getAssumptions() {
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/Providers.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/Providers.java	Mon Dec 02 12:45:18 2013 +0100
@@ -25,6 +25,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.phases.tiers.*;
 
 /**
  * A set of providers, some of which may not be present (i.e., null).
@@ -49,12 +50,11 @@
     }
 
     public Providers(Providers copyFrom) {
-        this.metaAccess = copyFrom.metaAccess;
-        this.codeCache = copyFrom.codeCache;
-        this.constantReflection = copyFrom.constantReflection;
-        this.foreignCalls = copyFrom.foreignCalls;
-        this.lowerer = copyFrom.lowerer;
-        this.replacements = copyFrom.replacements;
+        this(copyFrom.getMetaAccess(), copyFrom.getCodeCache(), copyFrom.getConstantReflection(), copyFrom.getForeignCalls(), copyFrom.getLowerer(), copyFrom.getReplacements());
+    }
+
+    public Providers(PhaseContext copyFrom) {
+        this(copyFrom.getMetaAccess(), null, copyFrom.getConstantReflection(), null, copyFrom.getLowerer(), copyFrom.getReplacements());
     }
 
     public MetaAccessProvider getMetaAccess() {
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BasicIdealGraphPrinter.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BasicIdealGraphPrinter.java	Mon Dec 02 12:45:18 2013 +0100
@@ -23,6 +23,7 @@
 package com.oracle.graal.printer;
 
 import java.io.*;
+import java.nio.charset.*;
 import java.util.*;
 import java.util.Map.Entry;
 
@@ -90,7 +91,7 @@
             } else {
                 buffered = new BufferedOutputStream(stream, 256 * 1024);
             }
-            this.stream = new PrintStream(buffered, false, "US-ASCII");
+            this.stream = new PrintStream(buffered, false, Charset.defaultCharset().name());
         } catch (UnsupportedEncodingException e) {
             throw new RuntimeException(e);
         }
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/DecompilerDebugDumpHandler.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/DecompilerDebugDumpHandler.java	Mon Dec 02 12:45:18 2013 +0100
@@ -22,12 +22,13 @@
  */
 package com.oracle.graal.printer;
 
+import static com.oracle.graal.phases.GraalOptions.*;
+
 import java.io.*;
 import java.util.concurrent.atomic.*;
 
-import static com.oracle.graal.phases.GraalOptions.*;
-
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.java.decompiler.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.schedule.*;
@@ -69,18 +70,15 @@
             final String currentScope = Debug.currentScope();
             if (currentScope.endsWith(filter) && graph.method() != null) {
                 final String methodName = graph.method().getName();
-                Debug.sandbox("Printing Decompiler Output", null, new Runnable() {
-
-                    @Override
-                    public void run() {
-                        printStream.println();
-                        printStream.println("Object: " + methodName);
-                        printStream.println("Message: " + message);
-                        new Decompiler(graph, getPredefinedSchedule(), printStream, infoPrintStream, currentScope).decompile();
-                        printStream.flush();
-                    }
-                });
-
+                try (Scope s = Debug.sandbox("Printing Decompiler Output", null)) {
+                    printStream.println();
+                    printStream.println("Object: " + methodName);
+                    printStream.println("Message: " + message);
+                    new Decompiler(graph, getPredefinedSchedule(), printStream, infoPrintStream, currentScope).decompile();
+                    printStream.flush();
+                } catch (Throwable e) {
+                    throw Debug.handle(e);
+                }
             }
         }
     }
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/GraphPrinterDumpHandler.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/GraphPrinterDumpHandler.java	Mon Dec 02 12:45:18 2013 +0100
@@ -34,6 +34,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.phases.schedule.*;
 
@@ -44,7 +45,7 @@
  */
 public class GraphPrinterDumpHandler implements DebugDumpHandler {
 
-    private GraphPrinter printer;
+    protected GraphPrinter printer;
     private List<String> previousInlineContext;
     private int[] dumpIds = {};
     private int failuresCount;
@@ -62,11 +63,15 @@
                 return;
             }
             previousInlineContext.clear();
-            if (PrintIdealGraphFile.getValue()) {
-                initializeFilePrinter();
-            } else {
-                initializeNetworkPrinter();
-            }
+            createPrinter();
+        }
+    }
+
+    protected void createPrinter() {
+        if (PrintIdealGraphFile.getValue()) {
+            initializeFilePrinter();
+        } else {
+            initializeNetworkPrinter();
         }
     }
 
@@ -172,19 +177,15 @@
                 previousInlineContext = inlineContext;
 
                 final SchedulePhase predefinedSchedule = getPredefinedSchedule();
-                Debug.sandbox("PrintingGraph", null, new Runnable() {
-
-                    @Override
-                    public void run() {
-                        // Finally, output the graph.
-                        try {
-                            printer.print(graph, nextDumpId() + ":" + message, predefinedSchedule);
-                        } catch (IOException e) {
-                            failuresCount++;
-                            printer = null;
-                        }
-                    }
-                });
+                try (Scope s = Debug.sandbox("PrintingGraph", null)) {
+                    // Finally, output the graph.
+                    printer.print(graph, nextDumpId() + ":" + message, predefinedSchedule);
+                } catch (IOException e) {
+                    failuresCount++;
+                    printer = null;
+                } catch (Throwable e) {
+                    throw Debug.handle(e);
+                }
             }
         }
     }
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinter.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinter.java	Mon Dec 02 12:45:18 2013 +0100
@@ -40,7 +40,7 @@
  * Generates a representation of {@link Graph Graphs} that can be visualized and inspected with the
  * <a href="http://kenai.com/projects/igv">Ideal Graph Visualizer</a>.
  */
-class IdealGraphPrinter extends BasicIdealGraphPrinter implements GraphPrinter {
+public class IdealGraphPrinter extends BasicIdealGraphPrinter implements GraphPrinter {
 
     /**
      * Creates a new {@link IdealGraphPrinter} that writes to the specified output stream.
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/MethodSubstitutionTest.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/MethodSubstitutionTest.java	Mon Dec 02 12:45:18 2013 +0100
@@ -24,12 +24,11 @@
 
 import static org.junit.Assert.*;
 
-import java.util.concurrent.*;
-
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.compiler.test.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.*;
@@ -44,24 +43,22 @@
 public abstract class MethodSubstitutionTest extends GraalCompilerTest {
 
     protected StructuredGraph test(final String snippet) {
-        return Debug.scope("MethodSubstitutionTest", getMetaAccess().lookupJavaMethod(getMethod(snippet)), new Callable<StructuredGraph>() {
+        try (Scope s = Debug.scope("MethodSubstitutionTest", getMetaAccess().lookupJavaMethod(getMethod(snippet)))) {
+            StructuredGraph graph = parse(snippet);
+            PhasePlan phasePlan = getDefaultPhasePlan();
+            Assumptions assumptions = new Assumptions(true);
+            HighTierContext context = new HighTierContext(getProviders(), assumptions, null, phasePlan, OptimisticOptimizations.ALL);
+            Debug.dump(graph, "Graph");
+            new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
+            Debug.dump(graph, "Graph");
+            new CanonicalizerPhase(true).apply(graph, context);
+            new DeadCodeEliminationPhase().apply(graph);
 
-            @Override
-            public StructuredGraph call() {
-                StructuredGraph graph = parse(snippet);
-                PhasePlan phasePlan = getDefaultPhasePlan();
-                Assumptions assumptions = new Assumptions(true);
-                HighTierContext context = new HighTierContext(getProviders(), assumptions, null, phasePlan, OptimisticOptimizations.ALL);
-                Debug.dump(graph, "Graph");
-                new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
-                Debug.dump(graph, "Graph");
-                new CanonicalizerPhase(true).apply(graph, context);
-                new DeadCodeEliminationPhase().apply(graph);
-
-                assertNotInGraph(graph, Invoke.class);
-                return graph;
-            }
-        });
+            assertNotInGraph(graph, Invoke.class);
+            return graph;
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
     }
 
     protected static StructuredGraph assertNotInGraph(StructuredGraph graph, Class<?> clazz) {
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/NewMultiArrayTest.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/NewMultiArrayTest.java	Mon Dec 02 12:45:18 2013 +0100
@@ -59,7 +59,7 @@
             int rank = dimensions.length;
             ValueNode[] dimensionNodes = new ValueNode[rank];
             for (int i = 0; i < rank; i++) {
-                dimensionNodes[i] = graph.unique(ConstantNode.forInt(dimensions[i], graph));
+                dimensionNodes[i] = ConstantNode.forInt(dimensions[i], graph);
             }
 
             NewMultiArrayNode repl = graph.add(new NewMultiArrayNode(arrayType, dimensionNodes));
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java	Mon Dec 02 12:45:18 2013 +0100
@@ -46,7 +46,7 @@
     private final ReplacementsImpl installer;
 
     public ObjectAccessTest() {
-        installer = new ReplacementsImpl(getProviders(), new Assumptions(false));
+        installer = new ReplacementsImpl(getProviders(), new Assumptions(false), getTarget());
     }
 
     private static final ThreadLocal<SnippetInliningPolicy> inliningPolicy = new ThreadLocal<>();
@@ -60,7 +60,7 @@
     @Test
     public void testRead1() {
         for (Kind kind : KINDS) {
-            assertRead(parse("read" + kind.name() + "1"), kind, false, ID);
+            assertRead(parse("read" + kind.name() + "1"), kind, true, ID);
         }
     }
 
@@ -74,14 +74,14 @@
     @Test
     public void testRead3() {
         for (Kind kind : KINDS) {
-            assertRead(parse("read" + kind.name() + "3"), kind, false, LocationIdentity.ANY_LOCATION);
+            assertRead(parse("read" + kind.name() + "3"), kind, true, LocationIdentity.ANY_LOCATION);
         }
     }
 
     @Test
     public void testWrite1() {
         for (Kind kind : KINDS) {
-            assertWrite(parse("write" + kind.name() + "1"), kind, false, ID);
+            assertWrite(parse("write" + kind.name() + "1"), kind, true, ID);
         }
     }
 
@@ -95,7 +95,7 @@
     @Test
     public void testWrite3() {
         for (Kind kind : KINDS) {
-            assertWrite(parse("write" + kind.name() + "3"), kind, false, LocationIdentity.ANY_LOCATION);
+            assertWrite(parse("write" + kind.name() + "3"), kind, true, LocationIdentity.ANY_LOCATION);
         }
     }
 
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java	Mon Dec 02 12:45:18 2013 +0100
@@ -52,7 +52,7 @@
 
     public PointerTest() {
         target = getCodeCache().getTarget();
-        installer = new ReplacementsImpl(getProviders(), new Assumptions(false));
+        installer = new ReplacementsImpl(getProviders(), new Assumptions(false), getTarget());
     }
 
     private static final ThreadLocal<SnippetInliningPolicy> inliningPolicy = new ThreadLocal<>();
@@ -66,7 +66,7 @@
     @Test
     public void testRead1() {
         for (Kind kind : KINDS) {
-            assertRead(parse("read" + kind.name() + "1"), kind, false, ID);
+            assertRead(parse("read" + kind.name() + "1"), kind, true, ID);
         }
     }
 
@@ -80,14 +80,14 @@
     @Test
     public void testRead3() {
         for (Kind kind : KINDS) {
-            assertRead(parse("read" + kind.name() + "3"), kind, false, LocationIdentity.ANY_LOCATION);
+            assertRead(parse("read" + kind.name() + "3"), kind, true, LocationIdentity.ANY_LOCATION);
         }
     }
 
     @Test
     public void testWrite1() {
         for (Kind kind : KINDS) {
-            assertWrite(parse("write" + kind.name() + "1"), kind, false, ID);
+            assertWrite(parse("write" + kind.name() + "1"), kind, true, ID);
         }
     }
 
@@ -101,7 +101,7 @@
     @Test
     public void testWrite3() {
         for (Kind kind : KINDS) {
-            assertWrite(parse("write" + kind.name() + "3"), kind, false, LocationIdentity.ANY_LOCATION);
+            assertWrite(parse("write" + kind.name() + "3"), kind, true, LocationIdentity.ANY_LOCATION);
         }
     }
 
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java	Mon Dec 02 12:45:18 2013 +0100
@@ -41,7 +41,7 @@
     private final ReplacementsImpl installer;
 
     public WordTest() {
-        installer = new ReplacementsImpl(getProviders(), new Assumptions(false));
+        installer = new ReplacementsImpl(getProviders(), new Assumptions(false), getTarget());
     }
 
     private static final ThreadLocal<SnippetInliningPolicy> inliningPolicy = new ThreadLocal<>();
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java	Mon Dec 02 12:45:18 2013 +0100
@@ -380,7 +380,7 @@
         } else if (usage instanceof ProxyNode) {
             ProxyNode proxy = (ProxyNode) usage;
             assert proxy.type() == PhiType.Value;
-            ProxyNode newProxy = graph.unique(new ProxyNode((ValueNode) intrinsifiedNode, proxy.proxyPoint(), PhiType.Value, proxy.getIdentity()));
+            ProxyNode newProxy = graph.unique(new ProxyNode((ValueNode) intrinsifiedNode, proxy.proxyPoint(), PhiType.Value));
             for (Node proxyUsage : usage.usages().snapshot()) {
                 checkCheckCastUsage(graph, newProxy, proxy, proxyUsage);
             }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Mon Dec 02 12:45:18 2013 +0100
@@ -36,6 +36,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.debug.internal.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.java.*;
@@ -60,18 +61,18 @@
     /**
      * The preprocessed replacement graphs.
      */
-    private final ConcurrentMap<ResolvedJavaMethod, StructuredGraph> graphs;
+    protected final ConcurrentMap<ResolvedJavaMethod, StructuredGraph> graphs;
 
     // These data structures are all fully initialized during single-threaded
     // compiler startup and so do not need to be concurrent.
-    private final Map<ResolvedJavaMethod, ResolvedJavaMethod> registeredMethodSubstitutions;
+    protected final Map<ResolvedJavaMethod, ResolvedJavaMethod> registeredMethodSubstitutions;
     private final Map<ResolvedJavaMethod, Class<? extends FixedWithNextNode>> registeredMacroSubstitutions;
     private final Set<ResolvedJavaMethod> forcedSubstitutions;
     private final Map<Class<? extends SnippetTemplateCache>, SnippetTemplateCache> snippetTemplateCache;
 
-    public ReplacementsImpl(Providers providers, Assumptions assumptions) {
+    public ReplacementsImpl(Providers providers, Assumptions assumptions, TargetDescription target) {
         this.providers = providers.copyWith(this);
-        this.target = providers.getCodeCache().getTarget();
+        this.target = target;
         this.assumptions = assumptions;
         this.graphs = new ConcurrentHashMap<>();
         this.registeredMethodSubstitutions = new HashMap<>();
@@ -83,6 +84,7 @@
     private static final boolean UseSnippetGraphCache = Boolean.parseBoolean(System.getProperty("graal.useSnippetGraphCache", "true"));
     private static final DebugTimer SnippetPreparationTime = Debug.timer("SnippetPreparationTime");
 
+    @Override
     public StructuredGraph getSnippet(ResolvedJavaMethod method) {
         assert method.getAnnotation(Snippet.class) != null : "Snippet must be annotated with @" + Snippet.class.getSimpleName();
         assert !Modifier.isAbstract(method.getModifiers()) && !Modifier.isNative(method.getModifiers()) : "Snippet must not be abstract or native";
@@ -102,6 +104,22 @@
         return graph;
     }
 
+    @Override
+    public void registerSnippet(ResolvedJavaMethod method) {
+        // No initialization needed as snippet graphs are created on demand in getSnippet
+    }
+
+    @Override
+    public void prepareSnippetCopyAfterInstantiation(StructuredGraph snippetCopy) {
+
+        // Do deferred intrinsification of node intrinsics
+
+        new NodeIntrinsificationPhase(providers).apply(snippetCopy);
+        new CanonicalizerPhase(true).apply(snippetCopy, new PhaseContext(providers, assumptions));
+        NodeIntrinsificationVerificationPhase.verify(snippetCopy);
+    }
+
+    @Override
     public StructuredGraph getMethodSubstitution(ResolvedJavaMethod original) {
         ResolvedJavaMethod substitute = registeredMethodSubstitutions.get(original);
         if (substitute == null) {
@@ -148,8 +166,8 @@
                     throw new GraalInternalError("Substitution method must not be abstract or native: " + substituteMethod);
                 }
                 String originalName = originalName(substituteMethod, methodSubstitution.value());
-                Class[] originalParameters = originalParameters(substituteMethod, methodSubstitution.signature(), methodSubstitution.isStatic());
-                Member originalMethod = originalMethod(classSubstitution, methodSubstitution.optional(), originalName, originalParameters);
+                JavaSignature originalSignature = originalSignature(substituteMethod, methodSubstitution.signature(), methodSubstitution.isStatic());
+                Member originalMethod = originalMethod(classSubstitution, methodSubstitution.optional(), originalName, originalSignature);
                 if (originalMethod != null) {
                     ResolvedJavaMethod original = registerMethodSubstitution(originalMethod, substituteMethod);
                     if (original != null && methodSubstitution.forced() && shouldIntrinsify(original)) {
@@ -159,8 +177,8 @@
             }
             if (macroSubstitution != null) {
                 String originalName = originalName(substituteMethod, macroSubstitution.value());
-                Class[] originalParameters = originalParameters(substituteMethod, macroSubstitution.signature(), macroSubstitution.isStatic());
-                Member originalMethod = originalMethod(classSubstitution, macroSubstitution.optional(), originalName, originalParameters);
+                JavaSignature originalSignature = originalSignature(substituteMethod, macroSubstitution.signature(), macroSubstitution.isStatic());
+                Member originalMethod = originalMethod(classSubstitution, macroSubstitution.optional(), originalName, originalSignature);
                 if (originalMethod != null) {
                     ResolvedJavaMethod original = registerMacroSubstitution(originalMethod, macroSubstitution.macro());
                     if (original != null && macroSubstitution.forced() && shouldIntrinsify(original)) {
@@ -187,7 +205,7 @@
         } else {
             original = metaAccess.lookupJavaConstructor((Constructor) originalMember);
         }
-        Debug.log("substitution: " + MetaUtil.format("%H.%n(%p)", original) + " --> " + MetaUtil.format("%H.%n(%p)", substitute));
+        Debug.log("substitution: " + MetaUtil.format("%H.%n(%p) %r", original) + " --> " + MetaUtil.format("%H.%n(%p) %r", substitute));
 
         registeredMethodSubstitutions.put(original, substitute);
         return original;
@@ -212,7 +230,15 @@
         return originalJavaMethod;
     }
 
-    private SnippetInliningPolicy inliningPolicy(ResolvedJavaMethod method) {
+    private static SnippetInliningPolicy createPolicyClassInstance(Class<? extends SnippetInliningPolicy> policyClass) {
+        try {
+            return policyClass.getConstructor().newInstance();
+        } catch (Exception e) {
+            throw new GraalInternalError(e);
+        }
+    }
+
+    protected SnippetInliningPolicy inliningPolicy(ResolvedJavaMethod method) {
         Class<? extends SnippetInliningPolicy> policyClass = SnippetInliningPolicy.class;
         Snippet snippet = method.getAnnotation(Snippet.class);
         if (snippet != null) {
@@ -221,11 +247,7 @@
         if (policyClass == SnippetInliningPolicy.class) {
             return new DefaultSnippetInliningPolicy(providers.getMetaAccess());
         }
-        try {
-            return policyClass.getConstructor().newInstance();
-        } catch (Exception e) {
-            throw new GraalInternalError(e);
-        }
+        return createPolicyClassInstance(policyClass);
     }
 
     /**
@@ -277,22 +299,20 @@
         }
 
         public StructuredGraph makeGraph(final SnippetInliningPolicy policy, final boolean removeAllFrameStates) {
-            return Debug.scope("BuildSnippetGraph", new Object[]{method}, new Callable<StructuredGraph>() {
+            try (Scope s = Debug.scope("BuildSnippetGraph", method)) {
+                StructuredGraph graph = parseGraph(method, policy);
 
-                @Override
-                public StructuredGraph call() throws Exception {
-                    StructuredGraph graph = parseGraph(method, policy);
+                // Cannot have a finalized version of a graph in the cache
+                graph = graph.copy();
 
-                    // Cannot have a finalized version of a graph in the cache
-                    graph = graph.copy();
+                finalizeGraph(graph, removeAllFrameStates);
 
-                    finalizeGraph(graph, removeAllFrameStates);
+                Debug.dump(graph, "%s: Final", method.getName());
 
-                    Debug.dump(graph, "%s: Final", method.getName());
-
-                    return graph;
-                }
-            });
+                return graph;
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            }
         }
 
         /**
@@ -322,12 +342,12 @@
         private StructuredGraph parseGraph(final ResolvedJavaMethod methodToParse, final SnippetInliningPolicy policy) {
             StructuredGraph graph = graphCache.get(methodToParse);
             if (graph == null) {
-                StructuredGraph newGraph = Debug.scope("ParseGraph", new Object[]{methodToParse}, new Callable<StructuredGraph>() {
-
-                    public StructuredGraph call() throws Exception {
-                        return buildGraph(methodToParse, policy == null ? inliningPolicy(methodToParse) : policy);
-                    }
-                });
+                StructuredGraph newGraph = null;
+                try (Scope s = Debug.scope("ParseGraph", methodToParse)) {
+                    newGraph = buildGraph(methodToParse, policy == null ? inliningPolicy(methodToParse) : policy);
+                } catch (Throwable e) {
+                    throw Debug.handle(e);
+                }
 
                 graphCache.putIfAbsent(methodToParse, newGraph);
                 graph = graphCache.get(methodToParse);
@@ -341,21 +361,19 @@
          */
         protected StructuredGraph buildInitialGraph(final ResolvedJavaMethod methodToParse) {
             final StructuredGraph graph = new StructuredGraph(methodToParse);
-            Debug.scope("buildInitialGraph", graph, new Runnable() {
+            try (Scope s = Debug.scope("buildInitialGraph", graph)) {
+                MetaAccessProvider metaAccess = providers.getMetaAccess();
+                ForeignCallsProvider foreignCalls = providers.getForeignCalls();
+                new GraphBuilderPhase(metaAccess, foreignCalls, GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.NONE).apply(graph);
+                new WordTypeVerificationPhase(metaAccess, target.wordKind).apply(graph);
+                new WordTypeRewriterPhase(metaAccess, target.wordKind).apply(graph);
 
-                @Override
-                public void run() {
-                    MetaAccessProvider metaAccess = providers.getMetaAccess();
-                    ForeignCallsProvider foreignCalls = providers.getForeignCalls();
-                    new GraphBuilderPhase(metaAccess, foreignCalls, GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.NONE).apply(graph);
-                    new WordTypeVerificationPhase(metaAccess, target.wordKind).apply(graph);
-                    new WordTypeRewriterPhase(metaAccess, target.wordKind).apply(graph);
-
-                    if (OptCanonicalizer.getValue()) {
-                        new CanonicalizerPhase(true).apply(graph, new PhaseContext(providers, assumptions));
-                    }
+                if (OptCanonicalizer.getValue()) {
+                    new CanonicalizerPhase(true).apply(graph, new PhaseContext(providers, assumptions));
                 }
-            });
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            }
             return graph;
         }
 
@@ -390,57 +408,56 @@
         private StructuredGraph buildGraph(final ResolvedJavaMethod methodToParse, final SnippetInliningPolicy policy) {
             assert !Modifier.isAbstract(methodToParse.getModifiers()) && !Modifier.isNative(methodToParse.getModifiers()) : methodToParse;
             final StructuredGraph graph = buildInitialGraph(methodToParse);
-            Debug.scope("buildGraph", graph, new Runnable() {
+            try (Scope s = Debug.scope("buildGraph", graph)) {
+
+                for (MethodCallTargetNode callTarget : graph.getNodes(MethodCallTargetNode.class)) {
+                    ResolvedJavaMethod callee = callTarget.targetMethod();
+                    if (callee == method) {
+                        final StructuredGraph originalGraph = new StructuredGraph(original);
+                        MetaAccessProvider metaAccess = providers.getMetaAccess();
+                        ForeignCallsProvider foreignCalls = providers.getForeignCalls();
+                        new GraphBuilderPhase(metaAccess, foreignCalls, GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.NONE).apply(originalGraph);
+                        new WordTypeVerificationPhase(metaAccess, target.wordKind).apply(graph);
+                        new WordTypeRewriterPhase(metaAccess, target.wordKind).apply(graph);
+
+                        InliningUtil.inline(callTarget.invoke(), originalGraph, true);
 
-                @Override
-                public void run() {
-                    for (MethodCallTargetNode callTarget : graph.getNodes(MethodCallTargetNode.class)) {
-                        ResolvedJavaMethod callee = callTarget.targetMethod();
-                        if (callee == method) {
-                            final StructuredGraph originalGraph = new StructuredGraph(original);
-                            MetaAccessProvider metaAccess = providers.getMetaAccess();
-                            ForeignCallsProvider foreignCalls = providers.getForeignCalls();
-                            new GraphBuilderPhase(metaAccess, foreignCalls, GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.NONE).apply(originalGraph);
-                            new WordTypeVerificationPhase(metaAccess, target.wordKind).apply(graph);
-                            new WordTypeRewriterPhase(metaAccess, target.wordKind).apply(graph);
-
-                            InliningUtil.inline(callTarget.invoke(), originalGraph, true);
-
+                        Debug.dump(graph, "after inlining %s", callee);
+                        afterInline(graph, originalGraph, null);
+                        substituteCallsOriginal = true;
+                    } else {
+                        StructuredGraph intrinsicGraph = InliningUtil.getIntrinsicGraph(ReplacementsImpl.this, callee);
+                        if ((callTarget.invokeKind() == InvokeKind.Static || callTarget.invokeKind() == InvokeKind.Special) &&
+                                        (policy.shouldInline(callee, methodToParse) || (intrinsicGraph != null && policy.shouldUseReplacement(callee, methodToParse)))) {
+                            StructuredGraph targetGraph;
+                            if (intrinsicGraph != null && policy.shouldUseReplacement(callee, methodToParse)) {
+                                targetGraph = intrinsicGraph;
+                            } else {
+                                if (callee.getName().startsWith("$jacoco")) {
+                                    throw new GraalInternalError("Parsing call to JaCoCo instrumentation method " + format("%H.%n(%p)", callee) + " from " + format("%H.%n(%p)", methodToParse) +
+                                                    " while preparing replacement " + format("%H.%n(%p)", method) + ". Placing \"//JaCoCo Exclude\" anywhere in " +
+                                                    methodToParse.getDeclaringClass().getSourceFileName() + " should fix this.");
+                                }
+                                targetGraph = parseGraph(callee, policy);
+                            }
+                            Object beforeInlineData = beforeInline(callTarget, targetGraph);
+                            InliningUtil.inline(callTarget.invoke(), targetGraph, true);
                             Debug.dump(graph, "after inlining %s", callee);
-                            afterInline(graph, originalGraph, null);
-                            substituteCallsOriginal = true;
-                        } else {
-                            StructuredGraph intrinsicGraph = InliningUtil.getIntrinsicGraph(ReplacementsImpl.this, callee);
-                            if ((callTarget.invokeKind() == InvokeKind.Static || callTarget.invokeKind() == InvokeKind.Special) &&
-                                            (policy.shouldInline(callee, methodToParse) || (intrinsicGraph != null && policy.shouldUseReplacement(callee, methodToParse)))) {
-                                StructuredGraph targetGraph;
-                                if (intrinsicGraph != null && policy.shouldUseReplacement(callee, methodToParse)) {
-                                    targetGraph = intrinsicGraph;
-                                } else {
-                                    if (callee.getName().startsWith("$jacoco")) {
-                                        throw new GraalInternalError("Parsing call to JaCoCo instrumentation method " + format("%H.%n(%p)", callee) + " from " + format("%H.%n(%p)", methodToParse) +
-                                                        " while preparing replacement " + format("%H.%n(%p)", method) + ". Placing \"//JaCoCo Exclude\" anywhere in " +
-                                                        methodToParse.getDeclaringClass().getSourceFileName() + " should fix this.");
-                                    }
-                                    targetGraph = parseGraph(callee, policy);
-                                }
-                                Object beforeInlineData = beforeInline(callTarget, targetGraph);
-                                InliningUtil.inline(callTarget.invoke(), targetGraph, true);
-                                Debug.dump(graph, "after inlining %s", callee);
-                                afterInline(graph, targetGraph, beforeInlineData);
-                            }
+                            afterInline(graph, targetGraph, beforeInlineData);
                         }
                     }
+                }
 
-                    afterInlining(graph);
+                afterInlining(graph);
 
-                    for (LoopEndNode end : graph.getNodes(LoopEndNode.class)) {
-                        end.disableSafepoint();
-                    }
+                for (LoopEndNode end : graph.getNodes(LoopEndNode.class)) {
+                    end.disableSafepoint();
+                }
 
-                    new DeadCodeEliminationPhase().apply(graph);
-                }
-            });
+                new DeadCodeEliminationPhase().apply(graph);
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            }
             return graph;
         }
     }
@@ -486,25 +503,50 @@
         return dimensions == 0 ? baseClass : Array.newInstance(baseClass, new int[dimensions]).getClass();
     }
 
-    private Class[] originalParameters(Method substituteMethod, String methodSubstitution, boolean isStatic) {
+    static class JavaSignature {
+        final Class returnType;
+        final Class[] parameters;
+
+        public JavaSignature(Class returnType, Class[] parameters) {
+            this.parameters = parameters;
+            this.returnType = returnType;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder("(");
+            for (int i = 0; i < parameters.length; i++) {
+                if (i != 0) {
+                    sb.append(", ");
+                }
+                sb.append(parameters[i].getName());
+            }
+            return sb.append(") ").append(returnType.getName()).toString();
+        }
+    }
+
+    private JavaSignature originalSignature(Method substituteMethod, String methodSubstitution, boolean isStatic) {
         Class[] parameters;
+        Class returnType;
         if (methodSubstitution.isEmpty()) {
             parameters = substituteMethod.getParameterTypes();
             if (!isStatic) {
                 assert parameters.length > 0 : "must be a static method with the 'this' object as its first parameter";
                 parameters = Arrays.copyOfRange(parameters, 1, parameters.length);
             }
+            returnType = substituteMethod.getReturnType();
         } else {
             Signature signature = providers.getMetaAccess().parseMethodDescriptor(methodSubstitution);
             parameters = new Class[signature.getParameterCount(false)];
             for (int i = 0; i < parameters.length; i++) {
                 parameters[i] = resolveType(signature.getParameterType(i, null));
             }
+            returnType = resolveType(signature.getReturnType(null));
         }
-        return parameters;
+        return new JavaSignature(returnType, parameters);
     }
 
-    private static Member originalMethod(ClassSubstitution classSubstitution, boolean optional, String name, Class[] parameters) {
+    private static Member originalMethod(ClassSubstitution classSubstitution, boolean optional, String name, JavaSignature signature) {
         Class<?> originalClass = classSubstitution.value();
         if (originalClass == ClassSubstitution.class) {
             originalClass = resolveType(classSubstitution.className(), classSubstitution.optional());
@@ -515,9 +557,15 @@
         }
         try {
             if (name.equals("<init>")) {
-                return originalClass.getDeclaredConstructor(parameters);
+                assert signature.returnType.equals(void.class) : signature;
+                Constructor<?> original = originalClass.getDeclaredConstructor(signature.parameters);
+                return original;
             } else {
-                return originalClass.getDeclaredMethod(name, parameters);
+                Method original = originalClass.getDeclaredMethod(name, signature.parameters);
+                if (!original.getReturnType().equals(signature.returnType)) {
+                    throw new NoSuchMethodException(originalClass.getName() + "." + name + signature);
+                }
+                return original;
             }
         } catch (NoSuchMethodException | SecurityException e) {
             if (optional) {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Mon Dec 02 12:45:18 2013 +0100
@@ -34,6 +34,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.debug.internal.*;
 import com.oracle.graal.graph.Graph.Mark;
 import com.oracle.graal.graph.*;
@@ -398,7 +399,9 @@
                 }
             }
             assert found != null : "did not find @" + Snippet.class.getSimpleName() + " method in " + declaringClass + (methodName == null ? "" : " named " + methodName);
-            return new SnippetInfo(providers.getMetaAccess().lookupJavaMethod(found));
+            ResolvedJavaMethod javaMethod = providers.getMetaAccess().lookupJavaMethod(found);
+            providers.getReplacements().registerSnippet(javaMethod);
+            return new SnippetInfo(javaMethod);
         }
 
         /**
@@ -408,17 +411,13 @@
             SnippetTemplate template = UseSnippetTemplateCache ? templates.get(args.cacheKey) : null;
             if (template == null) {
                 SnippetTemplates.increment();
-                try (TimerCloseable a = SnippetTemplateCreationTime.start()) {
-                    template = Debug.scope("SnippetSpecialization", args.info.method, new Callable<SnippetTemplate>() {
-
-                        @Override
-                        public SnippetTemplate call() throws Exception {
-                            return new SnippetTemplate(providers, args);
-                        }
-                    });
+                try (TimerCloseable a = SnippetTemplateCreationTime.start(); Scope s = Debug.scope("SnippetSpecialization", args.info.method)) {
+                    template = new SnippetTemplate(providers, args);
                     if (UseSnippetTemplateCache) {
                         templates.put(args.cacheKey, template);
                     }
+                } catch (Throwable e) {
+                    throw Debug.handle(e);
                 }
             }
             return template;
@@ -512,12 +511,8 @@
 
         Debug.dump(snippetCopy, "Before specialization");
         if (!nodeReplacements.isEmpty()) {
-            // Do deferred intrinsification of node intrinsics
-            new CanonicalizerPhase(true).apply(snippetCopy, phaseContext);
-            new NodeIntrinsificationPhase(providers).apply(snippetCopy);
-            new CanonicalizerPhase(true).apply(snippetCopy, phaseContext);
+            providers.getReplacements().prepareSnippetCopyAfterInstantiation(snippetCopy);
         }
-        NodeIntrinsificationVerificationPhase.verify(snippetCopy);
 
         // Gather the template parameters
         parameters = new Object[parameterCount];
@@ -585,13 +580,12 @@
 
         // Perform lowering on the snippet
         snippetCopy.setGuardsStage(args.cacheKey.guardsStage);
-        Debug.scope("LoweringSnippetTemplate", snippetCopy, new Runnable() {
-
-            public void run() {
-                PhaseContext c = new PhaseContext(providers, new Assumptions(false));
-                new LoweringPhase(new CanonicalizerPhase(true)).apply(snippetCopy, c);
-            }
-        });
+        try (Scope s = Debug.scope("LoweringSnippetTemplate", snippetCopy)) {
+            PhaseContext c = new PhaseContext(providers, new Assumptions(false));
+            new LoweringPhase(new CanonicalizerPhase(true)).apply(snippetCopy, c);
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
 
         // Remove all frame states from snippet graph. Snippets must be atomic (i.e. free
         // of side-effects that prevent deoptimizing to a point before the snippet).
@@ -856,25 +850,43 @@
      */
     public static final UsageReplacer DEFAULT_REPLACER = new UsageReplacer() {
 
+        private LocationIdentity getLocationIdentity(Node node) {
+            if (node instanceof MemoryAccess) {
+                return ((MemoryAccess) node).getLocationIdentity();
+            } else if (node instanceof MemoryProxy) {
+                return ((MemoryProxy) node).getLocationIdentity();
+            } else if (node instanceof MemoryPhiNode) {
+                return ((MemoryPhiNode) node).getLocationIdentity();
+            } else {
+                return null;
+            }
+        }
+
         @Override
         public void replace(ValueNode oldNode, ValueNode newNode, MemoryMapNode mmap) {
-            oldNode.replaceAtUsages(newNode);
-            if (mmap == null || newNode == null) {
-                return;
-            }
-            for (Node usage : newNode.usages().snapshot()) {
-                if (usage instanceof FloatingReadNode && ((FloatingReadNode) usage).getLastLocationAccess() == newNode) {
-                    assert newNode.graph().isAfterFloatingReadPhase();
+            if (mmap != null && newNode != null) {
+                for (Node usage : oldNode.usages().snapshot()) {
+                    LocationIdentity identity = getLocationIdentity(usage);
+                    if (identity != null && identity != LocationIdentity.FINAL_LOCATION) {
+                        // lastLocationAccess points into the snippet graph. find a proper
+                        // MemoryCheckPoint inside the snippet graph
+                        MemoryNode lastAccess = mmap.getLastLocationAccess(identity);
 
-                    // lastLocationAccess points into the snippet graph. find a proper
-                    // MemoryCheckPoint inside the snippet graph
-                    FloatingReadNode read = (FloatingReadNode) usage;
-                    Node lastAccess = mmap.getLastLocationAccess(read.location().getLocationIdentity());
-
-                    assert lastAccess != null : "no mapping found for lowerable node " + oldNode + ". (No node in the snippet kill the same location as the lowerable node?)";
-                    read.setLastLocationAccess(lastAccess);
+                        assert lastAccess != null : "no mapping found for lowerable node " + oldNode + ". (No node in the snippet kill the same location as the lowerable node?)";
+                        if (usage instanceof MemoryAccess) {
+                            MemoryAccess access = (MemoryAccess) usage;
+                            if (access.getLastLocationAccess() == oldNode) {
+                                assert newNode.graph().isAfterFloatingReadPhase();
+                                access.setLastLocationAccess(lastAccess);
+                            }
+                        } else {
+                            assert usage instanceof MemoryProxy || usage instanceof MemoryPhiNode;
+                            usage.replaceFirstInput(oldNode, lastAccess.asNode());
+                        }
+                    }
                 }
             }
+            oldNode.replaceAtUsages(newNode);
         }
     };
 
@@ -926,8 +938,8 @@
 
     private class DuplicateMapper extends MemoryMapNode {
 
-        Map<Node, Node> duplicates;
-        StartNode replaceeStart;
+        private final Map<Node, Node> duplicates;
+        @Input private StartNode replaceeStart;
 
         public DuplicateMapper(Map<Node, Node> duplicates, StartNode replaceeStart) {
             this.duplicates = duplicates;
@@ -935,14 +947,14 @@
         }
 
         @Override
-        public Node getLastLocationAccess(LocationIdentity locationIdentity) {
+        public MemoryNode getLastLocationAccess(LocationIdentity locationIdentity) {
             assert memoryMap != null : "no memory map stored for this snippet graph (snippet doesn't have a ReturnNode?)";
-            Node lastLocationAccess = memoryMap.getLastLocationAccess(locationIdentity);
+            MemoryNode lastLocationAccess = memoryMap.getLastLocationAccess(locationIdentity);
             assert lastLocationAccess != null;
             if (lastLocationAccess instanceof StartNode) {
                 return replaceeStart;
             } else {
-                return duplicates.get(lastLocationAccess);
+                return (MemoryNode) duplicates.get(ValueNodeUtil.asNode(lastLocationAccess));
             }
         }
     }
@@ -1005,7 +1017,7 @@
 
             // Replace all usages of the replacee with the value returned by the snippet
             ValueNode returnValue = null;
-            if (returnNode != null) {
+            if (returnNode != null && !(replacee instanceof ControlSinkNode)) {
                 if (returnNode.result() instanceof LocalNode) {
                     returnValue = (ValueNode) replacements.get(returnNode.result());
                 } else if (returnNode.result() != null) {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Mon Dec 02 12:45:18 2013 +0100
@@ -28,6 +28,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
@@ -37,7 +38,7 @@
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
 
-public class MacroNode extends AbstractStateSplit implements Lowerable, MemoryCheckpoint.Single {
+public class MacroNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single {
 
     @Input protected final NodeInputList<ValueNode> arguments;
 
@@ -96,14 +97,12 @@
      */
     protected StructuredGraph lowerReplacement(final StructuredGraph replacementGraph, LoweringTool tool) {
         replacementGraph.setGuardsStage(graph().getGuardsStage());
-        final PhaseContext c = new PhaseContext(tool.getMetaAccess(), tool.getCodeCache(), tool.getConstantReflection(), tool.getForeignCalls(), tool.getLowerer(), tool.assumptions(),
-                        tool.getReplacements());
-        Debug.scope("LoweringReplacement", replacementGraph, new Runnable() {
-
-            public void run() {
-                new LoweringPhase(new CanonicalizerPhase(true)).apply(replacementGraph, c);
-            }
-        });
+        final PhaseContext c = new PhaseContext(tool.getMetaAccess(), tool.getConstantReflection(), tool.getLowerer(), tool.getReplacements(), tool.assumptions());
+        try (Scope s = Debug.scope("LoweringReplacement", replacementGraph)) {
+            new LoweringPhase(new CanonicalizerPhase(true)).apply(replacementGraph, c);
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
         return replacementGraph;
     }
 
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java	Mon Dec 02 12:45:18 2013 +0100
@@ -23,7 +23,6 @@
 package com.oracle.graal.truffle.test;
 
 import java.util.*;
-import java.util.concurrent.*;
 
 import org.junit.*;
 
@@ -31,6 +30,7 @@
 import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.compiler.test.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.java.*;
 import com.oracle.graal.loop.*;
 import com.oracle.graal.nodes.*;
@@ -102,56 +102,53 @@
             compilable.call(null, arguments);
         } while (compilable.inline());
 
-        StructuredGraph graph = Debug.scope("TruffleCompilation", new TruffleDebugJavaMethod(compilable), new Callable<StructuredGraph>() {
+        try (Scope s = Debug.scope("TruffleCompilation", new TruffleDebugJavaMethod(compilable))) {
+
+            StructuredGraph resultGraph = partialEvaluator.createGraph(compilable, assumptions);
+            CanonicalizerPhase canonicalizer = new CanonicalizerPhase(canonicalizeReads);
+            PhaseContext context = new PhaseContext(getProviders(), assumptions);
+
+            if (resultGraph.hasLoops()) {
+                boolean unrolled;
+                do {
+                    unrolled = false;
+                    LoopsData loopsData = new LoopsData(resultGraph);
+                    loopsData.detectedCountedLoops();
+                    for (LoopEx ex : innerLoopsFirst(loopsData.countedLoops())) {
+                        if (ex.counted().isConstantMaxTripCount()) {
+                            long constant = ex.counted().constantMaxTripCount();
+                            if (constant <= UNROLL_LIMIT) {
+                                LoopTransformations.fullUnroll(ex, context, canonicalizer);
+                                Debug.dump(resultGraph, "After loop unrolling %d times", constant);
+
+                                canonicalizer.apply(resultGraph, context);
+                                unrolled = true;
+                                break;
+                            }
+                        }
+                    }
+                } while (unrolled);
+            }
+
+            new DeadCodeEliminationPhase().apply(resultGraph);
+            new PartialEscapePhase(true, canonicalizer).apply(resultGraph, context);
+
+            return resultGraph;
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+
+    private static List<LoopEx> innerLoopsFirst(Collection<LoopEx> loops) {
+        ArrayList<LoopEx> sortedLoops = new ArrayList<>(loops);
+        Collections.sort(sortedLoops, new Comparator<LoopEx>() {
 
             @Override
-            public StructuredGraph call() {
-                StructuredGraph resultGraph = partialEvaluator.createGraph(compilable, assumptions);
-                CanonicalizerPhase canonicalizer = new CanonicalizerPhase(canonicalizeReads);
-                PhaseContext context = new PhaseContext(getProviders(), assumptions);
-
-                if (resultGraph.hasLoops()) {
-                    boolean unrolled;
-                    do {
-                        unrolled = false;
-                        LoopsData loopsData = new LoopsData(resultGraph);
-                        loopsData.detectedCountedLoops();
-                        for (LoopEx ex : innerLoopsFirst(loopsData.countedLoops())) {
-                            if (ex.counted().isConstantMaxTripCount()) {
-                                long constant = ex.counted().constantMaxTripCount();
-                                if (constant <= UNROLL_LIMIT) {
-                                    LoopTransformations.fullUnroll(ex, context, canonicalizer);
-                                    Debug.dump(resultGraph, "After loop unrolling %d times", constant);
-
-                                    canonicalizer.apply(resultGraph, context);
-                                    unrolled = true;
-                                    break;
-                                }
-                            }
-                        }
-                    } while (unrolled);
-                }
-
-                new DeadCodeEliminationPhase().apply(resultGraph);
-                new PartialEscapePhase(true, canonicalizer).apply(resultGraph, context);
-
-                return resultGraph;
-            }
-
-            private List<LoopEx> innerLoopsFirst(Collection<LoopEx> loops) {
-                ArrayList<LoopEx> sortedLoops = new ArrayList<>(loops);
-                Collections.sort(sortedLoops, new Comparator<LoopEx>() {
-
-                    @Override
-                    public int compare(LoopEx o1, LoopEx o2) {
-                        return o2.lirLoop().depth - o1.lirLoop().depth;
-                    }
-                });
-                return sortedLoops;
+            public int compare(LoopEx o1, LoopEx o2) {
+                return o2.lirLoop().depth - o1.lirLoop().depth;
             }
         });
-
-        return graph;
+        return sortedLoops;
     }
 
     protected void removeFrameStates(StructuredGraph graph) {
@@ -163,44 +160,42 @@
         new DeadCodeEliminationPhase().apply(graph);
     }
 
+    @SuppressWarnings("deprecation")
     protected StructuredGraph parseForComparison(final String methodName) {
 
-        StructuredGraph graphResult = Debug.scope("Truffle", new DebugDumpScope("Comparison: " + methodName), new Callable<StructuredGraph>() {
+        try (Scope s = Debug.scope("Truffle", new DebugDumpScope("Comparison: " + methodName))) {
+            Assumptions assumptions = new Assumptions(false);
+            StructuredGraph graph = parse(methodName);
+            PhaseContext context = new PhaseContext(getProviders(), assumptions);
+            CanonicalizerPhase canonicalizer = new CanonicalizerPhase(true);
+            canonicalizer.apply(graph, context);
 
-            @SuppressWarnings("deprecation")
-            public StructuredGraph call() {
-                Assumptions assumptions = new Assumptions(false);
-                StructuredGraph graph = parse(methodName);
-                PhaseContext context = new PhaseContext(getProviders(), assumptions);
-                CanonicalizerPhase canonicalizer = new CanonicalizerPhase(true);
-                canonicalizer.apply(graph, context);
-
-                // Additional inlining.
-                final PhasePlan plan = new PhasePlan();
-                GraphBuilderPhase graphBuilderPhase = new GraphBuilderPhase(getMetaAccess(), getForeignCalls(), GraphBuilderConfiguration.getEagerDefault(), TruffleCompilerImpl.Optimizations);
-                plan.addPhase(PhasePosition.AFTER_PARSING, graphBuilderPhase);
-                canonicalizer.addToPhasePlan(plan, context);
-                plan.addPhase(PhasePosition.AFTER_PARSING, new DeadCodeEliminationPhase());
+            // Additional inlining.
+            final PhasePlan plan = new PhasePlan();
+            GraphBuilderPhase graphBuilderPhase = new GraphBuilderPhase(getMetaAccess(), getForeignCalls(), GraphBuilderConfiguration.getEagerDefault(), TruffleCompilerImpl.Optimizations);
+            plan.addPhase(PhasePosition.AFTER_PARSING, graphBuilderPhase);
+            canonicalizer.addToPhasePlan(plan, context);
+            plan.addPhase(PhasePosition.AFTER_PARSING, new DeadCodeEliminationPhase());
 
-                new ConvertDeoptimizeToGuardPhase().apply(graph);
-                canonicalizer.apply(graph, context);
-                new DeadCodeEliminationPhase().apply(graph);
+            new ConvertDeoptimizeToGuardPhase().apply(graph);
+            canonicalizer.apply(graph, context);
+            new DeadCodeEliminationPhase().apply(graph);
 
-                HighTierContext highTierContext = new HighTierContext(getProviders(), assumptions, null, plan, OptimisticOptimizations.NONE);
-                InliningPhase inliningPhase = new InliningPhase(canonicalizer);
-                inliningPhase.apply(graph, highTierContext);
-                removeFrameStates(graph);
+            HighTierContext highTierContext = new HighTierContext(getProviders(), assumptions, null, plan, OptimisticOptimizations.NONE);
+            InliningPhase inliningPhase = new InliningPhase(canonicalizer);
+            inliningPhase.apply(graph, highTierContext);
+            removeFrameStates(graph);
 
-                new ConvertDeoptimizeToGuardPhase().apply(graph);
-                canonicalizer.apply(graph, context);
-                new DeadCodeEliminationPhase().apply(graph);
+            new ConvertDeoptimizeToGuardPhase().apply(graph);
+            canonicalizer.apply(graph, context);
+            new DeadCodeEliminationPhase().apply(graph);
 
-                new LoweringPhase(new CanonicalizerPhase(true)).apply(graph, context);
-                canonicalizer.apply(graph, context);
-                new DeadCodeEliminationPhase().apply(graph);
-                return graph;
-            }
-        });
-        return graphResult;
+            new LoweringPhase(new CanonicalizerPhase(true)).apply(graph, context);
+            canonicalizer.apply(graph, context);
+            new DeadCodeEliminationPhase().apply(graph);
+            return graph;
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
     }
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/FrameWithoutBoxing.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/FrameWithoutBoxing.java	Mon Dec 02 12:45:18 2013 +0100
@@ -239,7 +239,9 @@
         int slotIndex = slot.getIndex();
         if (slotIndex >= getTags().length) {
             CompilerDirectives.transferToInterpreter();
-            resize();
+            if (!resize()) {
+                throw new IllegalArgumentException(String.format("The frame slot '%s' is not known by the frame descriptor.", slot));
+            }
         }
         getTags()[slotIndex] = (byte) accessKind.ordinal();
     }
@@ -248,7 +250,9 @@
         int slotIndex = slot.getIndex();
         if (slotIndex >= getTags().length) {
             CompilerDirectives.transferToInterpreter();
-            resize();
+            if (!resize()) {
+                throw new IllegalArgumentException(String.format("The frame slot '%s' is not known by the frame descriptor.", slot));
+            }
         }
         byte tag = this.getTags()[slotIndex];
         if (tag != accessKind.ordinal()) {
@@ -289,7 +293,7 @@
         }
     }
 
-    private void resize() {
+    private boolean resize() {
         int oldSize = tags.length;
         int newSize = descriptor.getSize();
         if (newSize > oldSize) {
@@ -297,7 +301,9 @@
             Arrays.fill(locals, oldSize, newSize, descriptor.getTypeConversion().getDefaultValue());
             primitiveLocals = Arrays.copyOf(primitiveLocals, newSize);
             tags = Arrays.copyOf(tags, newSize);
+            return true;
         }
+        return false;
     }
 
     private byte getTag(FrameSlot slot) {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Mon Dec 02 12:45:18 2013 +0100
@@ -32,6 +32,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.debug.internal.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Graph.Mark;
@@ -80,7 +81,6 @@
         this.skippedExceptionTypes = TruffleCompilerImpl.getSkippedExceptionTypes(providers.getMetaAccess());
         this.cache = runtime.getGraphCache();
         this.truffleCache = truffleCache;
-
         try {
             executeHelperMethod = providers.getMetaAccess().lookupJavaMethod(OptimizedCallTarget.class.getDeclaredMethod("executeHelper", PackedFrame.class, Arguments.class));
         } catch (NoSuchMethodException ex) {
@@ -105,84 +105,86 @@
 
         final StructuredGraph graph = new StructuredGraph(executeHelperMethod);
 
-        Debug.scope("createGraph", graph, new Runnable() {
+        try (Scope s = Debug.scope("createGraph", graph)) {
+            new GraphBuilderPhase(providers.getMetaAccess(), providers.getForeignCalls(), config, TruffleCompilerImpl.Optimizations).apply(graph);
 
-            @Override
-            public void run() {
-                new GraphBuilderPhase(providers.getMetaAccess(), providers.getForeignCalls(), config, TruffleCompilerImpl.Optimizations).apply(graph);
+            // Replace thisNode with constant.
+            LocalNode thisNode = graph.getLocal(0);
+            thisNode.replaceAndDelete(ConstantNode.forObject(node, providers.getMetaAccess(), graph));
 
-                // Replace thisNode with constant.
-                LocalNode thisNode = graph.getLocal(0);
-                thisNode.replaceAndDelete(ConstantNode.forObject(node, providers.getMetaAccess(), graph));
+            // Canonicalize / constant propagate.
+            PhaseContext baseContext = new PhaseContext(providers, assumptions);
+            canonicalizer.apply(graph, baseContext);
 
-                // Canonicalize / constant propagate.
-                PhaseContext baseContext = new PhaseContext(providers, assumptions);
-                canonicalizer.apply(graph, baseContext);
+            // Intrinsify methods.
+            new ReplaceIntrinsicsPhase(providers.getReplacements()).apply(graph);
 
-                // Intrinsify methods.
-                new ReplaceIntrinsicsPhase(providers.getReplacements()).apply(graph);
+            NewFrameNode newFrameNode = graph.getNodes(NewFrameNode.class).first();
+            if (newFrameNode == null) {
+                throw GraalInternalError.shouldNotReachHere("frame not found");
+            }
 
-                NewFrameNode newFrameNode = graph.getNodes(NewFrameNode.class).first();
-                if (newFrameNode == null) {
-                    throw GraalInternalError.shouldNotReachHere("frame not found");
-                }
+            Debug.dump(graph, "Before inlining");
 
-                Debug.dump(graph, "Before inlining");
-
-                // Make sure frame does not escape.
-                expandTree(graph, assumptions);
+            // Make sure frame does not escape.
+            expandTree(graph, assumptions);
 
-                if (Thread.interrupted()) {
-                    return;
-                }
+            if (Thread.interrupted()) {
+                return graph;
+            }
 
-                new VerifyFrameDoesNotEscapePhase().apply(graph, false);
+            new VerifyFrameDoesNotEscapePhase().apply(graph, false);
 
-                if (TraceTruffleCompilationDetails.getValue() && constantReceivers != null) {
-                    DebugHistogram histogram = Debug.createHistogram("Expanded Truffle Nodes");
-                    for (Constant c : constantReceivers) {
-                        histogram.add(c.asObject().getClass().getSimpleName());
-                    }
-                    new DebugHistogramAsciiPrinter(TTY.out().out()).print(histogram);
+            if (TraceTruffleCompilationDetails.getValue() && constantReceivers != null) {
+                DebugHistogram histogram = Debug.createHistogram("Expanded Truffle Nodes");
+                for (Constant c : constantReceivers) {
+                    histogram.add(c.asObject().getClass().getSimpleName());
                 }
+                new DebugHistogramAsciiPrinter(TTY.out().out()).print(histogram);
+            }
 
-                // Additional inlining.
-                final PhasePlan plan = new PhasePlan();
-                canonicalizer.apply(graph, baseContext);
-                HighTierContext tierContext = new HighTierContext(providers, assumptions, cache, plan, OptimisticOptimizations.NONE);
-
-                for (NeverPartOfCompilationNode neverPartOfCompilationNode : graph.getNodes(NeverPartOfCompilationNode.class)) {
-                    Throwable exception = new VerificationError(neverPartOfCompilationNode.getMessage());
-                    throw GraphUtil.approxSourceException(neverPartOfCompilationNode, exception);
-                }
+            // Additional inlining.
+            final PhasePlan plan = new PhasePlan();
+            canonicalizer.apply(graph, baseContext);
+            HighTierContext tierContext = new HighTierContext(providers, assumptions, cache, plan, OptimisticOptimizations.NONE);
 
-                // EA frame and clean up.
-                new PartialEscapePhase(true, canonicalizer).apply(graph, tierContext);
-                new VerifyNoIntrinsicsLeftPhase().apply(graph, false);
-                for (MaterializeFrameNode materializeNode : graph.getNodes(MaterializeFrameNode.class).snapshot()) {
-                    materializeNode.replaceAtUsages(materializeNode.getFrame());
-                    graph.removeFixed(materializeNode);
-                }
-                for (VirtualObjectNode virtualObjectNode : graph.getNodes(VirtualObjectNode.class)) {
-                    if (virtualObjectNode instanceof VirtualOnlyInstanceNode) {
-                        VirtualOnlyInstanceNode virtualOnlyInstanceNode = (VirtualOnlyInstanceNode) virtualObjectNode;
-                        virtualOnlyInstanceNode.setAllowMaterialization(true);
-                    } else if (virtualObjectNode instanceof VirtualInstanceNode) {
-                        VirtualInstanceNode virtualInstanceNode = (VirtualInstanceNode) virtualObjectNode;
-                        ResolvedJavaType type = virtualInstanceNode.type();
-                        if (type.getAnnotation(CompilerDirectives.ValueType.class) != null) {
-                            virtualInstanceNode.setIdentity(false);
-                        }
+            for (NeverPartOfCompilationNode neverPartOfCompilationNode : graph.getNodes(NeverPartOfCompilationNode.class)) {
+                Throwable exception = new VerificationError(neverPartOfCompilationNode.getMessage());
+                throw GraphUtil.approxSourceException(neverPartOfCompilationNode, exception);
+            }
+
+            // EA frame and clean up.
+            new PartialEscapePhase(true, canonicalizer).apply(graph, tierContext);
+            new VerifyNoIntrinsicsLeftPhase().apply(graph, false);
+            for (MaterializeFrameNode materializeNode : graph.getNodes(MaterializeFrameNode.class).snapshot()) {
+                materializeNode.replaceAtUsages(materializeNode.getFrame());
+                graph.removeFixed(materializeNode);
+            }
+            for (VirtualObjectNode virtualObjectNode : graph.getNodes(VirtualObjectNode.class)) {
+                if (virtualObjectNode instanceof VirtualOnlyInstanceNode) {
+                    VirtualOnlyInstanceNode virtualOnlyInstanceNode = (VirtualOnlyInstanceNode) virtualObjectNode;
+                    virtualOnlyInstanceNode.setAllowMaterialization(true);
+                } else if (virtualObjectNode instanceof VirtualInstanceNode) {
+                    VirtualInstanceNode virtualInstanceNode = (VirtualInstanceNode) virtualObjectNode;
+                    ResolvedJavaType type = virtualInstanceNode.type();
+                    if (type.getAnnotation(CompilerDirectives.ValueType.class) != null) {
+                        virtualInstanceNode.setIdentity(false);
                     }
                 }
             }
-        });
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
 
         return graph;
     }
 
     private void expandTree(StructuredGraph graph, Assumptions assumptions) {
         PhaseContext phaseContext = new PhaseContext(providers, assumptions);
+        TruffleExpansionLogger expansionLogger = null;
+        if (TraceTruffleExpansion.getValue()) {
+            expansionLogger = new TruffleExpansionLogger(graph);
+        }
         boolean changed;
         do {
             changed = false;
@@ -213,7 +215,13 @@
                     if (inlineGraph != null) {
                         int nodeCountBefore = graph.getNodeCount();
                         Mark mark = graph.getMark();
-                        InliningUtil.inline(methodCallTargetNode.invoke(), inlineGraph, false);
+                        if (TraceTruffleExpansion.getValue()) {
+                            expansionLogger.preExpand(methodCallTargetNode, inlineGraph);
+                        }
+                        Map<Node, Node> inlined = InliningUtil.inline(methodCallTargetNode.invoke(), inlineGraph, false);
+                        if (TraceTruffleExpansion.getValue()) {
+                            expansionLogger.postExpand(inlined);
+                        }
                         if (Debug.isDumpEnabled()) {
                             int nodeCountAfter = graph.getNodeCount();
                             Debug.dump(graph, "After inlining %s %+d (%d)", methodCallTargetNode.targetMethod().toString(), nodeCountAfter - nodeCountBefore, nodeCountAfter);
@@ -232,6 +240,10 @@
                 }
             }
         } while (changed);
+
+        if (TraceTruffleExpansion.getValue()) {
+            expansionLogger.print();
+        }
     }
 
     private StructuredGraph parseGraph(final ResolvedJavaMethod targetMethod, final NodeInputList<ValueNode> arguments, final Assumptions assumptions, final PhaseContext phaseContext) {
@@ -254,44 +266,44 @@
                     local.replaceAndDelete(ConstantNode.forConstant(constant, phaseContext.getMetaAccess(), graphCopy));
                 }
             }
-            Debug.scope("TruffleUnrollLoop", targetMethod, new Runnable() {
-
-                @Override
-                public void run() {
+            try (Scope s = Debug.scope("TruffleUnrollLoop", targetMethod)) {
 
-                    canonicalizer.applyIncremental(graphCopy, phaseContext, modifiedNodes);
-                    boolean unrolled;
-                    do {
-                        unrolled = false;
-                        LoopsData loopsData = new LoopsData(graphCopy);
-                        loopsData.detectedCountedLoops();
-                        for (LoopEx ex : innerLoopsFirst(loopsData.countedLoops())) {
-                            if (ex.counted().isConstantMaxTripCount()) {
-                                long constant = ex.counted().constantMaxTripCount();
-                                LoopTransformations.fullUnroll(ex, phaseContext, canonicalizer);
-                                Debug.dump(graphCopy, "After loop unrolling %d times", constant);
-                                unrolled = true;
-                                break;
-                            }
+                canonicalizer.applyIncremental(graphCopy, phaseContext, modifiedNodes);
+                boolean unrolled;
+                do {
+                    unrolled = false;
+                    LoopsData loopsData = new LoopsData(graphCopy);
+                    loopsData.detectedCountedLoops();
+                    for (LoopEx ex : innerLoopsFirst(loopsData.countedLoops())) {
+                        if (ex.counted().isConstantMaxTripCount()) {
+                            long constant = ex.counted().constantMaxTripCount();
+                            LoopTransformations.fullUnroll(ex, phaseContext, canonicalizer);
+                            Debug.dump(graphCopy, "After loop unrolling %d times", constant);
+                            unrolled = true;
+                            break;
                         }
-                    } while (unrolled);
-                }
-
-                private List<LoopEx> innerLoopsFirst(Collection<LoopEx> loops) {
-                    ArrayList<LoopEx> sortedLoops = new ArrayList<>(loops);
-                    Collections.sort(sortedLoops, new Comparator<LoopEx>() {
+                    }
+                } while (unrolled);
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            }
 
-                        @Override
-                        public int compare(LoopEx o1, LoopEx o2) {
-                            return o2.lirLoop().depth - o1.lirLoop().depth;
-                        }
-                    });
-                    return sortedLoops;
-                }
-            });
             return graphCopy;
         } else {
             return graph;
         }
     }
+
+    private static List<LoopEx> innerLoopsFirst(Collection<LoopEx> loops) {
+        ArrayList<LoopEx> sortedLoops = new ArrayList<>(loops);
+        Collections.sort(sortedLoops, new Comparator<LoopEx>() {
+
+            @Override
+            public int compare(LoopEx o1, LoopEx o2) {
+                return o2.lirLoop().depth - o1.lirLoop().depth;
+            }
+        });
+        return sortedLoops;
+    }
+
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluatorCanonicalizer.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluatorCanonicalizer.java	Mon Dec 02 12:45:18 2013 +0100
@@ -53,7 +53,7 @@
                                 loadFieldNode.field().getAnnotation(CompilerDirectives.CompilationFinal.class) != null) {
                     Constant constant = loadFieldNode.field().readValue(loadFieldNode.object().asConstant());
                     assert verifyFieldValue(loadFieldNode.field(), constant);
-                    return ConstantNode.forConstant(constant, metaAccess, node.graph());
+                    return ConstantNode.forConstant(constant, metaAccess, loadFieldNode.graph());
                 }
             }
         } else if (node instanceof LoadIndexedNode) {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java	Mon Dec 02 12:45:18 2013 +0100
@@ -26,13 +26,13 @@
 
 import java.lang.reflect.*;
 import java.util.*;
-import java.util.concurrent.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
+import com.oracle.graal.graph.Graph.Mark;
 import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.Graph.Mark;
 import com.oracle.graal.graph.Node;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.java.*;
@@ -91,102 +91,101 @@
         }
 
         cache.put(key, markerGraph);
-        resultGraph = Debug.scope("TruffleCache", new Object[]{providers.getMetaAccess(), method}, new Callable<StructuredGraph>() {
+        try (Scope s = Debug.scope("TruffleCache", new Object[]{providers.getMetaAccess(), method})) {
+
+            final StructuredGraph graph = new StructuredGraph(method);
+            PhaseContext phaseContext = new PhaseContext(providers, new Assumptions(false));
+            new GraphBuilderPhase(phaseContext.getMetaAccess(), providers.getForeignCalls(), config, optimisticOptimizations).apply(graph);
+
+            for (LocalNode l : graph.getNodes(LocalNode.class)) {
+                if (l.kind() == Kind.Object) {
+                    ValueNode actualArgument = arguments.get(l.index());
+                    l.setStamp(l.stamp().join(actualArgument.stamp()));
+                }
+            }
+
+            // Intrinsify methods.
+            new ReplaceIntrinsicsPhase(providers.getReplacements()).apply(graph);
 
-            public StructuredGraph call() {
+            // Convert deopt to guards.
+            new ConvertDeoptimizeToGuardPhase().apply(graph);
+
+            CanonicalizerPhase canonicalizerPhase = new CanonicalizerPhase(!AOTCompilation.getValue());
+            PartialEscapePhase partialEscapePhase = new PartialEscapePhase(false, canonicalizerPhase);
+
+            Mark mark = null;
+            while (true) {
+
+                partialEscapePhase.apply(graph, phaseContext);
+
+                // Conditional elimination.
+                ConditionalEliminationPhase conditionalEliminationPhase = new ConditionalEliminationPhase(phaseContext.getMetaAccess());
+                conditionalEliminationPhase.apply(graph);
+
+                // Canonicalize / constant propagate.
+                canonicalizerPhase.apply(graph, phaseContext);
 
-                final StructuredGraph graph = new StructuredGraph(method);
-                PhaseContext phaseContext = new PhaseContext(providers, new Assumptions(false));
-                new GraphBuilderPhase(phaseContext.getMetaAccess(), providers.getForeignCalls(), config, optimisticOptimizations).apply(graph);
-
-                for (LocalNode l : graph.getNodes(LocalNode.class)) {
-                    if (l.kind() == Kind.Object) {
-                        ValueNode actualArgument = arguments.get(l.index());
-                        l.setStamp(l.stamp().join(actualArgument.stamp()));
+                boolean inliningProgress = false;
+                for (MethodCallTargetNode methodCallTarget : graph.getNodes(MethodCallTargetNode.class)) {
+                    if (graph.getMark().equals(mark)) {
+                        // Make sure macro substitutions such as
+                        // CompilerDirectives.transferToInterpreter get processed first.
+                        for (Node newNode : graph.getNewNodes(mark)) {
+                            if (newNode instanceof MethodCallTargetNode) {
+                                MethodCallTargetNode methodCallTargetNode = (MethodCallTargetNode) newNode;
+                                Class<? extends FixedWithNextNode> macroSubstitution = providers.getReplacements().getMacroSubstitution(methodCallTargetNode.targetMethod());
+                                if (macroSubstitution != null) {
+                                    InliningUtil.inlineMacroNode(methodCallTargetNode.invoke(), methodCallTargetNode.targetMethod(), methodCallTargetNode.graph(), macroSubstitution);
+                                } else {
+                                    tryCutOffRuntimeExceptions(methodCallTargetNode);
+                                }
+                            }
+                        }
+                        mark = graph.getMark();
+                    }
+                    if (methodCallTarget.isAlive() && methodCallTarget.invoke() != null && shouldInline(methodCallTarget)) {
+                        inliningProgress = true;
+                        List<Node> canonicalizerUsages = new ArrayList<Node>();
+                        for (Node n : methodCallTarget.invoke().asNode().usages()) {
+                            if (n instanceof Canonicalizable) {
+                                canonicalizerUsages.add(n);
+                            }
+                        }
+                        List<ValueNode> argumentSnapshot = methodCallTarget.arguments().snapshot();
+                        Mark beforeInvokeMark = graph.getMark();
+                        expandInvoke(methodCallTarget);
+                        for (Node arg : argumentSnapshot) {
+                            if (arg != null && arg.recordsUsages()) {
+                                for (Node argUsage : arg.usages()) {
+                                    if (graph.isNew(beforeInvokeMark, argUsage) && argUsage instanceof Canonicalizable) {
+                                        canonicalizerUsages.add(argUsage);
+                                    }
+                                }
+                            }
+                        }
+                        canonicalizerPhase.applyIncremental(graph, phaseContext, canonicalizerUsages);
                     }
                 }
 
-                // Intrinsify methods.
-                new ReplaceIntrinsicsPhase(providers.getReplacements()).apply(graph);
-
                 // Convert deopt to guards.
                 new ConvertDeoptimizeToGuardPhase().apply(graph);
 
-                CanonicalizerPhase canonicalizerPhase = new CanonicalizerPhase(!AOTCompilation.getValue());
-                PartialEscapePhase partialEscapePhase = new PartialEscapePhase(false, canonicalizerPhase);
-
-                Mark mark = null;
-                while (true) {
+                new EarlyReadEliminationPhase(canonicalizerPhase).apply(graph, phaseContext);
 
-                    partialEscapePhase.apply(graph, phaseContext);
-
-                    // Conditional elimination.
-                    ConditionalEliminationPhase conditionalEliminationPhase = new ConditionalEliminationPhase(phaseContext.getMetaAccess());
-                    conditionalEliminationPhase.apply(graph);
-
-                    // Canonicalize / constant propagate.
-                    canonicalizerPhase.apply(graph, phaseContext);
+                if (!inliningProgress) {
+                    break;
+                }
+            }
 
-                    boolean inliningProgress = false;
-                    for (MethodCallTargetNode methodCallTarget : graph.getNodes(MethodCallTargetNode.class)) {
-                        if (graph.getMark().equals(mark)) {
-                            // Make sure macro substitutions such as
-                            // CompilerDirectives.transferToInterpreter get processed first.
-                            for (Node newNode : graph.getNewNodes(mark)) {
-                                if (newNode instanceof MethodCallTargetNode) {
-                                    MethodCallTargetNode methodCallTargetNode = (MethodCallTargetNode) newNode;
-                                    Class<? extends FixedWithNextNode> macroSubstitution = providers.getReplacements().getMacroSubstitution(methodCallTargetNode.targetMethod());
-                                    if (macroSubstitution != null) {
-                                        InliningUtil.inlineMacroNode(methodCallTargetNode.invoke(), methodCallTargetNode.targetMethod(), methodCallTargetNode.graph(), macroSubstitution);
-                                    } else {
-                                        tryCutOffRuntimeExceptions(methodCallTargetNode);
-                                    }
-                                }
-                            }
-                            mark = graph.getMark();
-                        }
-                        if (methodCallTarget.isAlive() && methodCallTarget.invoke() != null && shouldInline(methodCallTarget)) {
-                            inliningProgress = true;
-                            List<Node> canonicalizerUsages = new ArrayList<Node>();
-                            for (Node n : methodCallTarget.invoke().asNode().usages()) {
-                                if (n instanceof Canonicalizable) {
-                                    canonicalizerUsages.add(n);
-                                }
-                            }
-                            List<ValueNode> argumentSnapshot = methodCallTarget.arguments().snapshot();
-                            Mark beforeInvokeMark = graph.getMark();
-                            expandInvoke(methodCallTarget);
-                            for (Node arg : argumentSnapshot) {
-                                if (arg != null && arg.recordsUsages()) {
-                                    for (Node argUsage : arg.usages()) {
-                                        if (graph.isNew(beforeInvokeMark, argUsage) && argUsage instanceof Canonicalizable) {
-                                            canonicalizerUsages.add(argUsage);
-                                        }
-                                    }
-                                }
-                            }
-                            canonicalizerPhase.applyIncremental(graph, phaseContext, canonicalizerUsages);
-                        }
-                    }
+            cache.put(key, graph);
+            if (TruffleCompilerOptions.TraceTruffleCacheDetails.getValue()) {
+                TTY.println(String.format("[truffle] added to graph cache method %s with %d nodes.", method, graph.getNodeCount()));
+            }
+            return graph;
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
 
-                    // Convert deopt to guards.
-                    new ConvertDeoptimizeToGuardPhase().apply(graph);
-
-                    new EarlyReadEliminationPhase(canonicalizerPhase).apply(graph, phaseContext);
-
-                    if (!inliningProgress) {
-                        break;
-                    }
-                }
-
-                if (TruffleCompilerOptions.TraceTruffleCacheDetails.getValue()) {
-                    TTY.println(String.format("[truffle] added to graph cache method %s with %d nodes.", method, graph.getNodeCount()));
-                }
-                return graph;
-            }
-        });
-        cache.put(key, resultGraph);
-        return resultGraph;
     }
 
     private void expandInvoke(MethodCallTargetNode methodCallTargetNode) {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Mon Dec 02 12:45:18 2013 +0100
@@ -38,6 +38,7 @@
 import com.oracle.graal.compiler.CompilerThreadFactory.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.debug.internal.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.*;
@@ -109,21 +110,16 @@
     }
 
     public Future<InstalledCode> compile(final OptimizedCallTarget compilable) {
-        Future<InstalledCode> future = compileQueue.submit(new Callable<InstalledCode>() {
-
+        return compileQueue.submit(new Callable<InstalledCode>() {
             @Override
             public InstalledCode call() throws Exception {
-                Object[] debug = new Object[]{new TruffleDebugJavaMethod(compilable)};
-                return Debug.scope("Truffle", debug, new Callable<InstalledCode>() {
-
-                    @Override
-                    public InstalledCode call() throws Exception {
-                        return compileMethodImpl(compilable);
-                    }
-                });
+                try (Scope s = Debug.scope("Truffle", new TruffleDebugJavaMethod(compilable))) {
+                    return compileMethodImpl(compilable);
+                } catch (Throwable e) {
+                    throw Debug.handle(e);
+                }
             }
         });
-        return future;
     }
 
     public static final DebugTimer PartialEvaluationTime = Debug.timer("PartialEvaluationTime");
@@ -208,31 +204,22 @@
     public InstalledCode compileMethodHelper(final StructuredGraph graph, final GraphBuilderConfiguration config, final Assumptions assumptions) {
         final PhasePlan plan = createPhasePlan(config);
 
-        Debug.scope("TruffleFinal", new Runnable() {
-
-            @Override
-            public void run() {
-                Debug.dump(graph, "After TruffleTier");
-            }
-        });
-
-        final CompilationResult result = Debug.scope("TruffleGraal", new Callable<CompilationResult>() {
+        try (Scope s = Debug.scope("TruffleFinal")) {
+            Debug.dump(graph, "After TruffleTier");
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
 
-            @Override
-            public CompilationResult call() {
-                try (TimerCloseable a = CompilationTime.start()) {
-                    return Debug.scope("GraalCompiler", new Object[]{graph, providers.getCodeCache()}, new Callable<CompilationResult>() {
-                        public CompilationResult call() {
-                            CodeCacheProvider codeCache = providers.getCodeCache();
-                            CallingConvention cc = getCallingConvention(codeCache, Type.JavaCallee, graph.method(), false);
-                            CompilationResult compilationResult = new CompilationResult(graph.method().toString());
-                            return GraalCompiler.compileGraphNoScope(graph, cc, graph.method(), providers, backend, codeCache.getTarget(), null, plan, OptimisticOptimizations.ALL,
-                                            new SpeculationLog(), suites, compilationResult);
-                        }
-                    });
-                }
-            }
-        });
+        CompilationResult result = null;
+        try (TimerCloseable a = CompilationTime.start(); Scope s = Debug.scope("TruffleGraal.GraalCompiler", graph, providers.getCodeCache())) {
+            CodeCacheProvider codeCache = providers.getCodeCache();
+            CallingConvention cc = getCallingConvention(codeCache, Type.JavaCallee, graph.method(), false);
+            CompilationResult compilationResult = new CompilationResult(graph.method().toString());
+            result = GraalCompiler.compileGraphNoScope(graph, cc, graph.method(), providers, backend, codeCache.getTarget(), null, plan, OptimisticOptimizations.ALL, new SpeculationLog(), suites,
+                            compilationResult);
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
 
         List<AssumptionValidAssumption> validAssumptions = new ArrayList<>();
         Assumptions newAssumptions = new Assumptions(true);
@@ -250,19 +237,16 @@
 
         result.setAssumptions(newAssumptions);
 
-        InstalledCode compiledMethod = Debug.scope("CodeInstall", new Object[]{providers.getCodeCache()}, new Callable<InstalledCode>() {
-
-            @Override
-            public InstalledCode call() throws Exception {
-                try (TimerCloseable a = CodeInstallationTime.start()) {
-                    InstalledCode installedCode = providers.getCodeCache().addMethod(graph.method(), result);
-                    if (installedCode != null) {
-                        Debug.dump(new Object[]{result, installedCode}, "After code installation");
-                    }
-                    return installedCode;
-                }
+        InstalledCode compiledMethod = null;
+        try (Scope s = Debug.scope("CodeInstall", providers.getCodeCache()); TimerCloseable a = CodeInstallationTime.start()) {
+            InstalledCode installedCode = providers.getCodeCache().addMethod(graph.method(), result);
+            if (installedCode != null) {
+                Debug.dump(new Object[]{result, installedCode}, "After code installation");
             }
-        });
+            compiledMethod = installedCode;
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
 
         for (AssumptionValidAssumption a : validAssumptions) {
             a.getAssumption().registerInstalledCode(compiledMethod);
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java	Mon Dec 02 12:45:18 2013 +0100
@@ -82,6 +82,10 @@
     @Option(help = "")
     public static final OptionValue<Boolean> TraceTruffleCompilationDetails = new OptionValue<>(false);
     @Option(help = "")
+    public static final OptionValue<Boolean> TraceTruffleExpansion = new OptionValue<>(false);
+    @Option(help = "")
+    public static final OptionValue<Boolean> TraceTruffleExpansionSource = new OptionValue<>(false);
+    @Option(help = "")
     public static final OptionValue<Boolean> TraceTruffleCacheDetails = new OptionValue<>(false);
     @Option(help = "")
     public static final OptionValue<Boolean> TraceTruffleCompilationExceptions = new OptionValue<>(true);
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleDebugJavaMethod.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleDebugJavaMethod.java	Mon Dec 02 12:45:18 2013 +0100
@@ -30,7 +30,7 @@
 
 /**
  * Enables a Truffle compilable to masquerade as a {@link JavaMethod} for use as a context value in
- * {@linkplain Debug#scope(String, Object[], Runnable) debug scopes}.
+ * {@linkplain Debug#scope(String, Object...) debug scopes}.
  */
 public class TruffleDebugJavaMethod implements JavaMethod {
     private final DefaultCallTarget compilable;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleExpansionLogger.java	Mon Dec 02 12:45:18 2013 +0100
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.truffle;
+
+import java.io.*;
+import java.lang.reflect.*;
+import java.util.*;
+import java.util.Map.Entry;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
+
+public class TruffleExpansionLogger {
+
+    private final ExpansionTree root;
+    private final Map<MethodCallTargetNode, ExpansionTree> callToParentTree = new HashMap<>();
+
+    public TruffleExpansionLogger(StructuredGraph graph) {
+        root = new ExpansionTree(null, null, graph.method(), -1);
+        registerParentInCalls(root, graph);
+    }
+
+    public void preExpand(MethodCallTargetNode callTarget, StructuredGraph inliningGraph) {
+        ResolvedJavaMethod sourceMethod = callTarget.invoke().getState().method();
+
+        int sourceMethodBci = callTarget.invoke().bci();
+        ResolvedJavaMethod targetMethod = callTarget.targetMethod();
+        Object targetReceiver = null;
+        if (!Modifier.isStatic(sourceMethod.getModifiers())) {
+            targetReceiver = callTarget.arguments().first().asConstant().asObject();
+        }
+
+        ExpansionTree parent = callToParentTree.get(callTarget);
+        assert parent != null;
+        callToParentTree.remove(callTarget);
+        ExpansionTree tree = new ExpansionTree(parent, targetReceiver, targetMethod, sourceMethodBci);
+        registerParentInCalls(tree, inliningGraph);
+    }
+
+    @SuppressWarnings("unchecked")
+    public void postExpand(Map<Node, Node> states) {
+        Iterable<Entry<Node, Node>> entries;
+        if (states instanceof NodeMap) {
+            entries = ((NodeMap<Node>) states).entries();
+        } else {
+            entries = states.entrySet();
+        }
+
+        for (Entry<Node, Node> entry : entries) {
+            Node key = entry.getKey();
+            Node value = entry.getValue();
+
+            if (value instanceof MethodCallTargetNode && callToParentTree.containsKey(key)) {
+                callToParentTree.put((MethodCallTargetNode) value, callToParentTree.get(key));
+                callToParentTree.remove(key);
+            }
+        }
+    }
+
+    private void registerParentInCalls(ExpansionTree parentTree, StructuredGraph graph) {
+        for (MethodCallTargetNode target : graph.getNodes(MethodCallTargetNode.class)) {
+            callToParentTree.put(target, parentTree);
+        }
+    }
+
+    public void print() {
+        root.print(System.out);
+    }
+
+    private static final class ExpansionTree implements Comparable<ExpansionTree> {
+
+        private final ExpansionTree parent;
+        private final Object targetReceiver;
+        private final ResolvedJavaMethod targetMethod;
+        private final int parentBci;
+        private final List<ExpansionTree> children = new ArrayList<>();
+
+        public ExpansionTree(ExpansionTree parent, Object receiver, ResolvedJavaMethod targetMethod, int parentBci) {
+            this.parent = parent;
+            this.targetReceiver = receiver;
+            this.targetMethod = targetMethod;
+            this.parentBci = parentBci;
+            if (parent != null) {
+                parent.children.add(this);
+            }
+        }
+
+        public int compareTo(ExpansionTree o) {
+            if (parent == o.parent) {
+                return parentBci - o.parentBci;
+            }
+            return 0;
+        }
+
+        public void print(PrintStream p) {
+            print(p, "");
+        }
+
+        private void print(PrintStream p, String indent) {
+            StackTraceElement targetElement = targetMethod.asStackTraceElement(0);
+            StackTraceElement sourceElement = null;
+
+            ExpansionTree currentParent = this.parent;
+            if (currentParent != null) {
+                sourceElement = currentParent.targetMethod.asStackTraceElement(parentBci);
+            }
+
+            String className = targetElement.getClassName();
+            int lastIndex = className.lastIndexOf('.');
+            if (lastIndex != -1) {
+                className = className.substring(lastIndex + 1, className.length());
+            }
+
+            lastIndex = className.lastIndexOf('$');
+            if (lastIndex != -1) {
+                className = className.substring(lastIndex + 1, className.length());
+            }
+
+            String constantType = "";
+            if (targetReceiver != null) {
+                if (!targetReceiver.getClass().getSimpleName().equals(className)) {
+                    constantType = "<" + targetReceiver.getClass().getSimpleName() + ">";
+                }
+            }
+
+            String sourceSource = "";
+            String targetSource = "";
+            if (TruffleCompilerOptions.TraceTruffleExpansionSource.getValue()) {
+                sourceSource = formatSource(sourceElement);
+                targetSource = formatSource(targetElement);
+            }
+            p.printf("%s%s %s%s.%s%s%n", indent, sourceSource, className, constantType, targetMethod.getName(), targetSource);
+
+            Collections.sort(children);
+
+            for (ExpansionTree child : children) {
+                child.print(p, indent + "  ");
+            }
+        }
+
+        private static String formatSource(StackTraceElement e) {
+            if (e == null) {
+                return "";
+            }
+            if (e.getFileName() != null) {
+                if (e.getLineNumber() >= 0) {
+                    return String.format("(%s:%d)", e.getFileName(), e.getLineNumber());
+                } else {
+                    return String.format("(%s)", e.getFileName(), e.getLineNumber());
+                }
+            } else {
+                return String.format("(Unknown Source)", e.getFileName(), e.getLineNumber());
+            }
+        }
+    }
+
+}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleReplacements.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleReplacements.java	Mon Dec 02 12:45:18 2013 +0100
@@ -43,7 +43,7 @@
     private final Replacements graalReplacements;
 
     private TruffleReplacements(Providers providers) {
-        super(providers, providers.getReplacements().getAssumptions());
+        super(providers, providers.getReplacements().getAssumptions(), providers.getCodeCache().getTarget());
         this.graalReplacements = providers.getReplacements();
     }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/FrameWithoutBoxingSubstitutions.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/FrameWithoutBoxingSubstitutions.java	Mon Dec 02 12:45:18 2013 +0100
@@ -24,13 +24,14 @@
 
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.truffle.*;
+import com.oracle.truffle.api.frame.*;
 
 @ClassSubstitution(FrameWithoutBoxing.class)
 public class FrameWithoutBoxingSubstitutions {
 
     @SuppressWarnings("unused")
     @MethodSubstitution(isStatic = false, forced = true)
-    public static Object pack(FrameWithoutBoxing frame) {
+    public static PackedFrame pack(FrameWithoutBoxing frame) {
         return null;
     }
 }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsPhase.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsPhase.java	Mon Dec 02 12:45:18 2013 +0100
@@ -22,9 +22,8 @@
  */
 package com.oracle.graal.virtual.phases.ea;
 
-import java.util.concurrent.*;
-
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
@@ -60,45 +59,37 @@
     public boolean runAnalysis(final StructuredGraph graph, final PhaseContextT context) {
         boolean changed = false;
         for (int iteration = 0; iteration < maxIterations; iteration++) {
-            boolean currentChanged = Debug.scope("iteration " + iteration, new Callable<Boolean>() {
 
-                @Override
-                public Boolean call() {
-                    SchedulePhase schedule = new SchedulePhase();
-                    schedule.apply(graph, false);
-                    Closure<?> closure = createEffectsClosure(context, schedule);
-                    ReentrantBlockIterator.apply(closure, schedule.getCFG().getStartBlock());
+            try (Scope s = Debug.scope("iteration " + iteration)) {
+                SchedulePhase schedule = new SchedulePhase();
+                schedule.apply(graph, false);
+                Closure<?> closure = createEffectsClosure(context, schedule);
+                ReentrantBlockIterator.apply(closure, schedule.getCFG().getStartBlock());
 
-                    if (!closure.hasChanged()) {
-                        return false;
-                    }
+                if (!closure.hasChanged()) {
+                    break;
+                }
 
-                    // apply the effects collected during this iteration
-                    HashSetNodeChangeListener listener = new HashSetNodeChangeListener();
-                    graph.trackInputChange(listener);
-                    graph.trackUsagesDroppedZero(listener);
-                    closure.applyEffects();
-                    graph.stopTrackingInputChange();
-                    graph.stopTrackingUsagesDroppedZero();
+                // apply the effects collected during this iteration
+                HashSetNodeChangeListener listener = new HashSetNodeChangeListener();
+                graph.trackInputChange(listener);
+                graph.trackUsagesDroppedZero(listener);
+                closure.applyEffects();
+                graph.stopTrackingInputChange();
+                graph.stopTrackingUsagesDroppedZero();
 
-                    Debug.dump(graph, "after " + getName() + " iteration");
-
-                    new DeadCodeEliminationPhase().apply(graph);
+                Debug.dump(graph, "after " + getName() + " iteration");
 
-                    for (Node node : graph.getNodes()) {
-                        if (node instanceof Simplifiable) {
-                            listener.getChangedNodes().add(node);
-                        }
-                    }
-                    canonicalizer.applyIncremental(graph, context, listener.getChangedNodes());
+                new DeadCodeEliminationPhase().apply(graph);
 
-                    return true;
+                for (Node node : graph.getNodes()) {
+                    if (node instanceof Simplifiable) {
+                        listener.getChangedNodes().add(node);
+                    }
                 }
-            });
-            if (!currentChanged) {
-                break;
+                canonicalizer.applyIncremental(graph, context, listener.getChangedNodes());
             }
-            changed |= currentChanged;
+            changed = true;
         }
         return changed;
     }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/IterativeInliningPhase.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/IterativeInliningPhase.java	Mon Dec 02 12:45:18 2013 +0100
@@ -25,9 +25,9 @@
 import static com.oracle.graal.phases.GraalOptions.*;
 
 import java.util.*;
-import java.util.concurrent.*;
 
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
@@ -53,34 +53,32 @@
     }
 
     private void runIterations(final StructuredGraph graph, final boolean simple, final HighTierContext context) {
-        Boolean continueIteration = true;
-        for (int iteration = 0; iteration < EscapeAnalysisIterations.getValue() && continueIteration; iteration++) {
-            continueIteration = Debug.scope("iteration " + iteration, new Callable<Boolean>() {
+        for (int iteration = 0; iteration < EscapeAnalysisIterations.getValue(); iteration++) {
+            try (Scope s = Debug.scope("iteration " + iteration)) {
+                boolean progress = false;
+                PartialEscapePhase ea = new PartialEscapePhase(false, canonicalizer);
+                boolean eaResult = ea.runAnalysis(graph, context);
+                progress |= eaResult;
 
-                @Override
-                public Boolean call() {
-                    boolean progress = false;
-                    PartialEscapePhase ea = new PartialEscapePhase(false, canonicalizer);
-                    boolean eaResult = ea.runAnalysis(graph, context);
-                    progress |= eaResult;
-
-                    Map<Invoke, Double> hints = PEAInliningHints.getValue() ? PartialEscapePhase.getHints(graph) : null;
+                Map<Invoke, Double> hints = PEAInliningHints.getValue() ? PartialEscapePhase.getHints(graph) : null;
 
-                    InliningPhase inlining = new InliningPhase(hints, new CanonicalizerPhase(true));
-                    inlining.setMaxMethodsPerInlining(simple ? 1 : Integer.MAX_VALUE);
-                    inlining.apply(graph, context);
-                    progress |= inlining.getInliningCount() > 0;
+                InliningPhase inlining = new InliningPhase(hints, new CanonicalizerPhase(true));
+                inlining.setMaxMethodsPerInlining(simple ? 1 : Integer.MAX_VALUE);
+                inlining.apply(graph, context);
+                progress |= inlining.getInliningCount() > 0;
 
-                    new DeadCodeEliminationPhase().apply(graph);
+                new DeadCodeEliminationPhase().apply(graph);
 
-                    if (ConditionalElimination.getValue() && OptCanonicalizer.getValue()) {
-                        canonicalizer.apply(graph, context);
-                        new IterativeConditionalEliminationPhase(canonicalizer).apply(graph, context);
-                    }
-
-                    return progress;
+                if (ConditionalElimination.getValue() && OptCanonicalizer.getValue()) {
+                    canonicalizer.apply(graph, context);
+                    new IterativeConditionalEliminationPhase(canonicalizer).apply(graph, context);
                 }
-            });
+                if (!progress) {
+                    break;
+                }
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            }
         }
     }
 }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java	Mon Dec 02 12:45:18 2013 +0100
@@ -114,7 +114,7 @@
             if (initialState.getReadCache().get(entry.getKey()) != entry.getValue()) {
                 ValueNode value = exitState.getReadCache(entry.getKey().object, entry.getKey().identity, this);
                 if (!(value instanceof ProxyNode) || ((ProxyNode) value).proxyPoint() != exitNode) {
-                    ProxyNode proxy = new ProxyNode(value, exitNode, PhiType.Value, null);
+                    ProxyNode proxy = new ProxyNode(value, exitNode, PhiType.Value);
                     effects.addFloatingNode(proxy, "readCacheProxy");
                     entry.setValue(proxy);
                 }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Mon Dec 02 12:45:18 2013 +0100
@@ -247,7 +247,7 @@
                     ValueNode value = obj.getEntry(i);
                     if (!(value instanceof VirtualObjectNode || value.isConstant())) {
                         if (exitNode.loopBegin().isPhiAtMerge(value) || initialObj == null || !initialObj.isVirtual() || initialObj.getEntry(i) != value) {
-                            ProxyNode proxy = new ProxyNode(value, exitNode, PhiType.Value, null);
+                            ProxyNode proxy = new ProxyNode(value, exitNode, PhiType.Value);
                             obj.setEntry(i, proxy);
                             effects.addFloatingNode(proxy, "virtualProxy");
                         }
@@ -257,7 +257,7 @@
                 if (initialObj == null || initialObj.isVirtual()) {
                     ProxyNode proxy = proxies.get(obj.virtual);
                     if (proxy == null) {
-                        proxy = new ProxyNode(obj.getMaterializedValue(), exitNode, PhiType.Value, null);
+                        proxy = new ProxyNode(obj.getMaterializedValue(), exitNode, PhiType.Value);
                         effects.addFloatingNode(proxy, "proxy");
                     } else {
                         effects.replaceFirstInput(proxy, proxy.value(), obj.getMaterializedValue());
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java	Mon Dec 02 12:45:18 2013 +0100
@@ -171,7 +171,7 @@
     protected void processLoopExit(LoopExitNode exitNode, ReadEliminationBlockState initialState, ReadEliminationBlockState exitState, GraphEffectList effects) {
         for (Map.Entry<CacheEntry<?>, ValueNode> entry : exitState.getReadCache().entrySet()) {
             if (initialState.getReadCache().get(entry.getKey()) != entry.getValue()) {
-                ProxyNode proxy = new ProxyNode(exitState.getCacheEntry(entry.getKey()), exitNode, PhiType.Value, null);
+                ProxyNode proxy = new ProxyNode(exitState.getCacheEntry(entry.getKey()), exitNode, PhiType.Value);
                 effects.addFloatingNode(proxy, "readCacheProxy");
                 entry.setValue(proxy);
             }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/ComparableWord.java	Mon Dec 02 12:45:18 2013 +0100
@@ -0,0 +1,42 @@
+/*
+ * 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.graal.word;
+
+public interface ComparableWord extends WordBase {
+
+    /**
+     * Compares this word with the specified value.
+     * 
+     * @param val value to which this word is to be compared.
+     * @return {@code this == val}
+     */
+    boolean equal(ComparableWord val);
+
+    /**
+     * Compares this word with the specified value.
+     * 
+     * @param val value to which this word is to be compared.
+     * @return {@code this != val}
+     */
+    boolean notEqual(ComparableWord val);
+}
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/Pointer.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/Pointer.java	Mon Dec 02 12:45:18 2013 +0100
@@ -26,7 +26,7 @@
 import com.oracle.graal.nodes.HeapAccess.BarrierType;
 import com.oracle.graal.nodes.extended.*;
 
-public interface Pointer extends Unsigned {
+public interface Pointer extends Unsigned, PointerBase {
 
     /**
      * Unsafe conversion of this Pointer to a Java language object. No correctness checks or type
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/PointerBase.java	Mon Dec 02 12:45:18 2013 +0100
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.word;
+
+/**
+ * Marker interface for all {@link WordBase word types} that have the semantic of a pointer (but not
+ * necessarily all the memory access methods defined in {@link Pointer}).
+ */
+public interface PointerBase extends ComparableWord {
+}
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/Signed.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/Signed.java	Mon Dec 02 12:45:18 2013 +0100
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.word;
 
-public interface Signed extends WordBase {
+public interface Signed extends ComparableWord {
 
     /**
      * Returns a Signed whose value is {@code (this + val)}.
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/Unsigned.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/Unsigned.java	Mon Dec 02 12:45:18 2013 +0100
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.word;
 
-public interface Unsigned extends WordBase {
+public interface Unsigned extends ComparableWord {
 
     /**
      * Returns a Unsigned whose value is {@code (this + val)}.
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/Word.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/Word.java	Mon Dec 02 12:45:18 2013 +0100
@@ -427,6 +427,12 @@
 
     @Override
     @Operation(opcode = Opcode.COMPARISON, condition = Condition.EQ)
+    public boolean equal(ComparableWord val) {
+        return equal((Word) val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.COMPARISON, condition = Condition.EQ)
     public boolean equal(Signed val) {
         return equal((Word) val);
     }
@@ -450,6 +456,12 @@
 
     @Override
     @Operation(opcode = Opcode.COMPARISON, condition = Condition.NE)
+    public boolean notEqual(ComparableWord val) {
+        return notEqual((Word) val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.COMPARISON, condition = Condition.NE)
     public boolean notEqual(Signed val) {
         return notEqual((Word) val);
     }
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java	Mon Dec 02 12:45:18 2013 +0100
@@ -86,6 +86,21 @@
      * prepared to see the word type during canonicalization.
      */
     protected void inferStamps(StructuredGraph graph) {
+        /*
+         * We want to make the stamps more precise. For cyclic phi functions, this means we have to
+         * ignore the initial stamp because the imprecise stamp would always propagate around the
+         * cycle. We therefore set the stamp to an illegal stamp, which is automatically ignored
+         * when the phi function performs the "meet" operator on its input stamps.
+         */
+        for (Node n : graph.getNodes()) {
+            if (n instanceof PhiNode || n instanceof ProxyNode) {
+                ValueNode node = (ValueNode) n;
+                if (node.kind() == Kind.Object) {
+                    node.setStamp(StampFactory.illegal(node.kind()));
+                }
+            }
+        }
+
         boolean stampChanged;
         do {
             stampChanged = false;
@@ -104,6 +119,22 @@
                 }
             }
         } while (stampChanged);
+
+        /*
+         * Check that all the illegal stamps we introduced above are correctly replaced with real
+         * stamps again.
+         */
+        assert checkNoIllegalStamp(graph);
+    }
+
+    private static boolean checkNoIllegalStamp(StructuredGraph graph) {
+        for (Node n : graph.getNodes()) {
+            if (n instanceof ValueNode) {
+                ValueNode node = (ValueNode) n;
+                assert !(node.stamp() instanceof IllegalStamp);
+            }
+        }
+        return true;
     }
 
     /**
@@ -243,7 +274,7 @@
                 } else {
                     location = makeLocation(graph, arguments.get(1), readKind, arguments.get(2));
                 }
-                replace(invoke, readOp(graph, arguments.get(0), invoke, location, BarrierType.NONE, false));
+                replace(invoke, readOp(graph, arguments.get(0), invoke, location, readKind, BarrierType.NONE, false));
                 break;
             }
             case READ_HEAP: {
@@ -251,7 +282,7 @@
                 Kind readKind = asKind(callTargetNode.returnType());
                 LocationNode location = makeLocation(graph, arguments.get(1), readKind, ANY_LOCATION);
                 BarrierType barrierType = (BarrierType) arguments.get(2).asConstant().asObject();
-                replace(invoke, readOp(graph, arguments.get(0), invoke, location, barrierType, arguments.get(3).asConstant().asInt() == 0 ? false : true));
+                replace(invoke, readOp(graph, arguments.get(0), invoke, location, readKind, barrierType, arguments.get(3).asConstant().asInt() == 0 ? false : true));
                 break;
             }
             case WRITE:
@@ -390,15 +421,16 @@
         if (locationIdentity.isConstant()) {
             return makeLocation(graph, offset, readKind, (LocationIdentity) locationIdentity.asConstant().asObject());
         }
-        return SnippetLocationNode.create(locationIdentity, ConstantNode.forObject(readKind, metaAccess, graph), ConstantNode.forLong(0, graph), offset, ConstantNode.forInt(1, graph), graph);
+        return SnippetLocationNode.create(locationIdentity, ConstantNode.forObject(readKind, metaAccess, graph), ConstantNode.forLong(0, graph), fromSigned(graph, offset),
+                        ConstantNode.forInt(1, graph), graph);
     }
 
     protected LocationNode makeLocation(StructuredGraph graph, ValueNode offset, Kind readKind, LocationIdentity locationIdentity) {
-        return IndexedLocationNode.create(locationIdentity, readKind, 0, offset, graph, 1);
+        return IndexedLocationNode.create(locationIdentity, readKind, 0, fromSigned(graph, offset), graph, 1);
     }
 
-    protected ValueNode readOp(StructuredGraph graph, ValueNode base, Invoke invoke, LocationNode location, BarrierType barrierType, boolean compressible) {
-        ReadNode read = graph.add(new ReadNode(base, location, invoke.asNode().stamp(), barrierType, compressible));
+    protected ValueNode readOp(StructuredGraph graph, ValueNode base, Invoke invoke, LocationNode location, Kind readKind, BarrierType barrierType, boolean compressible) {
+        ReadNode read = graph.add(new ReadNode(base, location, StampFactory.forKind(readKind), barrierType, compressible));
         graph.addBeforeFixed(invoke.asNode(), read);
         /*
          * The read must not float outside its block otherwise it may float above an explicit zero
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultVirtualFrame.java	Mon Dec 02 12:44:53 2013 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultVirtualFrame.java	Mon Dec 02 12:45:18 2013 +0100
@@ -160,7 +160,9 @@
     public Object getValue(FrameSlot slot) {
         int slotIndex = slot.getIndex();
         if (slotIndex >= tags.length) {
-            resize();
+            if (!resize()) {
+                throw new IllegalArgumentException(String.format("The frame slot '%s' is not known by the frame descriptor.", slot));
+            }
         }
         return locals[slotIndex];
     }
@@ -168,7 +170,9 @@
     private void verifySet(FrameSlot slot, FrameSlotKind accessKind) {
         int slotIndex = slot.getIndex();
         if (slotIndex >= tags.length) {
-            resize();
+            if (!resize()) {
+                throw new IllegalArgumentException(String.format("The frame slot '%s' is not known by the frame descriptor.", slot));
+            }
         }
         tags[slotIndex] = (byte) accessKind.ordinal();
     }
@@ -176,7 +180,9 @@
     private void verifyGet(FrameSlot slot, FrameSlotKind accessKind) throws FrameSlotTypeException {
         int slotIndex = slot.getIndex();
         if (slotIndex >= tags.length) {
-            resize();
+            if (!resize()) {
+                throw new IllegalArgumentException(String.format("The frame slot '%s' is not known by the frame descriptor.", slot));
+            }
         }
         byte tag = tags[slotIndex];
         if (accessKind == FrameSlotKind.Object ? tag != 0 : tag != accessKind.ordinal()) {
@@ -190,20 +196,24 @@
         }
     }
 
-    private void resize() {
+    private boolean resize() {
         int oldSize = tags.length;
         int newSize = descriptor.getSize();
         if (newSize > oldSize) {
             locals = Arrays.copyOf(locals, newSize);
             Arrays.fill(locals, oldSize, newSize, descriptor.getTypeConversion().getDefaultValue());
             tags = Arrays.copyOf(tags, newSize);
+            return true;
         }
+        return false;
     }
 
     private byte getTag(FrameSlot slot) {
         int slotIndex = slot.getIndex();
         if (slotIndex >= tags.length) {
-            resize();
+            if (!resize()) {
+                throw new IllegalArgumentException(String.format("The frame slot '%s' is not known by the frame descriptor.", slot));
+            }
         }
         return tags[slotIndex];
     }
--- a/make/bsd/makefiles/jsig.make	Mon Dec 02 12:44:53 2013 +0100
+++ b/make/bsd/makefiles/jsig.make	Mon Dec 02 12:45:18 2013 +0100
@@ -97,7 +97,7 @@
 	$(QUIETLY) test -f $(LIBJSIG_DEBUGINFO) && \
 	    cp -f $(LIBJSIG_DEBUGINFO) $(DEST_JSIG_DEBUGINFO)
 endif
-	-$(QUIETLY) test -f $(LIBJSIG_DIZ) && \
+	$(QUIETLY) test ! -f $(LIBJSIG_DIZ) || \
 	    cp -f $(LIBJSIG_DIZ) $(DEST_JSIG_DIZ)
 	$(QUIETLY) cp -f $(LIBJSIG) $(DEST_JSIG) && echo "Done"
 
--- a/make/bsd/makefiles/saproc.make	Mon Dec 02 12:44:53 2013 +0100
+++ b/make/bsd/makefiles/saproc.make	Mon Dec 02 12:45:18 2013 +0100
@@ -163,7 +163,7 @@
 	$(QUIETLY) test -f $(LIBSAPROC_DEBUGINFO) && \
 	    cp -f $(LIBSAPROC_DEBUGINFO) $(DEST_SAPROC_DEBUGINFO)
 endif
-	-$(QUIETLY) test -f $(LIBSAPROC_DIZ) && \
+	$(QUIETLY) test ! -f $(LIBSAPROC_DIZ) || \
 	    cp -f $(LIBSAPROC_DIZ) $(DEST_SAPROC_DIZ)
 	$(QUIETLY) cp -f $(LIBSAPROC) $(DEST_SAPROC) && echo "Done"
 
--- a/make/bsd/makefiles/vm.make	Mon Dec 02 12:44:53 2013 +0100
+++ b/make/bsd/makefiles/vm.make	Mon Dec 02 12:45:18 2013 +0100
@@ -393,7 +393,7 @@
 	$(QUIETLY) test -f $(LIBJVM_DEBUGINFO) && \
 	    cp -f $(LIBJVM_DEBUGINFO) $(DEST_JVM_DEBUGINFO)
 endif
-	-$(QUIETLY) test -f $(LIBJVM_DIZ) && \
+	$(QUIETLY) test ! -f $(LIBJVM_DIZ) || \
 	    cp -f $(LIBJVM_DIZ) $(DEST_JVM_DIZ)
 	$(QUIETLY) cp -f $(LIBJVM) $(DEST_JVM) && echo "Done"
 
--- a/make/linux/makefiles/jsig.make	Mon Dec 02 12:44:53 2013 +0100
+++ b/make/linux/makefiles/jsig.make	Mon Dec 02 12:45:18 2013 +0100
@@ -74,9 +74,9 @@
 
 install_jsig: $(LIBJSIG)
 	@echo "Copying $(LIBJSIG) to $(DEST_JSIG)"
-	-$(QUIETLY) test -f $(LIBJSIG_DEBUGINFO) && \
+	$(QUIETLY) test ! -f $(LIBJSIG_DEBUGINFO) || \
 	    cp -f $(LIBJSIG_DEBUGINFO) $(DEST_JSIG_DEBUGINFO)
-	-$(QUIETLY) test -f $(LIBJSIG_DIZ) && \
+	$(QUIETLY) test ! -f $(LIBJSIG_DIZ) || \
 	    cp -f $(LIBJSIG_DIZ) $(DEST_JSIG_DIZ)
 	$(QUIETLY) cp -f $(LIBJSIG) $(DEST_JSIG) && echo "Done"
 
--- a/make/linux/makefiles/vm.make	Mon Dec 02 12:44:53 2013 +0100
+++ b/make/linux/makefiles/vm.make	Mon Dec 02 12:45:18 2013 +0100
@@ -382,9 +382,9 @@
 
 install_jvm: $(LIBJVM)
 	@echo "Copying $(LIBJVM) to $(DEST_JVM)"
-	-$(QUIETLY) test -f $(LIBJVM_DEBUGINFO) && \
+	$(QUIETLY) test ! -f $(LIBJVM_DEBUGINFO) || \
 	    cp -f $(LIBJVM_DEBUGINFO) $(DEST_JVM_DEBUGINFO)
-	-$(QUIETLY) test -f $(LIBJVM_DIZ) && \
+	$(QUIETLY) test ! -f $(LIBJVM_DIZ) || \
 	    cp -f $(LIBJVM_DIZ) $(DEST_JVM_DIZ)
 	$(QUIETLY) cp -f $(LIBJVM) $(DEST_JVM) && echo "Done"
 
--- a/make/solaris/makefiles/jsig.make	Mon Dec 02 12:44:53 2013 +0100
+++ b/make/solaris/makefiles/jsig.make	Mon Dec 02 12:45:18 2013 +0100
@@ -79,9 +79,9 @@
 
 install_jsig: $(LIBJSIG)
 	@echo "Copying $(LIBJSIG) to $(DEST_JSIG)"
-	-$(QUIETLY) test -f $(LIBJSIG_DEBUGINFO) && \
+	$(QUIETLY) test ! -f $(LIBJSIG_DEBUGINFO) || \
 	    cp -f $(LIBJSIG_DEBUGINFO) $(DEST_JSIG_DEBUGINFO)
-	-$(QUIETLY) test -f $(LIBJSIG_DIZ) && \
+	$(QUIETLY) test ! -f $(LIBJSIG_DIZ) || \
 	    cp -f $(LIBJSIG_DIZ) $(DEST_JSIG_DIZ)
 	$(QUIETLY) cp -f $(LIBJSIG) $(DEST_JSIG) && echo "Done"
 
--- a/make/solaris/makefiles/vm.make	Mon Dec 02 12:44:53 2013 +0100
+++ b/make/solaris/makefiles/vm.make	Mon Dec 02 12:45:18 2013 +0100
@@ -343,9 +343,9 @@
 
 install_jvm: $(LIBJVM)
 	@echo "Copying $(LIBJVM) to $(DEST_JVM)"
-	-$(QUIETLY) test -f $(LIBJVM_DEBUGINFO) && \
+	$(QUIETLY) test ! -f $(LIBJVM_DEBUGINFO) || \
 	    cp -f $(LIBJVM_DEBUGINFO) $(DEST_JVM_DEBUGINFO)
-	-$(QUIETLY) test -f $(LIBJVM_DIZ) && \
+	$(QUIETLY) test ! -f $(LIBJVM_DIZ) || \
 	    cp -f $(LIBJVM_DIZ) $(DEST_JVM_DIZ)
 	$(QUIETLY) cp -f $(LIBJVM) $(DEST_JVM) && echo "Done"
 
--- a/mx/projects	Mon Dec 02 12:44:53 2013 +0100
+++ b/mx/projects	Mon Dec 02 12:45:18 2013 +0100
@@ -67,6 +67,14 @@
 project@com.oracle.graal.api.meta.test@javaCompliance=1.7
 project@com.oracle.graal.api.meta.test@workingSets=API,Graal,Test
 
+# graal.api.meta.jdk8.test
+project@com.oracle.graal.api.meta.jdk8.test@subDir=graal
+project@com.oracle.graal.api.meta.jdk8.test@sourceDirs=src
+project@com.oracle.graal.api.meta.jdk8.test@dependencies=com.oracle.graal.api.meta.test
+project@com.oracle.graal.api.meta.jdk8.test@checkstyle=com.oracle.graal.graph
+project@com.oracle.graal.api.meta.jdk8.test@javaCompliance=1.8
+project@com.oracle.graal.api.meta.jdk8.test@workingSets=API,Graal,Test
+
 # graal.api.code
 project@com.oracle.graal.api.code@subDir=graal
 project@com.oracle.graal.api.code@sourceDirs=src
@@ -176,7 +184,7 @@
 project@com.oracle.graal.hotspot.test@javaCompliance=1.7
 project@com.oracle.graal.hotspot.test@workingSets=Graal,HotSpot,Test
 
-# graal.hotspot.test
+# graal.hotspot.jdk8.test
 project@com.oracle.graal.hotspot.jdk8.test@subDir=graal
 project@com.oracle.graal.hotspot.jdk8.test@sourceDirs=src
 project@com.oracle.graal.hotspot.jdk8.test@dependencies=com.oracle.graal.compiler.test
--- a/src/cpu/sparc/vm/c2_globals_sparc.hpp	Mon Dec 02 12:44:53 2013 +0100
+++ b/src/cpu/sparc/vm/c2_globals_sparc.hpp	Mon Dec 02 12:45:18 2013 +0100
@@ -44,12 +44,7 @@
 #else
 define_pd_global(bool, ProfileInterpreter,           true);
 #endif // CC_INTERP
-// Disable TieredCompilation while profile data problems are not resolved - same thing in c2_globals_x86.hpp
-#ifdef GRAAL
-define_pd_global(bool, TieredCompilation,            false);
-#else
 define_pd_global(bool, TieredCompilation,            trueInTiered);
-#endif
 define_pd_global(intx, CompileThreshold,             10000);
 define_pd_global(intx, BackEdgeThreshold,            140000);
 
--- a/src/cpu/x86/vm/c2_globals_x86.hpp	Mon Dec 02 12:44:53 2013 +0100
+++ b/src/cpu/x86/vm/c2_globals_x86.hpp	Mon Dec 02 12:45:18 2013 +0100
@@ -45,12 +45,7 @@
 #else
 define_pd_global(bool, ProfileInterpreter,           true);
 #endif // CC_INTERP
-// Disable TieredCompilation while profile data problems are not resolved - same thing in c2_globals_sparc.hpp
-#ifdef GRAAL
-define_pd_global(bool, TieredCompilation,            false);
-#else
 define_pd_global(bool, TieredCompilation,            trueInTiered);
-#endif
 define_pd_global(intx, CompileThreshold,             10000);
 define_pd_global(intx, BackEdgeThreshold,            100000);
 
--- a/src/cpu/x86/vm/globals_x86.hpp	Mon Dec 02 12:44:53 2013 +0100
+++ b/src/cpu/x86/vm/globals_x86.hpp	Mon Dec 02 12:45:18 2013 +0100
@@ -79,7 +79,7 @@
 // GC Ergo Flags
 define_pd_global(uintx, CMSYoungGenPerWorker, 64*M);  // default max size of CMS young gen, per GC worker thread
 
-define_pd_global(uintx, TypeProfileLevel, GRAALVM_ONLY(0) NOT_GRAALVM(111));
+define_pd_global(uintx, TypeProfileLevel, 111);
 
 #define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct) \
                                                                             \
--- a/src/cpu/x86/vm/templateTable_x86_64.cpp	Mon Dec 02 12:44:53 2013 +0100
+++ b/src/cpu/x86/vm/templateTable_x86_64.cpp	Mon Dec 02 12:45:18 2013 +0100
@@ -3043,11 +3043,11 @@
 
   // get target Method* & entry point
   __ lookup_virtual_method(rax, index, method);
-  __ profile_arguments_type(rdx, method, r13, true);
 #ifdef GRAAL
   // r14: MethodDataPointer (r14 is callee saved)
   __ profile_called_method(method, r14, r13);
 #endif
+  __ profile_arguments_type(rdx, method, r13, true);
 
   __ jump_from_interpreted(method, rdx);
 }
@@ -3147,15 +3147,15 @@
   __ testptr(rbx, rbx);
   __ jcc(Assembler::zero, no_such_method);
 
+#ifdef GRAAL
+  // r13: MethodDataPointer (r13 is callee saved)
+  __ profile_called_method(rbx, r13, r14);
+#endif
   __ profile_arguments_type(rdx, rbx, r13, true);
 
   // do the call
   // rcx: receiver
   // rbx,: Method*
-#ifdef GRAAL
-  // r13: MethodDataPointer (r13 is callee saved)
-  __ profile_called_method(rbx, r13, r14);
-#endif
   __ jump_from_interpreted(rbx, rdx);
   __ should_not_reach_here();
 
--- a/src/gpu/hsail/vm/gpu_hsail.cpp	Mon Dec 02 12:44:53 2013 +0100
+++ b/src/gpu/hsail/vm/gpu_hsail.cpp	Mon Dec 02 12:45:18 2013 +0100
@@ -33,8 +33,8 @@
 
 void * gpu::Hsail::_device_context;
 
-gpu::Hsail::okra_ctx_create_func_t      gpu::Hsail::_okra_ctx_create;
-gpu::Hsail::okra_kernel_create_func_t   gpu::Hsail::_okra_kernel_create;
+gpu::Hsail::okra_create_context_func_t  gpu::Hsail::_okra_create_context;
+gpu::Hsail::okra_create_kernel_func_t   gpu::Hsail::_okra_create_kernel;
 gpu::Hsail::okra_push_object_func_t     gpu::Hsail::_okra_push_object;
 gpu::Hsail::okra_push_boolean_func_t    gpu::Hsail::_okra_push_boolean;
 gpu::Hsail::okra_push_byte_func_t       gpu::Hsail::_okra_push_byte;
@@ -92,13 +92,13 @@
   // The kernel entrypoint is always run for the time being  
   const char* entryPointName = "&run";
 
-  _device_context = _okra_ctx_create();
+  _device_context = _okra_create_context();
 
   // code is not null terminated, must be a better way to do this
   unsigned char* nullTerminatedCodeBuffer = (unsigned char*) malloc(code_len + 1);
   memcpy(nullTerminatedCodeBuffer, code, code_len);
   nullTerminatedCodeBuffer[code_len] = 0;
-  void* kernel = _okra_kernel_create(_device_context, nullTerminatedCodeBuffer, entryPointName);
+  void* kernel = _okra_create_kernel(_device_context, nullTerminatedCodeBuffer, entryPointName);
   free(nullTerminatedCodeBuffer);
   return kernel;
 }
@@ -113,6 +113,16 @@
 
 #define STD_BUFFER_SIZE 1024
 
+#define STRINGIFY(x)     #x
+
+#define LOOKUP_OKRA_FUNCTION(name, alias)  \
+  _##alias =                               \
+    CAST_TO_FN_PTR(alias##_func_t, os::dll_lookup(handle, STRINGIFY(name))); \
+  if (_##alias == NULL) {      \
+  tty->print_cr("[HSAIL] ***** Error: Failed to lookup %s in %s, wrong version of OKRA?", STRINGIFY(name), okra_library_name); \
+        return 0; \
+  } \
+
 bool gpu::Hsail::probe_linkage() {
   if (okra_library_name != NULL) {
     char *buffer = (char*)malloc(STD_BUFFER_SIZE);
@@ -123,34 +133,19 @@
     free(buffer);
     if (handle != NULL) {
 
-      _okra_ctx_create =
-        CAST_TO_FN_PTR(okra_ctx_create_func_t, os::dll_lookup(handle, "okra_create_context"));
-      _okra_kernel_create =
-        CAST_TO_FN_PTR(okra_kernel_create_func_t, os::dll_lookup(handle, "okra_create_kernel"));
-      _okra_push_object =
-        CAST_TO_FN_PTR(okra_push_object_func_t, os::dll_lookup(handle, "okra_push_object"));
-      _okra_push_boolean =
-        CAST_TO_FN_PTR(okra_push_boolean_func_t, os::dll_lookup(handle, "okra_push_boolean"));
-      _okra_push_byte =
-        CAST_TO_FN_PTR(okra_push_byte_func_t, os::dll_lookup(handle, "okra_push_byte"));
-      _okra_push_double =
-        CAST_TO_FN_PTR(okra_push_double_func_t, os::dll_lookup(handle, "okra_push_double"));
-      _okra_push_float =
-        CAST_TO_FN_PTR(okra_push_float_func_t, os::dll_lookup(handle, "okra_push_float"));
-      _okra_push_int =
-        CAST_TO_FN_PTR(okra_push_int_func_t, os::dll_lookup(handle, "okra_push_int"));
-      _okra_push_long =
-        CAST_TO_FN_PTR(okra_push_long_func_t, os::dll_lookup(handle, "okra_push_long"));
-      _okra_execute_with_range =
-        CAST_TO_FN_PTR(okra_execute_with_range_func_t, os::dll_lookup(handle, "okra_execute_with_range"));
-      _okra_clearargs =
-        CAST_TO_FN_PTR(okra_clearargs_func_t, os::dll_lookup(handle, "okra_clearargs"));
-      _okra_register_heap =
-        CAST_TO_FN_PTR(okra_register_heap_func_t, os::dll_lookup(handle, "okra_register_heap"));
+      LOOKUP_OKRA_FUNCTION(okra_create_context, okra_create_context);
+      LOOKUP_OKRA_FUNCTION(okra_create_kernel, okra_create_kernel);
+      LOOKUP_OKRA_FUNCTION(okra_push_object, okra_push_object);
+      LOOKUP_OKRA_FUNCTION(okra_push_boolean, okra_push_boolean);
+      LOOKUP_OKRA_FUNCTION(okra_push_byte, okra_push_byte);
+      LOOKUP_OKRA_FUNCTION(okra_push_double, okra_push_double);
+      LOOKUP_OKRA_FUNCTION(okra_push_float, okra_push_float);
+      LOOKUP_OKRA_FUNCTION(okra_push_int, okra_push_int);
+      LOOKUP_OKRA_FUNCTION(okra_push_long, okra_push_long);
+      LOOKUP_OKRA_FUNCTION(okra_execute_with_range, okra_execute_with_range);
+      LOOKUP_OKRA_FUNCTION(okra_clearargs, okra_clearargs);
+      LOOKUP_OKRA_FUNCTION(okra_register_heap, okra_register_heap);
 
-      if (TraceGPUInteraction) {
-        tty->print_cr("[HSAIL] Success: library linkage _okra_clearargs=0x%08x", _okra_clearargs);
-      }
       return true;
     } else {
       // Unable to dlopen okra
--- a/src/gpu/hsail/vm/gpu_hsail.hpp	Mon Dec 02 12:44:53 2013 +0100
+++ b/src/gpu/hsail/vm/gpu_hsail.hpp	Mon Dec 02 12:45:18 2013 +0100
@@ -44,8 +44,8 @@
 #endif
 
 private:
-  typedef void* (*okra_ctx_create_func_t)();
-  typedef void* (*okra_kernel_create_func_t)(void*, unsigned char *, const char *);
+  typedef void* (*okra_create_context_func_t)();
+  typedef void* (*okra_create_kernel_func_t)(void*, unsigned char *, const char *);
   typedef bool (*okra_push_object_func_t)(void*, void*);
   typedef bool (*okra_push_boolean_func_t)(void*, jboolean);
   typedef bool (*okra_push_byte_func_t)(void*, jbyte);
@@ -58,8 +58,8 @@
   typedef bool (*okra_register_heap_func_t)(void*, size_t);
   
 public:
-  static okra_ctx_create_func_t                 _okra_ctx_create;
-  static okra_kernel_create_func_t              _okra_kernel_create;
+  static okra_create_context_func_t             _okra_create_context;
+  static okra_create_kernel_func_t              _okra_create_kernel;
   static okra_push_object_func_t                _okra_push_object;
   static okra_push_boolean_func_t               _okra_push_boolean;
   static okra_push_byte_func_t                  _okra_push_byte;
--- a/src/os_gpu/linux_ptx/vm/gpu_linux.cpp	Mon Dec 02 12:44:53 2013 +0100
+++ b/src/os_gpu/linux_ptx/vm/gpu_linux.cpp	Mon Dec 02 12:45:18 2013 +0100
@@ -81,13 +81,19 @@
         tty->print_cr("Found supported nVidia GPU device vendor : 0x%04x device 0x%04x", vendor, device);
       }
       break;
-    } else if (vendor == amd_vendor_id) {
-      gpu_device_exists = true;
-      set_target_il_type(gpu::HSAIL);
-      if (TraceGPUInteraction) {
-        tty->print_cr("Found supported AMD GPU device vendor : 0x%04x device 0x%04x", vendor, device);
-      }
-      break;
+       /*
+        * Remove AMD detection until we decide how to detect real HSA hardware.
+        * In the current form this check does not work correctly on AMD CPU system with 
+        * Nvidia GPU.
+        *
+        * } else if (vendor == amd_vendor_id) {
+        *   gpu_device_exists = true;
+        *   set_target_il_type(gpu::HSAIL);
+        *   if (TraceGPUInteraction) {
+        *     tty->print_cr("Found supported AMD GPU device vendor : 0x%04x device 0x%04x", vendor, device);
+        *   }
+        *   break;
+        */
     }
   }
 
--- a/src/share/vm/asm/codeBuffer.cpp	Mon Dec 02 12:44:53 2013 +0100
+++ b/src/share/vm/asm/codeBuffer.cpp	Mon Dec 02 12:45:18 2013 +0100
@@ -1096,8 +1096,9 @@
     CodeString* c = find(offset);
     while (c && c->offset() == offset) {
       stream->bol();
-      stream->print("  ;; ");
-      stream->print_cr(c->string());
+      stream->print_raw("  ;; ");
+      // Don't interpret as format strings since it could contain %
+      stream->print_raw_cr(c->string());
       c = c->next_comment();
     }
   }
--- a/src/share/vm/c1/c1_GraphBuilder.cpp	Mon Dec 02 12:44:53 2013 +0100
+++ b/src/share/vm/c1/c1_GraphBuilder.cpp	Mon Dec 02 12:45:18 2013 +0100
@@ -4340,11 +4340,15 @@
 #endif // PRODUCT
 
 void GraphBuilder::profile_call(ciMethod* callee, Value recv, ciKlass* known_holder, Values* obj_args, bool inlined) {
-  // A default method's holder is an interface
-  if (known_holder != NULL && known_holder->is_interface()) {
-    assert(known_holder->is_instance_klass() && ((ciInstanceKlass*)known_holder)->has_default_methods(), "should be default method");
-    known_holder = NULL;
+  assert(known_holder == NULL || (known_holder->is_instance_klass() &&
+                                  (!known_holder->is_interface() ||
+                                   ((ciInstanceKlass*)known_holder)->has_default_methods())), "should be default method");
+  if (known_holder != NULL) {
+    if (known_holder->exact_klass() == NULL) {
+      known_holder = compilation()->cha_exact_type(known_holder);
+    }
   }
+
   append(new ProfileCall(method(), bci(), callee, recv, known_holder, obj_args, inlined));
 }
 
--- a/src/share/vm/c1/c1_Runtime1.cpp	Mon Dec 02 12:44:53 2013 +0100
+++ b/src/share/vm/c1/c1_Runtime1.cpp	Mon Dec 02 12:45:18 2013 +0100
@@ -169,7 +169,7 @@
     RegisterMap reg_map(thread, false);
     frame runtime_frame = thread->last_frame();
     frame caller_frame = runtime_frame.sender(&reg_map);
-    Deoptimization::deoptimize_frame(thread, caller_frame.id(), Deoptimization::Reason_constraint);
+    Deoptimization::deoptimize_frame(thread, caller_frame.id());
     assert(caller_is_deopted(), "Must be deoptimized");
   }
 }
@@ -431,7 +431,7 @@
     if (osr_nm != NULL) {
       RegisterMap map(thread, false);
       frame fr =  thread->last_frame().sender(&map);
-      Deoptimization::deoptimize_frame(thread, fr.id(), Deoptimization::Reason_constraint);
+      Deoptimization::deoptimize_frame(thread, fr.id());
     }
   JRT_BLOCK_END
   return NULL;
@@ -502,7 +502,7 @@
     // We don't really want to deoptimize the nmethod itself since we
     // can actually continue in the exception handler ourselves but I
     // don't see an easy way to have the desired effect.
-    Deoptimization::deoptimize_frame(thread, caller_frame.id(), Deoptimization::Reason_constraint);
+    Deoptimization::deoptimize_frame(thread, caller_frame.id());
     assert(caller_is_deopted(), "Must be deoptimized");
 
     return SharedRuntime::deopt_blob()->unpack_with_exception_in_tls();
@@ -696,7 +696,7 @@
   assert(CodeCache::find_nmethod(caller_frame.pc()) != NULL, "sanity");
 
   // Deoptimize the caller frame.
-  Deoptimization::deoptimize_frame(thread, caller_frame.id(), Deoptimization::Reason_constraint);
+  Deoptimization::deoptimize_frame(thread, caller_frame.id());
 
   // Return to the now deoptimized frame.
 JRT_END
@@ -932,7 +932,7 @@
       nm->make_not_entrant();
     }
 
-    Deoptimization::deoptimize_frame(thread, caller_frame.id(), Deoptimization::Reason_constraint);
+    Deoptimization::deoptimize_frame(thread, caller_frame.id());
 
     // Return to the now deoptimized frame.
   }
@@ -1434,7 +1434,7 @@
   }
 
 
-  Deoptimization::deoptimize_frame(thread, caller_frame.id(), Deoptimization::Reason_none);
+  Deoptimization::deoptimize_frame(thread, caller_frame.id());
 
 JRT_END
 
--- a/src/share/vm/classfile/vmSymbols.hpp	Mon Dec 02 12:44:53 2013 +0100
+++ b/src/share/vm/classfile/vmSymbols.hpp	Mon Dec 02 12:45:18 2013 +0100
@@ -574,7 +574,6 @@
   template(char_array_void_signature,                 "([C)V")                                                    \
   template(int_int_void_signature,                    "(II)V")                                                    \
   template(long_long_void_signature,                  "(JJ)V")                                                    \
-  template(boolean_long_void_signature,               "(ZJ)V")                                                    \
   template(void_classloader_signature,                "()Ljava/lang/ClassLoader;")                                \
   template(void_object_signature,                     "()Ljava/lang/Object;")                                     \
   template(void_class_signature,                      "()Ljava/lang/Class;")                                      \
@@ -919,7 +918,7 @@
    do_signature(copyMemory_signature,         "(Ljava/lang/Object;JLjava/lang/Object;JJ)V")                             \
   do_intrinsic(_park,                     sun_misc_Unsafe,        park_name, park_signature,                     F_RN)  \
    do_name(     park_name,                                       "park")                                                \
-   do_alias(park_signature,                                       boolean_long_void_signature)                          \
+   do_signature(park_signature,                                  "(ZJ)V")                                               \
   do_intrinsic(_unpark,                   sun_misc_Unsafe,        unpark_name, unpark_signature,                 F_RN)  \
    do_name(     unpark_name,                                     "unpark")                                              \
    do_alias(    unpark_signature,                               /*(LObject;)V*/ object_void_signature)                  \
--- a/src/share/vm/compiler/compileBroker.cpp	Mon Dec 02 12:44:53 2013 +0100
+++ b/src/share/vm/compiler/compileBroker.cpp	Mon Dec 02 12:45:18 2013 +0100
@@ -2352,7 +2352,7 @@
       nmethods_size += stats->_nmethods_size;
       nmethods_code_size += stats->_nmethods_code_size;
 
-      tty->print_cr("  %s { speed: %d bytes/s; standard: %6.3f s, %d bytes, %d methods; osr: %6.3f s, %d bytes, %d methods; nmethods_size: %d bytes; nmethods_code_size: %d bytes}",
+      tty->print_cr("  %s {speed: %d bytes/s; standard: %6.3f s, %d bytes, %d methods; osr: %6.3f s, %d bytes, %d methods; nmethods_size: %d bytes; nmethods_code_size: %d bytes}",
           comp->name(), stats->bytes_per_second(),
           stats->_standard._time.seconds(), stats->_standard._bytes, stats->_standard._count,
           stats->_osr._time.seconds(), stats->_osr._bytes, stats->_osr._count,
--- a/src/share/vm/graal/graalCodeInstaller.cpp	Mon Dec 02 12:44:53 2013 +0100
+++ b/src/share/vm/graal/graalCodeInstaller.cpp	Mon Dec 02 12:45:18 2013 +0100
@@ -361,8 +361,13 @@
 
 // constructor used to create a method
 CodeInstaller::CodeInstaller(Handle& compiled_code, GraalEnv::CodeInstallResult& result, CodeBlob*& cb, Handle installed_code, Handle triggered_deoptimizations) {
-  GraalCompiler::initialize_buffer_blob();
-  CodeBuffer buffer(JavaThread::current()->get_buffer_blob());
+  BufferBlob* buffer_blob = GraalCompiler::initialize_buffer_blob();
+  if (buffer_blob == NULL) {
+    result = GraalEnv::cache_full;
+    return;
+  }
+
+  CodeBuffer buffer(buffer_blob);
   jobject compiled_code_obj = JNIHandles::make_local(compiled_code());
   initialize_assumptions(JNIHandles::resolve(compiled_code_obj));
 
--- a/src/share/vm/graal/graalCompiler.cpp	Mon Dec 02 12:44:53 2013 +0100
+++ b/src/share/vm/graal/graalCompiler.cpp	Mon Dec 02 12:45:18 2013 +0100
@@ -56,7 +56,13 @@
 
   _deopted_leaf_graph_count = 0;
 
-  initialize_buffer_blob();
+  BufferBlob* buffer_blob = initialize_buffer_blob();
+  if (buffer_blob == NULL) {
+    // If we are called from JNI_CreateJavaVM we cannot use set_state yet because it takes a lock.
+    // set_state(failed);
+  } else {
+    // set_state(initialized);
+  }
 
   JNIEnv *env = ((JavaThread *) Thread::current())->jni_environment();
   jclass klass = env->FindClass("com/oracle/graal/hotspot/bridge/CompilerToVMImpl");
@@ -98,19 +104,20 @@
         vm_abort(false);
       }
     }
-    VMToCompiler::finalizeOptions(CITime);
+    VMToCompiler::finalizeOptions(CITime || CITimeEach);
 
     if (UseCompiler) {
       bool bootstrap = GRAALVM_ONLY(BootstrapGraal) NOT_GRAALVM(false);
-      jlong compilerStatisticsAddress = (jlong) ((address) (stats()));
-      VMToCompiler::startCompiler(bootstrap, compilerStatisticsAddress);
+      VMToCompiler::startCompiler(bootstrap);
       _initialized = true;
       CompilationPolicy::completed_vm_startup();
       if (bootstrap) {
+        // Avoid -Xcomp and -Xbatch problems by turning on interpreter and background compilation for bootstrapping.
+        FlagSetting a(UseInterpreter, true);
+        FlagSetting b(BackgroundCompilation, true);
         VMToCompiler::bootstrap();
       }
 
-
 #ifndef PRODUCT
       if (CompileTheWorld) {
         // We turn off CompileTheWorld so that Graal can
@@ -164,14 +171,16 @@
   return array;
 }
 
-void GraalCompiler::initialize_buffer_blob() {
-
+BufferBlob* GraalCompiler::initialize_buffer_blob() {
   JavaThread* THREAD = JavaThread::current();
-  if (THREAD->get_buffer_blob() == NULL) {
-    BufferBlob* blob = BufferBlob::create("Graal thread-local CodeBuffer", GraalNMethodSizeLimit);
-    guarantee(blob != NULL, "must create code buffer");
-    THREAD->set_buffer_blob(blob);
+  BufferBlob* buffer_blob = THREAD->get_buffer_blob();
+  if (buffer_blob == NULL) {
+    buffer_blob = BufferBlob::create("Graal thread-local CodeBuffer", GraalNMethodSizeLimit);
+    if (buffer_blob != NULL) {
+      THREAD->set_buffer_blob(buffer_blob);
+    }
   }
+  return buffer_blob;
 }
 
 void GraalCompiler::compile_method(methodHandle method, int entry_bci, jboolean blocking) {
@@ -185,6 +194,7 @@
   ResourceMark rm;
   thread->set_is_graal_compiling(true);
   Handle holder = GraalCompiler::createHotSpotResolvedObjectType(method, CHECK);
+  check_pending_exception("Error while calling createHotSpotResolvedObjectType");
   VMToCompiler::compileMethod(method(), holder, entry_bci, blocking);
   thread->set_is_graal_compiling(false);
 }
--- a/src/share/vm/graal/graalCompiler.hpp	Mon Dec 02 12:44:53 2013 +0100
+++ b/src/share/vm/graal/graalCompiler.hpp	Mon Dec 02 12:45:18 2013 +0100
@@ -105,7 +105,7 @@
     return cp_index;
   }
 
-  static void initialize_buffer_blob();
+  static BufferBlob* initialize_buffer_blob();
 };
 
 // Tracing macros
--- a/src/share/vm/graal/graalCompilerToGPU.cpp	Mon Dec 02 12:44:53 2013 +0100
+++ b/src/share/vm/graal/graalCompilerToGPU.cpp	Mon Dec 02 12:45:18 2013 +0100
@@ -177,7 +177,9 @@
 
 C2V_VMENTRY(jboolean, deviceInit, (JNIEnv *env, jobject))
   if (gpu::is_available() == false || gpu::has_gpu_linkage() == false) {
-    tty->print_cr("deviceInit - not available / no linkage");
+    if (TraceGPUInteraction) {
+      tty->print_cr("deviceInit - not available / no linkage");
+    }
     return false;
   }
   if (gpu::is_initialized()) {
@@ -190,7 +192,9 @@
 
 C2V_VMENTRY(jint, availableProcessors, (JNIEnv *env, jobject))
   if (gpu::is_available() == false || gpu::has_gpu_linkage() == false) {
-    tty->print_cr("deviceInit - not available / no linkage");
+    if (TraceGPUInteraction) {
+      tty->print_cr("deviceInit - not available / no linkage");
+    }
     return false;
   }
   return gpu::available_processors();
--- a/src/share/vm/graal/graalCompilerToVM.cpp	Mon Dec 02 12:44:53 2013 +0100
+++ b/src/share/vm/graal/graalCompilerToVM.cpp	Mon Dec 02 12:45:18 2013 +0100
@@ -732,8 +732,6 @@
 
   set_int("instanceKlassVtableStartOffset", InstanceKlass::vtable_start_offset() * HeapWordSize);
 
-  set_long("elapsedTimerFrequency", os::elapsed_frequency());
-
   //------------------------------------------------------------------------------------------------
 
   set_address("handleDeoptStub", SharedRuntime::deopt_blob()->unpack());
@@ -827,6 +825,37 @@
   return result;
 C2V_END
 
+C2V_VMENTRY(void, notifyCompilationStatistics, (JNIEnv *jniEnv, jobject, jint id, jobject hotspot_method, jboolean osr, jint processedBytecodes, jlong time, jlong timeUnitsPerSecond, jobject installed_code))
+  CompilerStatistics* stats = GraalCompiler::instance()->stats();
+
+  elapsedTimer timer = elapsedTimer(time, timeUnitsPerSecond);
+  if (osr) {
+    stats->_osr.update(timer, processedBytecodes);
+  } else {
+    stats->_standard.update(timer, processedBytecodes);
+  }
+  Handle installed_code_handle = JNIHandles::resolve(installed_code);
+  stats->_nmethods_size += HotSpotInstalledCode::size(installed_code_handle);
+  stats->_nmethods_code_size += HotSpotInstalledCode::codeSize(installed_code_handle);
+
+  if (CITimeEach) {
+    methodHandle method = asMethod(HotSpotResolvedJavaMethod::metaspaceMethod(hotspot_method));
+    float bytes_per_sec = 1.0 * processedBytecodes / timer.seconds();
+    tty->print_cr("%3d   seconds: %f bytes/sec: %f (bytes %d)",
+                  id, timer.seconds(), bytes_per_sec, processedBytecodes);
+  }
+C2V_END
+
+C2V_VMENTRY(void, resetCompilationStatistics, (JNIEnv *jniEnv, jobject))
+  CompilerStatistics* stats = GraalCompiler::instance()->stats();
+  stats->_standard._time.reset();
+  stats->_standard._bytes = 0;
+  stats->_standard._count = 0;
+  stats->_osr._time.reset();
+  stats->_osr._bytes = 0;
+  stats->_osr._count = 0;
+C2V_END
+
 C2V_VMENTRY(jobject, disassembleCodeBlob, (JNIEnv *jniEnv, jobject, jlong codeBlob))
   ResourceMark rm;
   HandleMark hm;
@@ -996,7 +1025,7 @@
     method_data = MethodData::allocate(loader_data, method, CHECK);
     method->set_method_data(method_data);
   } else {
-    method_data->initialize();
+    method_data->initialize(true);
   }
 C2V_END
 
@@ -1098,6 +1127,8 @@
   {CC"getJavaField",                  CC"("REFLECT_FIELD")"HS_RESOLVED_FIELD,                           FN_PTR(getJavaField)},
   {CC"initializeConfiguration",       CC"("HS_CONFIG")V",                                               FN_PTR(initializeConfiguration)},
   {CC"installCode0",                  CC"("HS_COMPILED_CODE HS_INSTALLED_CODE"[Z)I",                    FN_PTR(installCode0)},
+  {CC"notifyCompilationStatistics",   CC"(I"HS_RESOLVED_METHOD"ZIJJ"HS_INSTALLED_CODE")V",              FN_PTR(notifyCompilationStatistics)},
+  {CC"resetCompilationStatistics",    CC"()V",                                                          FN_PTR(resetCompilationStatistics)},
   {CC"disassembleCodeBlob",           CC"(J)"STRING,                                                    FN_PTR(disassembleCodeBlob)},
   {CC"executeCompiledMethodVarargs",  CC"(["OBJECT HS_INSTALLED_CODE")"OBJECT,                          FN_PTR(executeCompiledMethodVarargs)},
   {CC"getDeoptedLeafGraphIds",        CC"()[J",                                                         FN_PTR(getDeoptedLeafGraphIds)},
--- a/src/share/vm/graal/graalEnv.hpp	Mon Dec 02 12:44:53 2013 +0100
+++ b/src/share/vm/graal/graalEnv.hpp	Mon Dec 02 12:45:18 2013 +0100
@@ -58,7 +58,6 @@
 
 public:
 
-  // Must be kept in sync with the enum in the HotSpot implementation of CompilerToVM
   enum CodeInstallResult {
      ok,
      dependencies_failed,
--- a/src/share/vm/graal/graalVMToCompiler.cpp	Mon Dec 02 12:44:53 2013 +0100
+++ b/src/share/vm/graal/graalVMToCompiler.cpp	Mon Dec 02 12:45:18 2013 +0100
@@ -146,14 +146,13 @@
   }
 }
 
-void VMToCompiler::startCompiler(jboolean bootstrap_enabled, jlong compilerStatisticsAddress) {
+void VMToCompiler::startCompiler(jboolean bootstrap_enabled) {
   JavaThread* THREAD = JavaThread::current();
   JavaValue result(T_VOID);
   JavaCallArguments args;
   args.push_oop(instance());
   args.push_int(bootstrap_enabled);
-  args.push_long(compilerStatisticsAddress);
-  JavaCalls::call_interface(&result, vmToCompilerKlass(), vmSymbols::startCompiler_name(), vmSymbols::boolean_long_void_signature(), &args, THREAD);
+  JavaCalls::call_interface(&result, vmToCompilerKlass(), vmSymbols::startCompiler_name(), vmSymbols::bool_void_signature(), &args, THREAD);
   check_pending_exception("Error while calling startCompiler");
 }
 
--- a/src/share/vm/graal/graalVMToCompiler.hpp	Mon Dec 02 12:44:53 2013 +0100
+++ b/src/share/vm/graal/graalVMToCompiler.hpp	Mon Dec 02 12:45:18 2013 +0100
@@ -67,7 +67,7 @@
   static void shutdownCompiler();
   
   // public abstract void startCompiler(boolean bootstrapEnabled);
-  static void startCompiler(jboolean bootstrap_enabled, jlong compilerStatisticsAddress);
+  static void startCompiler(jboolean bootstrap_enabled);
   
   // public abstract void bootstrap();
   static void bootstrap();
--- a/src/share/vm/graal/vmStructs_graal.hpp	Mon Dec 02 12:44:53 2013 +0100
+++ b/src/share/vm/graal/vmStructs_graal.hpp	Mon Dec 02 12:45:18 2013 +0100
@@ -26,24 +26,18 @@
 #define SHARE_VM_GRAAL_VMSTRUCTS_GRAAL_HPP
 
 #include "compiler/abstractCompiler.hpp"
+#include "graal/graalEnv.hpp"
 
 #define VM_STRUCTS_GRAAL(nonstatic_field, static_field)                       \
-                                                                              \
   static_field(java_lang_Class, _graal_mirror_offset, int)                    \
-                                                                              \
-  nonstatic_field(CompilerStatistics, _standard,           CompilerStatistics::Data) \
-  nonstatic_field(CompilerStatistics, _osr,                CompilerStatistics::Data) \
-  nonstatic_field(CompilerStatistics, _nmethods_size,      int)                      \
-  nonstatic_field(CompilerStatistics, _nmethods_code_size, int)                      \
-  nonstatic_field(CompilerStatistics::Data, _bytes,        int)                      \
-  nonstatic_field(CompilerStatistics::Data, _count,        int)                      \
-  nonstatic_field(CompilerStatistics::Data, _time,         elapsedTimer)             \
-
 
 #define VM_TYPES_GRAAL(declare_type, declare_toplevel_type)                   \
-                                                                              \
-  declare_toplevel_type(CompilerStatistics)                                   \
-  declare_toplevel_type(CompilerStatistics::Data)                             \
 
+#define VM_INT_CONSTANTS_GRAAL(declare_constant)                              \
+  declare_constant(Deoptimization::Reason_aliasing)                           \
+  declare_constant(GraalEnv::ok)                                              \
+  declare_constant(GraalEnv::dependencies_failed)                             \
+  declare_constant(GraalEnv::cache_full)                                      \
+  declare_constant(GraalEnv::code_too_large)                                  \
 
 #endif // SHARE_VM_GRAAL_VMSTRUCTS_GRAAL_HPP
--- a/src/share/vm/oops/methodData.cpp	Mon Dec 02 12:44:53 2013 +0100
+++ b/src/share/vm/oops/methodData.cpp	Mon Dec 02 12:45:18 2013 +0100
@@ -397,7 +397,11 @@
   for (row = 0; row < row_limit(); row++) {
     if (receiver(row) != NULL)  entries++;
   }
+#ifdef GRAAL
+  st->print_cr("count(%u) nonprofiled_count(%u) entries(%u)", count(), nonprofiled_count(), entries);
+#else
   st->print_cr("count(%u) entries(%u)", count(), entries);
+#endif
   int total = count();
   for (row = 0; row < row_limit(); row++) {
     if (receiver(row) != NULL) {
@@ -416,9 +420,38 @@
   print_shared(st, "ReceiverTypeData");
   print_receiver_data_on(st);
 }
+
+#ifdef GRAAL
+void VirtualCallData::print_method_data_on(outputStream* st) const {
+  uint row;
+  int entries = 0;
+  for (row = 0; row < method_row_limit(); row++) {
+    if (method(row) != NULL) entries++;
+  }
+  tab(st);
+  st->print_cr("method_entries(%u)", entries);
+  int total = count();
+  for (row = 0; row < method_row_limit(); row++) {
+    if (method(row) != NULL) {
+      total += method_count(row);
+    }
+  }
+  for (row = 0; row < method_row_limit(); row++) {
+    if (method(row) != NULL) {
+      tab(st);
+      method(row)->print_value_on(st);
+      st->print_cr("(%u %4.2f)", method_count(row), (float) method_count(row) / (float) total);
+    }
+  }
+}
+#endif
+
 void VirtualCallData::print_data_on(outputStream* st) const {
   print_shared(st, "VirtualCallData");
   print_receiver_data_on(st);
+#ifdef GRAAL
+  print_method_data_on(st);
+#endif
 }
 #endif // !PRODUCT
 
@@ -788,8 +821,7 @@
   while ((c = stream.next()) >= 0) {
     int size_in_bytes = compute_data_size(&stream);
     data_size += size_in_bytes;
-
-    if (is_empty_data(size_in_bytes, c)) empty_bc_count += 1;
+    if (size_in_bytes == 0 GRAAL_ONLY(&& Bytecodes::can_trap(c)))  empty_bc_count += 1;
   }
   int object_size = in_bytes(data_offset()) + data_size;
 
@@ -797,7 +829,6 @@
   int extra_data_count = compute_extra_data_count(data_size, empty_bc_count);
   object_size += extra_data_count * DataLayout::compute_size_in_bytes(0);
 
-#ifndef GRAALVM
   // Add a cell to record information about modified arguments.
   int arg_size = method->size_of_parameters();
   object_size += DataLayout::compute_size_in_bytes(arg_size+1);
@@ -808,7 +839,6 @@
   if (args_cell > 0) {
     object_size += DataLayout::compute_size_in_bytes(args_cell);
   }
-#endif
   return object_size;
 }
 
@@ -1018,7 +1048,7 @@
   initialize();
 }
 
-void MethodData::initialize() {
+void MethodData::initialize(bool for_reprofile) {
   No_Safepoint_Verifier no_safepoint;  // init function atomic wrt GC
   ResourceMark rm;
 
@@ -1035,8 +1065,7 @@
   while ((c = stream.next()) >= 0) {
     int size_in_bytes = initialize_data(&stream, data_size);
     data_size += size_in_bytes;
-
-    if (is_empty_data(size_in_bytes, c)) empty_bc_count += 1;
+    if (size_in_bytes == 0 GRAAL_ONLY(&& Bytecodes::can_trap(c)))  empty_bc_count += 1;
   }
   _data_size = data_size;
   int object_size = in_bytes(data_offset()) + data_size;
@@ -1044,11 +1073,14 @@
   // Add some extra DataLayout cells (at least one) to track stray traps.
   int extra_data_count = compute_extra_data_count(data_size, empty_bc_count);
   int extra_size = extra_data_count * DataLayout::compute_size_in_bytes(0);
-  object_size += extra_size;
 
-  Copy::zero_to_bytes((HeapWord*) extra_data_base(), extra_size);
+#ifdef GRAAL
+  if (for_reprofile) {
+    // Clear out extra data
+    Copy::zero_to_bytes((HeapWord*) extra_data_base(), extra_size);
+  }
+#endif
 
-#ifndef GRAALVM
   // Add a cell to record information about modified arguments.
   // Set up _args_modified array after traps cells so that
   // the code for traps cells works.
@@ -1074,9 +1106,6 @@
   } else {
     _parameters_type_data_di = -1;
   }
-#else
-  _parameters_type_data_di = -1;
-#endif
 
   // Set an initial hint. Don't use set_hint_di() because
   // first_di() may be out of bounds if data_size is 0.
@@ -1086,6 +1115,7 @@
 
   post_initialize(&stream);
 
+  assert(object_size == compute_allocation_size_in_bytes(methodHandle(_method)), "MethodData: computed size != initialized size");
   set_size(object_size);
 }
 
@@ -1110,14 +1140,6 @@
                       sizeof(_trap_hist) / sizeof(HeapWord));
 }
 
-bool MethodData::is_empty_data(int size_in_bytes, Bytecodes::Code code) {
-#ifdef GRAAL
-  return size_in_bytes == 0 && Bytecodes::can_trap(code);
-#else
-  return size_in_bytes == 0;
-#endif
-}
-
 // Get a measure of how much mileage the method has on it.
 int MethodData::mileage_of(Method* method) {
   int mileage = 0;
--- a/src/share/vm/oops/methodData.hpp	Mon Dec 02 12:44:53 2013 +0100
+++ b/src/share/vm/oops/methodData.hpp	Mon Dec 02 12:45:18 2013 +0100
@@ -1079,7 +1079,7 @@
     //          TODO (chaeubl): in fact, Graal should also increment the count for failed type checks to mimic the C1/C2 behavior
     // VirtualCallData for invokevirtual/invokeinterface:
     //   C1/C2: count is incremented on type overflow
-    //   Graal: count is incremented on type overflow, nonprofiled_count is increment on method overflow
+    //   Graal: count is incremented on type overflow, nonprofiled_count is incremented on method overflow
 
     // Graal is interested in knowing the percentage of type checks involving a type not explicitly in the profile
     nonprofiled_count_off_set = counter_cell_count,
@@ -1183,6 +1183,9 @@
   static ByteSize nonprofiled_receiver_count_offset() {
     return cell_offset(nonprofiled_count_off_set);
   }
+  uint nonprofiled_count() const {
+    return uint_at(nonprofiled_count_off_set);
+  }
   void set_nonprofiled_count(uint count) {
     set_uint_at(nonprofiled_count_off_set, count);
   }
@@ -1245,7 +1248,7 @@
     return MethodProfileWidth;
   }
 
-  Method* method(uint row) {
+  Method* method(uint row) const {
     assert(row < method_row_limit(), "oob");
 
     Method* method = (Method*)intptr_at(method_cell_index(row));
@@ -1253,6 +1256,11 @@
     return method;
   }
 
+  uint method_count(uint row) const {
+    assert(row < method_row_limit(), "oob");
+    return uint_at(method_count_cell_index(row));
+  }
+
   void set_method(uint row, Method* m) {
     assert((uint)row < method_row_limit(), "oob");
     set_intptr_at(method_cell_index(row), (uintptr_t)m);
@@ -1276,6 +1284,9 @@
 #endif
 
 #ifndef PRODUCT
+#ifdef GRAAL
+  void print_method_data_on(outputStream* st) const;
+#endif
   void print_data_on(outputStream* st) const;
 #endif
 };
@@ -1885,7 +1896,7 @@
   MethodData() {}; // For ciMethodData
 
   bool is_methodData() const volatile { return true; }
-  void initialize();
+  void initialize(bool for_reprofile = false);
 
   // Whole-method sticky bits and flags
   enum {
@@ -2092,7 +2103,6 @@
 
   bool is_mature() const;  // consult mileage and ProfileMaturityPercentage
   static int mileage_of(Method* m);
-  static bool is_empty_data(int size, Bytecodes::Code code);
 
   // Support for interprocedural escape analysis, from Thomas Kotzmann.
   enum EscapeFlag {
--- a/src/share/vm/opto/runtime.cpp	Mon Dec 02 12:44:53 2013 +0100
+++ b/src/share/vm/opto/runtime.cpp	Mon Dec 02 12:45:18 2013 +0100
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -1185,7 +1186,7 @@
   frame caller_frame = stub_frame.sender(&reg_map);
 
   // Deoptimize the caller frame.
-  Deoptimization::deoptimize_frame(thread, caller_frame.id(), Deoptimization::Reason_constraint);
+  Deoptimization::deoptimize_frame(thread, caller_frame.id());
 }
 
 
--- a/src/share/vm/prims/jni.cpp	Mon Dec 02 12:44:53 2013 +0100
+++ b/src/share/vm/prims/jni.cpp	Mon Dec 02 12:45:18 2013 +0100
@@ -5176,7 +5176,11 @@
 #ifdef GRAAL
     // GraalCompiler needs to have been created in compileBroker.cpp
     GraalCompiler* graal_compiler = GraalCompiler::instance();
-    graal_compiler->initialize();
+    if (graal_compiler != NULL) {
+      graal_compiler->initialize();
+    } else {
+      assert(!UseCompiler, "why isn't there are compiler?");
+    }
 #endif
 
     // Tracks the time application was running before GC
--- a/src/share/vm/prims/jvmtiEnv.cpp	Mon Dec 02 12:44:53 2013 +0100
+++ b/src/share/vm/prims/jvmtiEnv.cpp	Mon Dec 02 12:45:18 2013 +0100
@@ -1442,7 +1442,7 @@
     // If any of the top 2 frames is a compiled one, need to deoptimize it
     for (int i = 0; i < 2; i++) {
       if (!is_interpreted[i]) {
-        Deoptimization::deoptimize_frame(java_thread, frame_sp[i], Deoptimization::Reason_constraint);
+        Deoptimization::deoptimize_frame(java_thread, frame_sp[i]);
       }
     }
 
--- a/src/share/vm/prims/jvmtiEnvBase.cpp	Mon Dec 02 12:44:53 2013 +0100
+++ b/src/share/vm/prims/jvmtiEnvBase.cpp	Mon Dec 02 12:45:18 2013 +0100
@@ -1338,7 +1338,7 @@
     if (!vf->fr().can_be_deoptimized()) {
       return JVMTI_ERROR_OPAQUE_FRAME;
     }
-    Deoptimization::deoptimize_frame(java_thread, jvf->fr().id(), Deoptimization::Reason_constraint);
+    Deoptimization::deoptimize_frame(java_thread, jvf->fr().id());
   }
 
   // Get information about method return type
--- a/src/share/vm/prims/jvmtiImpl.cpp	Mon Dec 02 12:44:53 2013 +0100
+++ b/src/share/vm/prims/jvmtiImpl.cpp	Mon Dec 02 12:45:18 2013 +0100
@@ -752,7 +752,7 @@
 
       // Schedule deoptimization so that eventually the local
       // update will be written to an interpreter frame.
-      Deoptimization::deoptimize_frame(_jvf->thread(), _jvf->fr().id(), Deoptimization::Reason_constraint);
+      Deoptimization::deoptimize_frame(_jvf->thread(), _jvf->fr().id());
 
       // Now store a new value for the local which will be applied
       // once deoptimization occurs. Note however that while this
--- a/src/share/vm/runtime/deoptimization.cpp	Mon Dec 02 12:44:53 2013 +0100
+++ b/src/share/vm/runtime/deoptimization.cpp	Mon Dec 02 12:45:18 2013 +0100
@@ -1214,6 +1214,10 @@
   fr.deoptimize(thread);
 }
 
+void Deoptimization::deoptimize(JavaThread* thread, frame fr, RegisterMap *map) {
+  deoptimize(thread, fr, map, Reason_constraint);
+}
+
 void Deoptimization::deoptimize(JavaThread* thread, frame fr, RegisterMap *map, DeoptReason reason) {
   // Deoptimize only if the frame comes from compile code.
   // Do not deoptimize the frame which is already patched
@@ -1253,6 +1257,9 @@
   }
 }
 
+void Deoptimization::deoptimize_frame(JavaThread* thread, intptr_t* id) {
+  deoptimize_frame(thread, id, Reason_constraint);
+}
 
 // JVMTI PopFrame support
 JRT_LEAF(void, Deoptimization::popframe_preserve_args(JavaThread* thread, int bytes_to_save, void* start_address))
@@ -1948,7 +1955,8 @@
   "div0_check",
   "age" GRAAL_ONLY("|jsr_mismatch"),
   "predicate",
-  "loop_limit_check"
+  "loop_limit_check",
+  GRAAL_ONLY("aliasing")
 };
 const char* Deoptimization::_trap_action_name[Action_LIMIT] = {
   // Note:  Keep this in sync. with enum DeoptAction.
--- a/src/share/vm/runtime/deoptimization.hpp	Mon Dec 02 12:44:53 2013 +0100
+++ b/src/share/vm/runtime/deoptimization.hpp	Mon Dec 02 12:45:18 2013 +0100
@@ -72,6 +72,9 @@
     Reason_age,                   // nmethod too old; tier threshold reached
     Reason_predicate,             // compiler generated predicate failed
     Reason_loop_limit_check,      // compiler generated loop limits check failed
+#ifdef GRAAL
+    Reason_aliasing,              // optimistic assumption about aliasing failed
+#endif
     Reason_LIMIT,
 
 #ifdef GRAAL
@@ -121,6 +124,7 @@
   static int deoptimize_dependents();
 
   // Deoptimizes a frame lazily. nmethod gets patched deopt happens on return to the frame
+  static void deoptimize(JavaThread* thread, frame fr, RegisterMap *reg_map);
   static void deoptimize(JavaThread* thread, frame fr, RegisterMap *reg_map, DeoptReason reason);
 
   private:
@@ -261,6 +265,7 @@
   // if thread is not the current thread then execute
   // VM_DeoptimizeFrame otherwise deoptimize directly.
   static void deoptimize_frame(JavaThread* thread, intptr_t* id, DeoptReason reason);
+  static void deoptimize_frame(JavaThread* thread, intptr_t* id);
 
   // Statistics
   static void gather_statistics(DeoptReason reason, DeoptAction action,
--- a/src/share/vm/runtime/java.cpp	Mon Dec 02 12:44:53 2013 +0100
+++ b/src/share/vm/runtime/java.cpp	Mon Dec 02 12:45:18 2013 +0100
@@ -462,7 +462,9 @@
   static jint volatile _before_exit_status = BEFORE_EXIT_NOT_RUN;
 
 #ifdef GRAAL
-  GraalCompiler::instance()->exit();
+  if (GraalCompiler::instance() != NULL) {
+    GraalCompiler::instance()->exit();
+  }
 #endif
 
   // Note: don't use a Mutex to guard the entire before_exit(), as
--- a/src/share/vm/runtime/safepoint.cpp	Mon Dec 02 12:44:53 2013 +0100
+++ b/src/share/vm/runtime/safepoint.cpp	Mon Dec 02 12:45:18 2013 +0100
@@ -1081,7 +1081,7 @@
     // as otherwise we may never deliver it.
     if (thread()->has_async_condition()) {
       ThreadInVMfromJavaNoAsyncException __tiv(thread());
-      Deoptimization::deoptimize_frame(thread(), caller_fr.id(), Deoptimization::Reason_constraint);
+      Deoptimization::deoptimize_frame(thread(), caller_fr.id());
     }
 
     // If an exception has been installed we must check for a pending deoptimization
--- a/src/share/vm/runtime/thread.cpp	Mon Dec 02 12:44:53 2013 +0100
+++ b/src/share/vm/runtime/thread.cpp	Mon Dec 02 12:45:18 2013 +0100
@@ -2265,7 +2265,7 @@
           RegisterMap reg_map(this, UseBiasedLocking);
           frame compiled_frame = f.sender(&reg_map);
           if (!StressCompiledExceptionHandlers && compiled_frame.can_be_deoptimized()) {
-            Deoptimization::deoptimize(this, compiled_frame, &reg_map, Deoptimization::Reason_constraint);
+            Deoptimization::deoptimize(this, compiled_frame, &reg_map);
           }
         }
       }
@@ -2698,7 +2698,7 @@
         trace_frames();
         trace_stack();
       }
-      Deoptimization::deoptimize(this, *fst.current(), fst.register_map(), Deoptimization::Reason_constraint);
+      Deoptimization::deoptimize(this, *fst.current(), fst.register_map());
     }
   }
 
@@ -2734,7 +2734,7 @@
                    this->name(), nm != NULL ? nm->compile_id() : -1);
       }
 
-      Deoptimization::deoptimize(this, *fst.current(), fst.register_map(), Deoptimization::Reason_constraint);
+      Deoptimization::deoptimize(this, *fst.current(), fst.register_map());
     }
   }
 }
@@ -3378,10 +3378,6 @@
   // Initialize the os module before using TLS
   os::init();
 
-  // Probe for existance of supported GPU and initialize it if one
-  // exists.
-  gpu::init();
-
   // Initialize system properties.
   Arguments::init_system_properties();
 
@@ -3395,6 +3391,10 @@
   jint parse_result = Arguments::parse(args);
   if (parse_result != JNI_OK) return parse_result;
 
+  // Probe for existance of supported GPU and initialize it if one
+  // exists.
+  gpu::init();
+
   os::init_before_ergo();
 
   jint ergo_result = Arguments::apply_ergo();
--- a/src/share/vm/runtime/timer.cpp	Mon Dec 02 12:44:53 2013 +0100
+++ b/src/share/vm/runtime/timer.cpp	Mon Dec 02 12:45:18 2013 +0100
@@ -45,6 +45,22 @@
   return counter/freq;
 }
 
+elapsedTimer::elapsedTimer(jlong time, jlong timeUnitsPerSecond) {
+  _active = false;
+  jlong osTimeUnitsPerSecond = os::elapsed_frequency();
+  assert(osTimeUnitsPerSecond % 1000 == 0, "must be");
+  assert(timeUnitsPerSecond % 1000 == 0, "must be");
+  while (osTimeUnitsPerSecond < timeUnitsPerSecond) {
+    timeUnitsPerSecond /= 1000;
+    time *= 1000;
+  }
+  while (osTimeUnitsPerSecond > timeUnitsPerSecond) {
+    timeUnitsPerSecond *= 1000;
+    time /= 1000;
+  }
+  _counter = time;
+}
+
 void elapsedTimer::add(elapsedTimer t) {
   _counter += t._counter;
 }
--- a/src/share/vm/runtime/timer.hpp	Mon Dec 02 12:44:53 2013 +0100
+++ b/src/share/vm/runtime/timer.hpp	Mon Dec 02 12:45:18 2013 +0100
@@ -37,6 +37,7 @@
   bool  _active;
  public:
   elapsedTimer()             { _active = false; reset(); }
+  elapsedTimer(jlong time, jlong timeUnitsPerSecond);
   void add(elapsedTimer t);
   void start();
   void stop();
--- a/src/share/vm/runtime/vframeArray.cpp	Mon Dec 02 12:44:53 2013 +0100
+++ b/src/share/vm/runtime/vframeArray.cpp	Mon Dec 02 12:45:18 2013 +0100
@@ -251,9 +251,6 @@
       case Deoptimization::Unpack_uncommon_trap:
       case Deoptimization::Unpack_reexecute:
         // redo last byte code
-#ifdef GRAALVM
-        assert(should_reexecute(), "");
-#endif
         pc  = Interpreter::deopt_entry(vtos, 0);
         use_next_mdp = false;
         break;
--- a/src/share/vm/runtime/vmStructs.cpp	Mon Dec 02 12:44:53 2013 +0100
+++ b/src/share/vm/runtime/vmStructs.cpp	Mon Dec 02 12:45:18 2013 +0100
@@ -2373,6 +2373,19 @@
   /**************/                                                        \
                                                                           \
   declare_constant(DataLayout::cell_size)                                 \
+  declare_constant(DataLayout::no_tag)                                    \
+  declare_constant(DataLayout::bit_data_tag)                              \
+  declare_constant(DataLayout::counter_data_tag)                          \
+  declare_constant(DataLayout::jump_data_tag)                             \
+  declare_constant(DataLayout::receiver_type_data_tag)                    \
+  declare_constant(DataLayout::virtual_call_data_tag)                     \
+  declare_constant(DataLayout::ret_data_tag)                              \
+  declare_constant(DataLayout::branch_data_tag)                           \
+  declare_constant(DataLayout::multi_branch_data_tag)                     \
+  declare_constant(DataLayout::arg_info_data_tag)                         \
+  declare_constant(DataLayout::call_type_data_tag)                        \
+  declare_constant(DataLayout::virtual_call_type_data_tag)                \
+  declare_constant(DataLayout::parameters_type_data_tag)                  \
                                                                           \
   /*************************************/                                 \
   /* InstanceKlass enum                */                                 \
@@ -3011,6 +3024,10 @@
                    GENERATE_C2_VM_INT_CONSTANT_ENTRY,
                    GENERATE_C2_PREPROCESSOR_VM_INT_CONSTANT_ENTRY)
 
+#ifdef GRAAL
+  VM_INT_CONSTANTS_GRAAL(GENERATE_VM_INT_CONSTANT_ENTRY)
+#endif
+
 #if INCLUDE_ALL_GCS
   VM_INT_CONSTANTS_CMS(GENERATE_VM_INT_CONSTANT_ENTRY)
 
--- a/src/share/vm/runtime/vm_operations.cpp	Mon Dec 02 12:44:53 2013 +0100
+++ b/src/share/vm/runtime/vm_operations.cpp	Mon Dec 02 12:45:18 2013 +0100
@@ -150,7 +150,7 @@
             if (fst.current()->can_be_deoptimized()) {
               if (fcount++ == fnum) {
                 fcount = 0;
-                Deoptimization::deoptimize(thread, *fst.current(), fst.register_map(), Deoptimization::Reason_constraint);
+                Deoptimization::deoptimize(thread, *fst.current(), fst.register_map());
               }
             }
           }