changeset 9704:f9a65a0e626b

Merge.
author Christian Haeubl <haeubl@ssw.jku.at>
date Mon, 13 May 2013 17:11:31 +0200
parents 57113d21ce36 (current diff) 822adbb2ee7b (diff)
children de7319e48e48
files graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/IdentityHashCodeStubCall.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArraySlowStubCall.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceSlowStubCall.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSnippetUtils.java graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Reflection_getCallerClass01.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ComputeProbabilityClosure.java graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/nodes/CyclicMaterializeStoreNode.java graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/nodes/MaterializeObjectNode.java src/cpu/x86/vm/graalRuntime_x86.cpp src/cpu/x86/vm/graalStubAssembler_x86.cpp
diffstat 424 files changed, 12801 insertions(+), 6713 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.amd64/src/com/oracle/graal/amd64/AMD64.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.amd64/src/com/oracle/graal/amd64/AMD64.java	Mon May 13 17:11:31 2013 +0200
@@ -23,12 +23,12 @@
 package com.oracle.graal.amd64;
 
 import static com.oracle.graal.api.code.MemoryBarriers.*;
-import static com.oracle.graal.api.code.Register.RegisterFlag.*;
+import static com.oracle.graal.api.code.Register.*;
 
 import java.nio.*;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.Register.RegisterFlag;
+import com.oracle.graal.api.code.Register.RegisterCategory;
 import com.oracle.graal.api.meta.*;
 
 /**
@@ -36,26 +36,29 @@
  */
 public class AMD64 extends Architecture {
 
+    public static final RegisterCategory CPU = new RegisterCategory("CPU");
+    public static final RegisterCategory XMM = new RegisterCategory("XMM");
+
     // @formatter:off
 
     // General purpose CPU registers
-    public static final Register rax = new Register(0, 0, 8, "rax", CPU, RegisterFlag.Byte);
-    public static final Register rcx = new Register(1, 1, 8, "rcx", CPU, RegisterFlag.Byte);
-    public static final Register rdx = new Register(2, 2, 8, "rdx", CPU, RegisterFlag.Byte);
-    public static final Register rbx = new Register(3, 3, 8, "rbx", CPU, RegisterFlag.Byte);
-    public static final Register rsp = new Register(4, 4, 8, "rsp", CPU, RegisterFlag.Byte);
-    public static final Register rbp = new Register(5, 5, 8, "rbp", CPU, RegisterFlag.Byte);
-    public static final Register rsi = new Register(6, 6, 8, "rsi", CPU, RegisterFlag.Byte);
-    public static final Register rdi = new Register(7, 7, 8, "rdi", CPU, RegisterFlag.Byte);
+    public static final Register rax = new Register(0, 0, "rax", CPU);
+    public static final Register rcx = new Register(1, 1, "rcx", CPU);
+    public static final Register rdx = new Register(2, 2, "rdx", CPU);
+    public static final Register rbx = new Register(3, 3, "rbx", CPU);
+    public static final Register rsp = new Register(4, 4, "rsp", CPU);
+    public static final Register rbp = new Register(5, 5, "rbp", CPU);
+    public static final Register rsi = new Register(6, 6, "rsi", CPU);
+    public static final Register rdi = new Register(7, 7, "rdi", CPU);
 
-    public static final Register r8  = new Register(8,  8,  8, "r8", CPU, RegisterFlag.Byte);
-    public static final Register r9  = new Register(9,  9,  8, "r9", CPU, RegisterFlag.Byte);
-    public static final Register r10 = new Register(10, 10, 8, "r10", CPU, RegisterFlag.Byte);
-    public static final Register r11 = new Register(11, 11, 8, "r11", CPU, RegisterFlag.Byte);
-    public static final Register r12 = new Register(12, 12, 8, "r12", CPU, RegisterFlag.Byte);
-    public static final Register r13 = new Register(13, 13, 8, "r13", CPU, RegisterFlag.Byte);
-    public static final Register r14 = new Register(14, 14, 8, "r14", CPU, RegisterFlag.Byte);
-    public static final Register r15 = new Register(15, 15, 8, "r15", CPU, RegisterFlag.Byte);
+    public static final Register r8  = new Register(8,  8,  "r8", CPU);
+    public static final Register r9  = new Register(9,  9,  "r9", CPU);
+    public static final Register r10 = new Register(10, 10, "r10", CPU);
+    public static final Register r11 = new Register(11, 11, "r11", CPU);
+    public static final Register r12 = new Register(12, 12, "r12", CPU);
+    public static final Register r13 = new Register(13, 13, "r13", CPU);
+    public static final Register r14 = new Register(14, 14, "r14", CPU);
+    public static final Register r15 = new Register(15, 15, "r15", CPU);
 
     public static final Register[] cpuRegisters = {
         rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi,
@@ -63,23 +66,23 @@
     };
 
     // XMM registers
-    public static final Register xmm0 = new Register(16, 0, 8, "xmm0", FPU);
-    public static final Register xmm1 = new Register(17, 1, 8, "xmm1", FPU);
-    public static final Register xmm2 = new Register(18, 2, 8, "xmm2", FPU);
-    public static final Register xmm3 = new Register(19, 3, 8, "xmm3", FPU);
-    public static final Register xmm4 = new Register(20, 4, 8, "xmm4", FPU);
-    public static final Register xmm5 = new Register(21, 5, 8, "xmm5", FPU);
-    public static final Register xmm6 = new Register(22, 6, 8, "xmm6", FPU);
-    public static final Register xmm7 = new Register(23, 7, 8, "xmm7", FPU);
+    public static final Register xmm0 = new Register(16, 0, "xmm0", XMM);
+    public static final Register xmm1 = new Register(17, 1, "xmm1", XMM);
+    public static final Register xmm2 = new Register(18, 2, "xmm2", XMM);
+    public static final Register xmm3 = new Register(19, 3, "xmm3", XMM);
+    public static final Register xmm4 = new Register(20, 4, "xmm4", XMM);
+    public static final Register xmm5 = new Register(21, 5, "xmm5", XMM);
+    public static final Register xmm6 = new Register(22, 6, "xmm6", XMM);
+    public static final Register xmm7 = new Register(23, 7, "xmm7", XMM);
 
-    public static final Register xmm8 =  new Register(24,  8, 8, "xmm8",  FPU);
-    public static final Register xmm9 =  new Register(25,  9, 8, "xmm9",  FPU);
-    public static final Register xmm10 = new Register(26, 10, 8, "xmm10", FPU);
-    public static final Register xmm11 = new Register(27, 11, 8, "xmm11", FPU);
-    public static final Register xmm12 = new Register(28, 12, 8, "xmm12", FPU);
-    public static final Register xmm13 = new Register(29, 13, 8, "xmm13", FPU);
-    public static final Register xmm14 = new Register(30, 14, 8, "xmm14", FPU);
-    public static final Register xmm15 = new Register(31, 15, 8, "xmm15", FPU);
+    public static final Register xmm8 =  new Register(24,  8, "xmm8",  XMM);
+    public static final Register xmm9 =  new Register(25,  9, "xmm9",  XMM);
+    public static final Register xmm10 = new Register(26, 10, "xmm10", XMM);
+    public static final Register xmm11 = new Register(27, 11, "xmm11", XMM);
+    public static final Register xmm12 = new Register(28, 12, "xmm12", XMM);
+    public static final Register xmm13 = new Register(29, 13, "xmm13", XMM);
+    public static final Register xmm14 = new Register(30, 14, "xmm14", XMM);
+    public static final Register xmm15 = new Register(31, 15, "xmm15", XMM);
 
     public static final Register[] xmmRegisters = {
         xmm0, xmm1, xmm2,  xmm3,  xmm4,  xmm5,  xmm6,  xmm7,
@@ -96,7 +99,7 @@
     /**
      * Register used to construct an instruction-relative address.
      */
-    public static final Register rip = new Register(32, -1, 0, "rip");
+    public static final Register rip = new Register(32, -1, "rip", SPECIAL);
 
     public static final Register[] allRegisters = {
         rax,  rcx,  rdx,   rbx,   rsp,   rbp,   rsi,   rdi,
@@ -124,54 +127,6 @@
     }
     // @formatter:on
 
-    @Override
-    public int getMaxVectorLength(Kind kind) {
-        if (supportedAVXVersion > 0) {
-            switch (kind) {
-                case Boolean:
-                    return 32;
-                case Byte:
-                    return 32;
-                case Short:
-                    return 16;
-                case Char:
-                    return 16;
-                case Int:
-                    return 8;
-                case Float:
-                    return 8;
-                case Long:
-                    return 4;
-                case Double:
-                    return 4;
-                case Object:
-                    return 4;
-            }
-        } else {
-            switch (kind) {
-                case Boolean:
-                    return 16;
-                case Byte:
-                    return 16;
-                case Short:
-                    return 8;
-                case Char:
-                    return 8;
-                case Int:
-                    return 4;
-                case Float:
-                    return 4;
-                case Long:
-                    return 2;
-                case Double:
-                    return 2;
-                case Object:
-                    return 2;
-            }
-        }
-        return 1;
-    }
-
     public int getSupportedSSEVersion() {
         return supportedSSEVersion;
     }
@@ -179,4 +134,44 @@
     public int getSupportedAVXVersion() {
         return supportedAVXVersion;
     }
+
+    @Override
+    public boolean canStoreValue(RegisterCategory category, PlatformKind platformKind) {
+        if (!(platformKind instanceof Kind)) {
+            return false;
+        }
+
+        Kind kind = (Kind) platformKind;
+        if (category == CPU) {
+            switch (kind) {
+                case Boolean:
+                case Byte:
+                case Char:
+                case Short:
+                case Int:
+                case Long:
+                case Object:
+                    return true;
+            }
+        } else if (category == XMM) {
+            switch (kind) {
+                case Float:
+                case Double:
+                    return true;
+            }
+        }
+
+        return false;
+    }
+
+    @Override
+    public PlatformKind getLargestStorableKind(RegisterCategory category) {
+        if (category == CPU) {
+            return Kind.Long;
+        } else if (category == XMM) {
+            return Kind.Double;
+        } else {
+            return Kind.Illegal;
+        }
+    }
 }
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Architecture.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Architecture.java	Mon May 13 17:11:31 2013 +0200
@@ -24,6 +24,7 @@
 
 import java.nio.*;
 
+import com.oracle.graal.api.code.Register.RegisterCategory;
 import com.oracle.graal.api.meta.*;
 
 /**
@@ -164,4 +165,40 @@
     public int getMaxVectorLength(@SuppressWarnings("unused") Kind kind) {
         return 1;
     }
+
+    /**
+     * Gets the size in bytes of the specified kind for this target.
+     * 
+     * @param kind the kind for which to get the size
+     * 
+     * @return the size in bytes of {@code kind}
+     */
+    public int getSizeInBytes(PlatformKind kind) {
+        switch ((Kind) kind) {
+            case Boolean:
+                return 1;
+            case Byte:
+                return 1;
+            case Char:
+                return 2;
+            case Short:
+                return 2;
+            case Int:
+                return 4;
+            case Long:
+                return 8;
+            case Float:
+                return 4;
+            case Double:
+                return 8;
+            case Object:
+                return wordSize;
+            default:
+                return 0;
+        }
+    }
+
+    public abstract boolean canStoreValue(RegisterCategory category, PlatformKind kind);
+
+    public abstract PlatformKind getLargestStorableKind(RegisterCategory category);
 }
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CalleeSaveLayout.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CalleeSaveLayout.java	Mon May 13 17:11:31 2013 +0200
@@ -24,6 +24,8 @@
 
 import java.util.*;
 
+import com.oracle.graal.api.meta.*;
+
 /**
  * The callee save area (CSA) is a contiguous space in a stack frame used to save (and restore) the
  * values of the caller's registers. This class describes the layout of a CSA in terms of its
@@ -69,7 +71,7 @@
      *            CSA
      * @param registers the registers that can be saved in the CSA
      */
-    public CalleeSaveLayout(int frameOffsetToCSA, int size, int slotSize, Register... registers) {
+    public CalleeSaveLayout(Architecture architecture, int frameOffsetToCSA, int size, int slotSize, Register... registers) {
         this.frameOffsetToCSA = frameOffsetToCSA;
         assert slotSize == 0 || CodeUtil.isPowerOf2(slotSize);
         this.slotSize = slotSize;
@@ -86,7 +88,8 @@
             if (offset > maxOffset) {
                 maxOffset = offset;
             }
-            offset += reg.spillSlotSize;
+            PlatformKind kind = architecture.getLargestStorableKind(reg.getRegisterCategory());
+            offset += architecture.getSizeInBytes(kind);
         }
         if (size == -1) {
             this.size = offset;
@@ -103,7 +106,8 @@
             int index = offset / slotSize;
             regNumToIndex[reg.number] = index;
             indexToReg[index] = reg;
-            offset += reg.spillSlotSize;
+            PlatformKind kind = architecture.getLargestStorableKind(reg.getRegisterCategory());
+            offset += architecture.getSizeInBytes(kind);
         }
     }
 
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CallingConvention.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CallingConvention.java	Mon May 13 17:11:31 2013 +0200
@@ -171,7 +171,7 @@
             sb.append(sep).append(op);
             sep = ", ";
         }
-        if (returnLocation != Value.ILLEGAL) {
+        if (!returnLocation.equals(Value.ILLEGAL)) {
             sb.append(" -> ").append(returnLocation);
         }
         if (temporaryLocations.length != 0) {
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeUtil.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeUtil.java	Mon May 13 17:11:31 2013 +0200
@@ -303,6 +303,14 @@
             }
             sb.append(' ').append(bm).append(nl);
         }
+        RegisterSaveLayout calleeSaveInfo = info.getCalleeSaveInfo();
+        if (calleeSaveInfo != null) {
+            sb.append("callee-save-info:").append(nl);
+            Map<Integer, Register> map = calleeSaveInfo.slotsToRegisters(true);
+            for (Map.Entry<Integer, Register> e : map.entrySet()) {
+                sb.append("    ").append(e.getValue()).append(" -> ").append(formatter.formatStackSlot(e.getKey())).append(nl);
+            }
+        }
         BytecodeFrame frame = info.frame();
         if (frame != null) {
             append(sb, frame);
@@ -318,9 +326,17 @@
     public static CallingConvention getCallingConvention(CodeCacheProvider codeCache, CallingConvention.Type type, ResolvedJavaMethod method, boolean stackOnly) {
         Signature sig = method.getSignature();
         JavaType retType = sig.getReturnType(null);
-        JavaType[] argTypes = new JavaType[sig.getParameterCount(!Modifier.isStatic(method.getModifiers()))];
-        for (int i = 0; i < argTypes.length; i++) {
-            argTypes[i] = sig.getParameterType(i, null);
+        int sigCount = sig.getParameterCount(false);
+        JavaType[] argTypes;
+        int argIndex = 0;
+        if (!Modifier.isStatic(method.getModifiers())) {
+            argTypes = new JavaType[sigCount + 1];
+            argTypes[argIndex++] = method.getDeclaringClass();
+        } else {
+            argTypes = new JavaType[sigCount];
+        }
+        for (int i = 0; i < sigCount; i++) {
+            argTypes[argIndex++] = sig.getParameterType(i, null);
         }
 
         RegisterConfig registerConfig = codeCache.lookupRegisterConfig();
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CompilationResult.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CompilationResult.java	Mon May 13 17:11:31 2013 +0200
@@ -507,6 +507,16 @@
         if (info != null) {
             appendRefMap(sb, "stackMap", info.getFrameRefMap());
             appendRefMap(sb, "registerMap", info.getRegisterRefMap());
+            RegisterSaveLayout calleeSaveInfo = info.getCalleeSaveInfo();
+            if (calleeSaveInfo != null) {
+                sb.append(" callee-save-info[");
+                String sep = "";
+                for (Map.Entry<Register, Integer> e : calleeSaveInfo.registersToSlots(true).entrySet()) {
+                    sb.append(sep).append(e.getKey()).append("->").append(e.getValue());
+                    sep = ", ";
+                }
+                sb.append(']');
+            }
             BytecodePosition codePos = info.getBytecodePosition();
             if (codePos != null) {
                 MetaUtil.appendLocation(sb.append(" "), codePos.getMethod(), codePos.getBCI());
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/DebugInfo.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/DebugInfo.java	Mon May 13 17:11:31 2013 +0200
@@ -26,8 +26,16 @@
 import java.util.*;
 
 /**
- * Represents the debugging information for a particular place in the code, which includes the code
- * position, a reference map, and deoptimization information.
+ * Represents the debugging information for a particular point of execution. This information
+ * includes:
+ * <ul>
+ * <li>a {@linkplain #getBytecodePosition() bytecode position}</li>
+ * <li>a reference map for {@linkplain #getRegisterRefMap() registers}</li>
+ * <li>a reference map for {@linkplain #getRegisterRefMap() stack slots} in the current frame</li>
+ * <li>a map from bytecode locals and operand stack slots to their values or locations from which
+ * their values can be read</li>
+ * <li>a map from the registers (in the caller's frame) to the slots where they are saved in the
+ * current frame</li>
  */
 public class DebugInfo implements Serializable {
 
@@ -37,6 +45,7 @@
     private final BitSet registerRefMap;
     private final BitSet frameRefMap;
     private final short deoptimizationReason;
+    private RegisterSaveLayout calleeSaveInfo;
 
     /**
      * Creates a new {@link DebugInfo} from the given values.
@@ -125,4 +134,20 @@
     public short getDeoptimizationReason() {
         return deoptimizationReason;
     }
+
+    /**
+     * Sets the map from the registers (in the caller's frame) to the slots where they are saved in
+     * the current frame.
+     */
+    public void setCalleeSaveInfo(RegisterSaveLayout calleeSaveInfo) {
+        this.calleeSaveInfo = calleeSaveInfo;
+    }
+
+    /**
+     * Gets the map from the registers (in the caller's frame) to the slots where they are saved in
+     * the current frame. If no such information is available, {@code null} is returned.
+     */
+    public RegisterSaveLayout getCalleeSaveInfo() {
+        return calleeSaveInfo;
+    }
 }
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Register.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Register.java	Mon May 13 17:11:31 2013 +0200
@@ -23,7 +23,6 @@
 package com.oracle.graal.api.code;
 
 import java.io.*;
-import java.util.*;
 
 import com.oracle.graal.api.meta.*;
 
@@ -34,18 +33,20 @@
 
     private static final long serialVersionUID = -7213269157816016300L;
 
+    public static final RegisterCategory SPECIAL = new RegisterCategory("SPECIAL");
+
     /**
      * Invalid register.
      */
-    public static final Register None = new Register(-1, -1, 0, "noreg");
+    public static final Register None = new Register(-1, -1, "noreg", SPECIAL);
 
     /**
      * Frame pointer of the current method. All spill slots and outgoing stack-based arguments are
      * addressed relative to this register.
      */
-    public static final Register Frame = new Register(-2, -2, 0, "framereg", RegisterFlag.CPU);
+    public static final Register Frame = new Register(-2, -2, "framereg", SPECIAL);
 
-    public static final Register CallerFrame = new Register(-3, -3, 0, "callerframereg", RegisterFlag.CPU);
+    public static final Register CallerFrame = new Register(-3, -3, "callerframereg", SPECIAL);
 
     /**
      * The identifier for this register that is unique across all the registers in a
@@ -72,42 +73,40 @@
     }
 
     /**
-     * The size of the stack slot used to spill the value of this register.
-     */
-    public final int spillSlotSize;
-
-    /**
-     * The set of {@link RegisterFlag} values associated with this register.
+     * A platform specific register category that describes which values can be stored in a
+     * register.
      */
-    private final int flags;
-
-    /**
-     * An array of {@link RegisterValue} objects, for this register, with one entry per {@link Kind}
-     * , indexed by {@link Kind#ordinal}.
-     */
-    private final RegisterValue[] values;
+    private final RegisterCategory registerCategory;
 
     /**
-     * Attributes that characterize a register in a useful way.
-     * 
+     * A platform specific register type that describes which values can be stored in a register.
      */
-    public enum RegisterFlag {
-        /**
-         * Denotes an integral (i.e. non floating point) register.
-         */
-        CPU,
+    public static class RegisterCategory {
+
+        private String name;
+
+        public RegisterCategory(String name) {
+            this.name = name;
+        }
 
-        /**
-         * Denotes a register whose lowest order byte can be addressed separately.
-         */
-        Byte,
+        @Override
+        public String toString() {
+            return name;
+        }
 
-        /**
-         * Denotes a floating point register.
-         */
-        FPU;
+        @Override
+        public int hashCode() {
+            return 23 + name.hashCode();
+        }
 
-        public final int mask = 1 << (ordinal() + 1);
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof RegisterCategory) {
+                RegisterCategory other = (RegisterCategory) obj;
+                return name.equals(other.name);
+            }
+            return false;
+        }
     }
 
     /**
@@ -115,33 +114,18 @@
      * 
      * @param number unique identifier for the register
      * @param encoding the target machine encoding for the register
-     * @param spillSlotSize the size of the stack slot used to spill the value of the register
      * @param name the mnemonic name for the register
-     * @param flags the set of {@link RegisterFlag} values for the register
+     * @param registerCategory the register category
      */
-    public Register(int number, int encoding, int spillSlotSize, String name, RegisterFlag... flags) {
+    public Register(int number, int encoding, String name, RegisterCategory registerCategory) {
         this.number = number;
         this.name = name;
-        this.spillSlotSize = spillSlotSize;
-        this.flags = createMask(flags);
+        this.registerCategory = registerCategory;
         this.encoding = encoding;
-
-        values = new RegisterValue[Kind.values().length];
-        for (Kind kind : Kind.values()) {
-            values[kind.ordinal()] = new RegisterValue(kind, this);
-        }
     }
 
-    private static int createMask(RegisterFlag... flags) {
-        int result = 0;
-        for (RegisterFlag f : flags) {
-            result |= f.mask;
-        }
-        return result;
-    }
-
-    public boolean isSet(RegisterFlag f) {
-        return (flags & f.mask) != 0;
+    public RegisterCategory getRegisterCategory() {
+        return registerCategory;
     }
 
     /**
@@ -150,8 +134,8 @@
      * @param kind the specified kind
      * @return the {@link RegisterValue}
      */
-    public RegisterValue asValue(Kind kind) {
-        return values[kind.ordinal()];
+    public RegisterValue asValue(PlatformKind kind) {
+        return new RegisterValue(kind, this);
     }
 
     /**
@@ -173,60 +157,6 @@
     }
 
     /**
-     * Determines if this a floating point register.
-     */
-    public boolean isFpu() {
-        return isSet(RegisterFlag.FPU);
-    }
-
-    /**
-     * Determines if this a general purpose register.
-     */
-    public boolean isCpu() {
-        return isSet(RegisterFlag.CPU);
-    }
-
-    /**
-     * Determines if this register has the {@link RegisterFlag#Byte} attribute set.
-     * 
-     * @return {@code true} iff this register has the {@link RegisterFlag#Byte} attribute set.
-     */
-    public boolean isByte() {
-        return isSet(RegisterFlag.Byte);
-    }
-
-    /**
-     * Gets a hash code for this register.
-     * 
-     * @return the value of {@link #number}
-     */
-    @Override
-    public int hashCode() {
-        return number;
-    }
-
-    /**
-     * Categorizes a set of registers by {@link RegisterFlag}.
-     * 
-     * @param registers a list of registers to be categorized
-     * @return a map from each {@link RegisterFlag} constant to the list of registers for which the
-     *         flag is {@linkplain #isSet(RegisterFlag) set}
-     */
-    public static EnumMap<RegisterFlag, Register[]> categorize(Register[] registers) {
-        EnumMap<RegisterFlag, Register[]> result = new EnumMap<>(RegisterFlag.class);
-        for (RegisterFlag flag : RegisterFlag.values()) {
-            ArrayList<Register> list = new ArrayList<>();
-            for (Register r : registers) {
-                if (r.isSet(flag)) {
-                    list.add(r);
-                }
-            }
-            result.put(flag, list.toArray(new Register[list.size()]));
-        }
-        return result;
-    }
-
-    /**
      * Gets the maximum register {@linkplain #number number} in a given set of registers.
      * 
      * @param registers the set of registers to process
@@ -274,4 +204,23 @@
         return 0;
     }
 
+    @Override
+    public int hashCode() {
+        final int prime = 17;
+        int result = 1;
+        result = prime * result + encoding;
+        result = prime * result + name.hashCode();
+        result = prime * result + number;
+        result = prime * result + registerCategory.hashCode();
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof Register) {
+            Register other = (Register) obj;
+            return encoding == other.encoding && name.equals(other.name) && number == other.number && registerCategory.equals(registerCategory);
+        }
+        return false;
+    }
 }
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterConfig.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterConfig.java	Mon May 13 17:11:31 2013 +0200
@@ -22,10 +22,7 @@
  */
 package com.oracle.graal.api.code;
 
-import java.util.*;
-
-import com.oracle.graal.api.code.CallingConvention.*;
-import com.oracle.graal.api.code.Register.*;
+import com.oracle.graal.api.code.CallingConvention.Type;
 import com.oracle.graal.api.meta.*;
 
 /**
@@ -60,12 +57,11 @@
      * given calling convention.
      * 
      * @param type the type of calling convention
-     * @param flag specifies whether registers for {@linkplain RegisterFlag#CPU integral} or
-     *            {@linkplain RegisterFlag#FPU floating point} parameters are being requested
+     * @param kind specifies what kind of registers is being requested
      * @return the ordered set of registers that may be used to pass parameters in a call conforming
      *         to {@code type}
      */
-    Register[] getCallingConventionRegisters(Type type, RegisterFlag flag);
+    Register[] getCallingConventionRegisters(Type type, Kind kind);
 
     /**
      * Gets the set of registers that can be used by the register allocator.
@@ -73,16 +69,10 @@
     Register[] getAllocatableRegisters();
 
     /**
-     * Gets the set of registers that can be used by the register allocator,
-     * {@linkplain Register#categorize(Register[]) categorized} by register
-     * {@linkplain RegisterFlag flags}.
-     * 
-     * @return a map from each {@link RegisterFlag} constant to the list of
-     *         {@linkplain #getAllocatableRegisters() allocatable} registers for which the flag is
-     *         set
-     * 
+     * Gets the set of registers that can be used by the register allocator for a value of a
+     * particular kind.
      */
-    EnumMap<RegisterFlag, Register[]> getCategorizedAllocatableRegisters();
+    Register[] getAllocatableRegisters(PlatformKind kind);
 
     /**
      * Gets the registers whose values must be preserved by a method across any call it makes.
@@ -102,7 +92,6 @@
      * 
      * @return an array where an element at index i holds the attributes of the register whose
      *         number is i
-     * @see Register#categorize(Register[])
      */
     RegisterAttributes[] getAttributesMap();
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterSaveLayout.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,93 @@
+/*
+ * 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.code;
+
+import java.util.*;
+
+/**
+ * A map from registers to frame slots. This can be used to describe where callee saved registers
+ * are saved in a callee's frame.
+ */
+public class RegisterSaveLayout {
+
+    /**
+     * Keys.
+     */
+    private Register[] registers;
+
+    /**
+     * Slot indexes relative to stack pointer.
+     */
+    private int[] slots;
+
+    /**
+     * Creates a map from registers to frame slots.
+     * 
+     * @param registers the keys in the map
+     * @param slots frame slot index for each register in {@code registers}
+     */
+    public RegisterSaveLayout(Register[] registers, int[] slots) {
+        assert registers.length == slots.length;
+        this.registers = registers;
+        this.slots = slots;
+        assert registersToSlots(false).size() == registers.length : "non-unique registers";
+        assert new HashSet<>(registersToSlots(false).values()).size() == slots.length : "non-unqiue slots";
+    }
+
+    /**
+     * Gets this layout information as a {@link Map} from registers to slots.
+     */
+    public Map<Register, Integer> registersToSlots(boolean sorted) {
+        Map<Register, Integer> result;
+        if (sorted) {
+            result = new TreeMap<>();
+        } else {
+            result = new HashMap<>();
+        }
+        for (int i = 0; i < registers.length; i++) {
+            result.put(registers[i], slots[i]);
+        }
+        return result;
+    }
+
+    /**
+     * Gets this layout information as a {@link Map} from slots to registers.
+     */
+    public Map<Integer, Register> slotsToRegisters(boolean sorted) {
+        Map<Integer, Register> result;
+        if (sorted) {
+            result = new TreeMap<>();
+        } else {
+            result = new HashMap<>();
+        }
+        for (int i = 0; i < registers.length; i++) {
+            result.put(slots[i], registers[i]);
+        }
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return registersToSlots(true).toString();
+    }
+}
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterValue.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterValue.java	Mon May 13 17:11:31 2013 +0200
@@ -27,8 +27,8 @@
 /**
  * Denotes a register that stores a value of a fixed kind. There is exactly one (canonical) instance
  * of {@link RegisterValue} for each ({@link Register}, {@link Kind}) pair. Use
- * {@link Register#asValue(Kind)} to retrieve the canonical {@link RegisterValue} instance for a
- * given (register,kind) pair.
+ * {@link Register#asValue(PlatformKind)} to retrieve the canonical {@link RegisterValue} instance
+ * for a given (register,kind) pair.
  */
 public final class RegisterValue extends AllocatableValue {
 
@@ -39,17 +39,12 @@
     /**
      * Should only be called from {@link Register#Register} to ensure canonicalization.
      */
-    protected RegisterValue(Kind kind, Register register) {
+    protected RegisterValue(PlatformKind kind, Register register) {
         super(kind);
         this.reg = register;
     }
 
     @Override
-    public int hashCode() {
-        return (getRegister().number << 4) ^ getKind().ordinal();
-    }
-
-    @Override
     public String toString() {
         return getRegister().name + getKindSuffix();
     }
@@ -60,4 +55,18 @@
     public Register getRegister() {
         return reg;
     }
+
+    @Override
+    public int hashCode() {
+        return 29 * super.hashCode() + reg.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof RegisterValue) {
+            RegisterValue other = (RegisterValue) obj;
+            return super.equals(obj) && reg.equals(other.reg);
+        }
+        return false;
+    }
 }
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RuntimeCallTarget.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RuntimeCallTarget.java	Mon May 13 17:11:31 2013 +0200
@@ -67,14 +67,14 @@
         /**
          * Gets the return kind of this runtime call.
          */
-        public Class getResultType() {
+        public Class<?> getResultType() {
             return resultType;
         }
 
         /**
          * Gets the argument kinds of this runtime call.
          */
-        public Class[] getArgumentTypes() {
+        public Class<?>[] getArgumentTypes() {
             return argumentTypes.clone();
         }
 
@@ -115,5 +115,11 @@
 
     Descriptor getDescriptor();
 
-    boolean preservesRegisters();
+    /**
+     * Determines if the target routine destroys all registers.
+     * 
+     * @return {@code true} if the register allocator must save all live registers around a call to
+     *         this target
+     */
+    boolean destroysRegisters();
 }
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/StackSlot.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/StackSlot.java	Mon May 13 17:11:31 2013 +0200
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.api.code;
 
-import static com.oracle.graal.api.meta.Kind.*;
-
 import com.oracle.graal.api.meta.*;
 
 /**
@@ -46,36 +44,16 @@
      * @param addFrameSize Specifies if the offset is relative to the stack pointer, or the
      *            beginning of the frame (stack pointer + total frame size).
      */
-    public static StackSlot get(Kind kind, int offset, boolean addFrameSize) {
-        assert kind.getStackKind() == kind;
+    public static StackSlot get(PlatformKind kind, int offset, boolean addFrameSize) {
         assert addFrameSize || offset >= 0;
-
-        if (offset % CACHE_GRANULARITY == 0) {
-            StackSlot[][] cache;
-            int index = offset / CACHE_GRANULARITY;
-            if (!addFrameSize) {
-                cache = OUT_CACHE;
-            } else if (offset >= 0) {
-                cache = IN_CACHE;
-            } else {
-                cache = SPILL_CACHE;
-                index = -index;
-            }
-            StackSlot[] slots = cache[kind.ordinal()];
-            if (index < slots.length) {
-                StackSlot slot = slots[index];
-                assert slot.getKind() == kind && slot.offset == offset && slot.addFrameSize == addFrameSize;
-                return slot;
-            }
-        }
         return new StackSlot(kind, offset, addFrameSize);
     }
 
     /**
-     * Private constructor to enforce use of {@link #get(Kind, int, boolean)} so that a cache can be
-     * used.
+     * Private constructor to enforce use of {@link #get(PlatformKind, int, boolean)} so that a
+     * cache can be used.
      */
-    private StackSlot(Kind kind, int offset, boolean addFrameSize) {
+    private StackSlot(PlatformKind kind, int offset, boolean addFrameSize) {
         super(kind);
         this.offset = offset;
         this.addFrameSize = addFrameSize;
@@ -106,23 +84,6 @@
     }
 
     @Override
-    public int hashCode() {
-        return getKind().ordinal() ^ (offset << 4) ^ (addFrameSize ? 15 : 0);
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (o == this) {
-            return true;
-        }
-        if (o instanceof StackSlot) {
-            StackSlot l = (StackSlot) o;
-            return l.getKind() == getKind() && l.offset == offset && l.addFrameSize == addFrameSize;
-        }
-        return false;
-    }
-
-    @Override
     public String toString() {
         if (!addFrameSize) {
             return "out:" + offset + getKindSuffix();
@@ -139,7 +100,7 @@
     public StackSlot asOutArg() {
         assert offset >= 0;
         if (addFrameSize) {
-            return get(getKind(), offset, false);
+            return get(getPlatformKind(), offset, false);
         }
         return this;
     }
@@ -150,28 +111,26 @@
     public StackSlot asInArg() {
         assert offset >= 0;
         if (!addFrameSize) {
-            return get(getKind(), offset, true);
+            return get(getPlatformKind(), offset, true);
         }
         return this;
     }
 
-    private static final int CACHE_GRANULARITY = 8;
-    private static final int SPILL_CACHE_PER_KIND_SIZE = 100;
-    private static final int PARAM_CACHE_PER_KIND_SIZE = 10;
-
-    private static final StackSlot[][] SPILL_CACHE = makeCache(SPILL_CACHE_PER_KIND_SIZE, -1, true);
-    private static final StackSlot[][] IN_CACHE = makeCache(PARAM_CACHE_PER_KIND_SIZE, 1, true);
-    private static final StackSlot[][] OUT_CACHE = makeCache(PARAM_CACHE_PER_KIND_SIZE, 1, false);
+    @Override
+    public int hashCode() {
+        final int prime = 37;
+        int result = super.hashCode();
+        result = prime * result + (addFrameSize ? 1231 : 1237);
+        result = prime * result + offset;
+        return result;
+    }
 
-    private static StackSlot[][] makeCache(int cachePerKindSize, int sign, boolean addFrameSize) {
-        StackSlot[][] cache = new StackSlot[Kind.values().length][];
-        for (Kind kind : new Kind[]{Illegal, Int, Long, Float, Double, Object}) {
-            StackSlot[] slots = new StackSlot[cachePerKindSize];
-            for (int i = 0; i < cachePerKindSize; i++) {
-                slots[i] = new StackSlot(kind, sign * i * CACHE_GRANULARITY, addFrameSize);
-            }
-            cache[kind.ordinal()] = slots;
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof StackSlot) {
+            StackSlot other = (StackSlot) obj;
+            return super.equals(obj) && addFrameSize == other.addFrameSize && offset == other.offset;
         }
-        return cache;
+        return false;
     }
 }
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/TargetDescription.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/TargetDescription.java	Mon May 13 17:11:31 2013 +0200
@@ -83,39 +83,6 @@
     }
 
     /**
-     * Gets the size in bytes of the specified kind for this target.
-     * 
-     * @param kind the kind for which to get the size
-     * @return the size in bytes of {@code kind}
-     */
-    public int sizeInBytes(Kind kind) {
-        // Checkstyle: stop
-        switch (kind) {
-            case Boolean:
-                return 1;
-            case Byte:
-                return 1;
-            case Char:
-                return 2;
-            case Short:
-                return 2;
-            case Int:
-                return 4;
-            case Long:
-                return 8;
-            case Float:
-                return 4;
-            case Double:
-                return 8;
-            case Object:
-                return wordSize;
-            default:
-                return 0;
-        }
-        // Checkstyle: resume
-    }
-
-    /**
      * Aligns the given frame size (without return instruction pointer) to the stack alignment size
      * and return the aligned size (without return instruction pointer).
      * 
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ValueUtil.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ValueUtil.java	Mon May 13 17:11:31 2013 +0200
@@ -31,7 +31,7 @@
 
     public static boolean isIllegal(Value value) {
         assert value != null;
-        return value == Value.ILLEGAL;
+        return value.equals(Value.ILLEGAL);
     }
 
     public static boolean isLegal(Value value) {
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/VirtualObject.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/VirtualObject.java	Mon May 13 17:11:31 2013 +0200
@@ -168,7 +168,7 @@
 
     @Override
     public int hashCode() {
-        return getKind().ordinal() + type.hashCode();
+        return getPlatformKind().hashCode() + type.hashCode();
     }
 
     @Override
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/AllocatableValue.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/AllocatableValue.java	Mon May 13 17:11:31 2013 +0200
@@ -32,8 +32,7 @@
 
     public static final AllocatableValue[] NONE = {};
 
-    public AllocatableValue(Kind kind) {
-        super(kind);
+    public AllocatableValue(PlatformKind platformKind) {
+        super(platformKind);
     }
-
 }
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/DeoptimizationReason.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/DeoptimizationReason.java	Mon May 13 17:11:31 2013 +0200
@@ -38,5 +38,6 @@
     Unresolved,
     JavaSubroutineMismatch,
     ArithmeticException,
-    RuntimeConstraint
+    RuntimeConstraint,
+    LoopLimitCheck,
 }
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaTypeProfile.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaTypeProfile.java	Mon May 13 17:11:31 2013 +0200
@@ -23,6 +23,7 @@
 package com.oracle.graal.api.meta;
 
 import java.io.*;
+import java.util.*;
 
 import com.oracle.graal.api.meta.ProfilingInfo.*;
 
@@ -43,6 +44,8 @@
 
         private static final long serialVersionUID = 7838575753661305744L;
 
+        public static final ProfiledType[] EMPTY_ARRAY = new ProfiledType[0];
+
         private final ResolvedJavaType type;
         private final double probability;
 
@@ -78,6 +81,40 @@
             }
             return 0;
         }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            long temp;
+            temp = Double.doubleToLongBits(probability);
+            result = prime * result + (int) (temp ^ (temp >>> 32));
+            result = prime * result + type.hashCode();
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            ProfiledType other = (ProfiledType) obj;
+            if (Double.doubleToLongBits(probability) != Double.doubleToLongBits(other.probability)) {
+                return false;
+            }
+            return type.equals(other.type);
+        }
+
+        @Override
+        public String toString() {
+            return "{" + type.getName() + ", " + probability + "}";
+        }
     }
 
     private final TriState nullSeen;
@@ -100,6 +137,7 @@
     public JavaTypeProfile(TriState nullSeen, double notRecordedProbability, ProfiledType... ptypes) {
         this.nullSeen = nullSeen;
         this.ptypes = ptypes;
+        assert notRecordedProbability != Double.NaN;
         this.notRecordedProbability = notRecordedProbability;
         assert isSorted(ptypes);
     }
@@ -129,4 +167,154 @@
     public ProfiledType[] getTypes() {
         return ptypes;
     }
+
+    /**
+     * Searches for an entry of a given resolved Java type.
+     * 
+     * @param type the type for which an entry should be searched
+     * @return the entry or null if no entry for this type can be found
+     */
+    public ProfiledType findEntry(ResolvedJavaType type) {
+        if (ptypes != null) {
+            for (ProfiledType pt : ptypes) {
+                if (pt.getType() == type) {
+                    return pt;
+                }
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append("JavaTypeProfile[");
+        builder.append(this.nullSeen);
+        builder.append(", ");
+        if (ptypes != null) {
+            for (ProfiledType pt : ptypes) {
+                builder.append(pt.toString());
+                builder.append(", ");
+            }
+        }
+        builder.append(this.notRecordedProbability);
+        builder.append("]");
+        return builder.toString();
+    }
+
+    public JavaTypeProfile restrict(JavaTypeProfile otherProfile) {
+        if (otherProfile.getNotRecordedProbability() > 0.0) {
+            // Not useful for restricting since there is an unknown set of types occuring.
+            return this;
+        }
+
+        if (this.getNotRecordedProbability() > 0.0) {
+            // We are unrestricted, so the other profile is always a better estimate.
+            return otherProfile;
+        }
+
+        ArrayList<ProfiledType> result = new ArrayList<>();
+        for (int i = 0; i < getTypes().length; i++) {
+            ProfiledType ptype = getTypes()[i];
+            ResolvedJavaType type = ptype.getType();
+            if (otherProfile.isIncluded(type)) {
+                result.add(ptype);
+            }
+        }
+
+        TriState newNullSeen = (otherProfile.getNullSeen() == TriState.FALSE) ? TriState.FALSE : this.nullSeen;
+        double newNotRecorded = this.notRecordedProbability;
+        return createAdjustedProfile(result, newNullSeen, newNotRecorded);
+    }
+
+    public boolean isIncluded(ResolvedJavaType type) {
+        if (this.getNotRecordedProbability() > 0.0) {
+            return true;
+        } else {
+            for (int i = 0; i < getTypes().length; i++) {
+                ProfiledType ptype = getTypes()[i];
+                ResolvedJavaType curType = ptype.getType();
+                if (curType == type) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public JavaTypeProfile restrict(ResolvedJavaType declaredType, boolean nonNull) {
+        ArrayList<ProfiledType> result = new ArrayList<>();
+        for (int i = 0; i < getTypes().length; i++) {
+            ProfiledType ptype = getTypes()[i];
+            ResolvedJavaType type = ptype.getType();
+            if (declaredType.isAssignableFrom(type)) {
+                result.add(ptype);
+            }
+        }
+
+        TriState newNullSeen = (nonNull) ? TriState.FALSE : this.nullSeen;
+        double newNotRecorded = this.getNotRecordedProbability();
+        // Assume for the types not recorded, the incompatibility rate is the same.
+        if (getTypes().length != 0) {
+            newNotRecorded *= ((double) result.size() / (double) getTypes().length);
+        }
+        return createAdjustedProfile(result, newNullSeen, newNotRecorded);
+    }
+
+    private JavaTypeProfile createAdjustedProfile(ArrayList<ProfiledType> result, TriState newNullSeen, double newNotRecorded) {
+        if (result.size() != this.getTypes().length || newNotRecorded != getNotRecordedProbability() || newNullSeen != this.nullSeen) {
+            if (result.size() == 0) {
+                return new JavaTypeProfile(newNullSeen, 1.0, ProfiledType.EMPTY_ARRAY);
+            }
+            double probabilitySum = 0.0;
+            for (int i = 0; i < result.size(); i++) {
+                probabilitySum += result.get(i).getProbability();
+            }
+            probabilitySum += newNotRecorded;
+
+            double factor = 1.0 / probabilitySum; // Normalize to 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);
+                newResult[i] = new ProfiledType(curType.getType(), Math.min(1.0, curType.getProbability() * factor));
+            }
+            double newNotRecordedTypeProbability = Math.min(1.0, newNotRecorded * factor);
+            return new JavaTypeProfile(newNullSeen, newNotRecordedTypeProbability, newResult);
+        }
+        return this;
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (other == this) {
+            return true;
+        }
+        if (other instanceof JavaTypeProfile) {
+            JavaTypeProfile javaTypeProfile = (JavaTypeProfile) other;
+            if (javaTypeProfile.nullSeen != nullSeen) {
+                return false;
+            }
+            if (javaTypeProfile.notRecordedProbability != notRecordedProbability) {
+                return false;
+            }
+            if (javaTypeProfile.ptypes.length != ptypes.length) {
+                return false;
+            }
+
+            for (int i = 0; i < ptypes.length; ++i) {
+                if (!ptypes[i].equals(javaTypeProfile.ptypes[i])) {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return nullSeen.hashCode() + (int) Double.doubleToLongBits(notRecordedProbability) + ptypes.length * 13;
+    }
 }
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Kind.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Kind.java	Mon May 13 17:11:31 2013 +0200
@@ -29,7 +29,7 @@
  * {@link Kind#Int} for {@code int} and {@link Kind#Object} for all object types. A kind has a
  * single character short name, a Java name, and a set of flags further describing its behavior.
  */
-public enum Kind {
+public enum Kind implements PlatformKind {
     /** The primitive boolean kind, represented as an int on the stack. */
     Boolean('z', "boolean", true, java.lang.Boolean.TYPE, java.lang.Boolean.class),
 
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaUtil.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaUtil.java	Mon May 13 17:11:31 2013 +0200
@@ -162,6 +162,13 @@
         return (type == null) ? null : internalNameToJava(type.getName(), true, false);
     }
 
+    /**
+     * Returns the type name in the same format as {@link Class#getName()}.
+     */
+    public static String toClassName(JavaType type) {
+        return internalNameToJava(type.getName(), true, true);
+    }
+
     private static String internalNameToJava(String name, boolean qualified, boolean classForNameCompatible) {
         switch (name.charAt(0)) {
             case 'L': {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/PlatformKind.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,31 @@
+/*
+ * 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;
+
+/**
+ * Represents a platform-specific low-level type for values.
+ */
+public interface PlatformKind {
+
+    String name();
+}
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java	Mon May 13 17:11:31 2013 +0200
@@ -24,7 +24,6 @@
 
 import java.lang.annotation.*;
 import java.lang.reflect.*;
-import java.lang.reflect.Method;
 import java.util.*;
 
 /**
@@ -195,4 +194,18 @@
      * @return The newly created and initialized object.
      */
     Constant newInstance(Constant[] arguments);
+
+    /**
+     * Gets the encoding of (that is, a constant representing the value of) this method.
+     * 
+     * @return a constant representing a reference to this method
+     */
+    Constant getEncoding();
+
+    /**
+     * Checks if this method is present in the virtual table.
+     * 
+     * @return true is this method is present in the virtual table
+     */
+    boolean isInVirtualMethodTable();
 }
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Value.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Value.java	Mon May 13 17:11:31 2013 +0200
@@ -41,14 +41,20 @@
     };
 
     private final Kind kind;
+    private final PlatformKind platformKind;
 
     /**
      * Initializes a new value of the specified kind.
      * 
-     * @param kind the kind
+     * @param platformKind the kind
      */
-    protected Value(Kind kind) {
-        this.kind = kind;
+    protected Value(PlatformKind platformKind) {
+        this.platformKind = platformKind;
+        if (platformKind instanceof Kind) {
+            this.kind = (Kind) platformKind;
+        } else {
+            this.kind = Kind.Illegal;
+        }
     }
 
     /**
@@ -65,4 +71,29 @@
     public final Kind getKind() {
         return kind;
     }
+
+    /**
+     * Returns the platform specific kind used to store this value.
+     */
+    public final PlatformKind getPlatformKind() {
+        return platformKind;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 41;
+        int result = 1;
+        result = prime * result + kind.hashCode();
+        result = prime * result + platformKind.hashCode();
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof Value) {
+            Value other = (Value) obj;
+            return kind.equals(other.kind) && platformKind.equals(platformKind);
+        }
+        return false;
+    }
 }
--- a/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java	Mon May 13 17:11:31 2013 +0200
@@ -380,7 +380,7 @@
     }
 
     public final void addsd(Register dst, Register src) {
-        assert dst.isFpu() && src.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM && src.getRegisterCategory() == AMD64.XMM;
         emitByte(0xF2);
         int encode = prefixAndEncode(dst.encoding, src.encoding);
         emitByte(0x0F);
@@ -389,7 +389,7 @@
     }
 
     public final void addsd(Register dst, AMD64Address src) {
-        assert dst.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM;
         emitByte(0xF2);
         prefix(src, dst);
         emitByte(0x0F);
@@ -398,7 +398,7 @@
     }
 
     public final void addss(Register dst, Register src) {
-        assert dst.isFpu() && src.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM && src.getRegisterCategory() == AMD64.XMM;
         emitByte(0xF3);
         int encode = prefixAndEncode(dst.encoding, src.encoding);
         emitByte(0x0F);
@@ -407,7 +407,7 @@
     }
 
     public final void addss(Register dst, AMD64Address src) {
-        assert dst.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM;
         emitByte(0xF3);
         prefix(src, dst);
         emitByte(0x0F);
@@ -513,6 +513,13 @@
         emitOperandHelper(dst, src);
     }
 
+    public final void cmpl(AMD64Address dst, int imm32) {
+        prefix(dst);
+        emitByte(0x81);
+        emitOperandHelper(7, dst);
+        emitInt(imm32);
+    }
+
     // The 32-bit cmpxchg compares the value at adr with the contents of X86.rax,
     // and stores reg into adr if so; otherwise, the value at adr is loaded into X86.rax,.
     // The ZF is set if the compared values were equal, and cleared otherwise.
@@ -540,7 +547,7 @@
     }
 
     public final void cvtsd2ss(Register dst, AMD64Address src) {
-        assert dst.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM;
         emitByte(0xF2);
         prefix(src, dst);
         emitByte(0x0F);
@@ -549,8 +556,8 @@
     }
 
     public final void cvtsd2ss(Register dst, Register src) {
-        assert dst.isFpu();
-        assert src.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM;
+        assert src.getRegisterCategory() == AMD64.XMM;
         emitByte(0xF2);
         int encode = prefixAndEncode(dst.encoding, src.encoding);
         emitByte(0x0F);
@@ -559,7 +566,7 @@
     }
 
     public final void cvtsi2sdl(Register dst, AMD64Address src) {
-        assert dst.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM;
         emitByte(0xF2);
         prefix(src, dst);
         emitByte(0x0F);
@@ -568,7 +575,7 @@
     }
 
     public final void cvtsi2sdl(Register dst, Register src) {
-        assert dst.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM;
         emitByte(0xF2);
         int encode = prefixAndEncode(dst.encoding, src.encoding);
         emitByte(0x0F);
@@ -577,7 +584,7 @@
     }
 
     public final void cvtsi2ssl(Register dst, AMD64Address src) {
-        assert dst.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM;
         emitByte(0xF3);
         prefix(src, dst);
         emitByte(0x0F);
@@ -586,7 +593,7 @@
     }
 
     public final void cvtsi2ssl(Register dst, Register src) {
-        assert dst.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM;
         emitByte(0xF3);
         int encode = prefixAndEncode(dst.encoding, src.encoding);
         emitByte(0x0F);
@@ -595,7 +602,7 @@
     }
 
     public final void cvtss2sd(Register dst, AMD64Address src) {
-        assert dst.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM;
         emitByte(0xF3);
         prefix(src, dst);
         emitByte(0x0F);
@@ -604,8 +611,8 @@
     }
 
     public final void cvtss2sd(Register dst, Register src) {
-        assert dst.isFpu();
-        assert src.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM;
+        assert src.getRegisterCategory() == AMD64.XMM;
         emitByte(0xF3);
         int encode = prefixAndEncode(dst.encoding, src.encoding);
         emitByte(0x0F);
@@ -622,7 +629,7 @@
     }
 
     public final void cvttsd2sil(Register dst, Register src) {
-        assert src.isFpu();
+        assert src.getRegisterCategory() == AMD64.XMM;
         emitByte(0xF2);
         int encode = prefixAndEncode(dst.encoding, src.encoding);
         emitByte(0x0F);
@@ -639,7 +646,7 @@
     }
 
     public final void cvttss2sil(Register dst, Register src) {
-        assert src.isFpu();
+        assert src.getRegisterCategory() == AMD64.XMM;
         emitByte(0xF3);
         int encode = prefixAndEncode(dst.encoding, src.encoding);
         emitByte(0x0F);
@@ -654,7 +661,7 @@
     }
 
     public final void divsd(Register dst, AMD64Address src) {
-        assert dst.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM;
         emitByte(0xF2);
         prefix(src, dst);
         emitByte(0x0F);
@@ -663,8 +670,8 @@
     }
 
     public final void divsd(Register dst, Register src) {
-        assert dst.isFpu();
-        assert src.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM;
+        assert src.getRegisterCategory() == AMD64.XMM;
         emitByte(0xF2);
         int encode = prefixAndEncode(dst.encoding, src.encoding);
         emitByte(0x0F);
@@ -673,7 +680,7 @@
     }
 
     public final void divss(Register dst, AMD64Address src) {
-        assert dst.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM;
         emitByte(0xF3);
         prefix(src, dst);
         emitByte(0x0F);
@@ -682,8 +689,8 @@
     }
 
     public final void divss(Register dst, Register src) {
-        assert dst.isFpu();
-        assert src.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM;
+        assert src.getRegisterCategory() == AMD64.XMM;
         emitByte(0xF3);
         int encode = prefixAndEncode(dst.encoding, src.encoding);
         emitByte(0x0F);
@@ -862,8 +869,8 @@
     }
 
     public final void movapd(Register dst, Register src) {
-        assert dst.isFpu();
-        assert src.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM;
+        assert src.getRegisterCategory() == AMD64.XMM;
         int dstenc = dst.encoding;
         int srcenc = src.encoding;
         emitByte(0x66);
@@ -887,8 +894,8 @@
     }
 
     public final void movaps(Register dst, Register src) {
-        assert dst.isFpu();
-        assert src.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM;
+        assert src.getRegisterCategory() == AMD64.XMM;
         int dstenc = dst.encoding;
         int srcenc = src.encoding;
         if (dstenc < 8) {
@@ -918,22 +925,22 @@
     }
 
     public final void movb(AMD64Address dst, Register src) {
-        assert src.isByte() : "must have byte register";
+        assert src.getRegisterCategory() == AMD64.CPU : "must have byte register";
         prefix(dst, src); // , true)
         emitByte(0x88);
         emitOperandHelper(src, dst);
     }
 
     public final void movdl(Register dst, Register src) {
-        if (dst.isFpu()) {
-            assert !src.isFpu() : "does this hold?";
+        if (dst.getRegisterCategory() == AMD64.XMM) {
+            assert src.getRegisterCategory() != AMD64.XMM : "does this hold?";
             emitByte(0x66);
             int encode = prefixAndEncode(dst.encoding, src.encoding);
             emitByte(0x0F);
             emitByte(0x6E);
             emitByte(0xC0 | encode);
-        } else if (src.isFpu()) {
-            assert !dst.isFpu();
+        } else if (src.getRegisterCategory() == AMD64.XMM) {
+            assert dst.getRegisterCategory() != AMD64.XMM;
             emitByte(0x66);
             // swap src/dst to get correct prefix
             int encode = prefixAndEncode(src.encoding, dst.encoding);
@@ -981,7 +988,7 @@
      * {@link AMD64MacroAssembler#movflt(Register, Register)}.
      */
     public final void movlpd(Register dst, AMD64Address src) {
-        assert dst.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM;
         emitByte(0x66);
         prefix(src, dst);
         emitByte(0x0F);
@@ -990,7 +997,7 @@
     }
 
     public final void movq(Register dst, AMD64Address src) {
-        if (dst.isFpu()) {
+        if (dst.getRegisterCategory() == AMD64.XMM) {
             emitByte(0xF3);
             prefixq(src, dst);
             emitByte(0x0F);
@@ -1010,7 +1017,7 @@
     }
 
     public final void movq(AMD64Address dst, Register src) {
-        if (src.isFpu()) {
+        if (src.getRegisterCategory() == AMD64.XMM) {
             emitByte(0x66);
             prefixq(dst, src);
             emitByte(0x0F);
@@ -1038,8 +1045,8 @@
     }
 
     public final void movsd(Register dst, Register src) {
-        assert dst.isFpu();
-        assert src.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM;
+        assert src.getRegisterCategory() == AMD64.XMM;
         emitByte(0xF2);
         int encode = prefixAndEncode(dst.encoding, src.encoding);
         emitByte(0x0F);
@@ -1048,7 +1055,7 @@
     }
 
     public final void movsd(Register dst, AMD64Address src) {
-        assert dst.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM;
         emitByte(0xF2);
         prefix(src, dst);
         emitByte(0x0F);
@@ -1057,7 +1064,7 @@
     }
 
     public final void movsd(AMD64Address dst, Register src) {
-        assert src.isFpu();
+        assert src.getRegisterCategory() == AMD64.XMM;
         emitByte(0xF2);
         prefix(dst, src);
         emitByte(0x0F);
@@ -1066,8 +1073,8 @@
     }
 
     public final void movss(Register dst, Register src) {
-        assert dst.isFpu();
-        assert src.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM;
+        assert src.getRegisterCategory() == AMD64.XMM;
         emitByte(0xF3);
         int encode = prefixAndEncode(dst.encoding, src.encoding);
         emitByte(0x0F);
@@ -1076,7 +1083,7 @@
     }
 
     public final void movss(Register dst, AMD64Address src) {
-        assert dst.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM;
         emitByte(0xF3);
         prefix(src, dst);
         emitByte(0x0F);
@@ -1085,7 +1092,7 @@
     }
 
     public final void movss(AMD64Address dst, Register src) {
-        assert src.isFpu();
+        assert src.getRegisterCategory() == AMD64.XMM;
         emitByte(0xF3);
         prefix(dst, src);
         emitByte(0x0F);
@@ -1137,7 +1144,7 @@
     }
 
     public final void mulsd(Register dst, AMD64Address src) {
-        assert dst.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM;
         emitByte(0xF2);
         prefix(src, dst);
         emitByte(0x0F);
@@ -1146,8 +1153,8 @@
     }
 
     public final void mulsd(Register dst, Register src) {
-        assert dst.isFpu();
-        assert src.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM;
+        assert src.getRegisterCategory() == AMD64.XMM;
 
         emitByte(0xF2);
         int encode = prefixAndEncode(dst.encoding, src.encoding);
@@ -1157,7 +1164,7 @@
     }
 
     public final void mulss(Register dst, AMD64Address src) {
-        assert dst.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM;
 
         emitByte(0xF3);
         prefix(src, dst);
@@ -1167,8 +1174,8 @@
     }
 
     public final void mulss(Register dst, Register src) {
-        assert dst.isFpu();
-        assert src.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM;
+        assert src.getRegisterCategory() == AMD64.XMM;
         emitByte(0xF3);
         int encode = prefixAndEncode(dst.encoding, src.encoding);
         emitByte(0x0F);
@@ -1512,8 +1519,8 @@
     }
 
     public final void sqrtsd(Register dst, Register src) {
-        assert dst.isFpu();
-        assert src.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM;
+        assert src.getRegisterCategory() == AMD64.XMM;
         // HMM Table D-1 says sse2
         // assert is64 || target.supportsSSE();
         emitByte(0xF2);
@@ -1545,8 +1552,8 @@
     }
 
     public final void subsd(Register dst, Register src) {
-        assert dst.isFpu();
-        assert src.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM;
+        assert src.getRegisterCategory() == AMD64.XMM;
         emitByte(0xF2);
         int encode = prefixAndEncode(dst.encoding, src.encoding);
         emitByte(0x0F);
@@ -1555,7 +1562,7 @@
     }
 
     public final void subsd(Register dst, AMD64Address src) {
-        assert dst.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM;
 
         emitByte(0xF2);
         prefix(src, dst);
@@ -1565,8 +1572,8 @@
     }
 
     public final void subss(Register dst, Register src) {
-        assert dst.isFpu();
-        assert src.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM;
+        assert src.getRegisterCategory() == AMD64.XMM;
         emitByte(0xF3);
         int encode = prefixAndEncode(dst.encoding, src.encoding);
         emitByte(0x0F);
@@ -1575,7 +1582,7 @@
     }
 
     public final void subss(Register dst, AMD64Address src) {
-        assert dst.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM;
 
         emitByte(0xF3);
         prefix(src, dst);
@@ -1611,20 +1618,20 @@
     }
 
     public final void ucomisd(Register dst, AMD64Address src) {
-        assert dst.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM;
         emitByte(0x66);
         ucomiss(dst, src);
     }
 
     public final void ucomisd(Register dst, Register src) {
-        assert dst.isFpu();
-        assert src.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM;
+        assert src.getRegisterCategory() == AMD64.XMM;
         emitByte(0x66);
         ucomiss(dst, src);
     }
 
     public final void ucomiss(Register dst, AMD64Address src) {
-        assert dst.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM;
 
         prefix(src, dst);
         emitByte(0x0F);
@@ -1633,8 +1640,8 @@
     }
 
     public final void ucomiss(Register dst, Register src) {
-        assert dst.isFpu();
-        assert src.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM;
+        assert src.getRegisterCategory() == AMD64.XMM;
         int encode = prefixAndEncode(dst.encoding, src.encoding);
         emitByte(0x0F);
         emitByte(0x2E);
@@ -1668,7 +1675,7 @@
     }
 
     public final void andps(Register dst, Register src) {
-        assert dst.isFpu() && src.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM && src.getRegisterCategory() == AMD64.XMM;
         int encode = prefixAndEncode(dst.encoding, src.encoding);
         emitByte(0x0F);
         emitByte(0x54);
@@ -1676,7 +1683,7 @@
     }
 
     public final void andps(Register dst, AMD64Address src) {
-        assert dst.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM;
         prefix(src, dst);
         emitByte(0x0F);
         emitByte(0x54);
@@ -1694,7 +1701,7 @@
     }
 
     public final void orps(Register dst, Register src) {
-        assert dst.isFpu() && src.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM && src.getRegisterCategory() == AMD64.XMM;
         int encode = prefixAndEncode(dst.encoding, src.encoding);
         emitByte(0x0F);
         emitByte(0x56);
@@ -1702,7 +1709,7 @@
     }
 
     public final void orps(Register dst, AMD64Address src) {
-        assert dst.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM;
         prefix(src, dst);
         emitByte(0x0F);
         emitByte(0x56);
@@ -1720,7 +1727,7 @@
     }
 
     public final void xorps(Register dst, Register src) {
-        assert dst.isFpu() && src.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM && src.getRegisterCategory() == AMD64.XMM;
         int encode = prefixAndEncode(dst.encoding, src.encoding);
         emitByte(0x0F);
         emitByte(0x57);
@@ -1728,7 +1735,7 @@
     }
 
     public final void xorps(Register dst, AMD64Address src) {
-        assert dst.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM;
         prefix(src, dst);
         emitByte(0x0F);
         emitByte(0x57);
@@ -2014,7 +2021,7 @@
     }
 
     public final void cvtsi2sdq(Register dst, AMD64Address src) {
-        assert dst.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM;
         emitByte(0xF2);
         prefixq(src, dst);
         emitByte(0x0F);
@@ -2023,7 +2030,7 @@
     }
 
     public final void cvtsi2sdq(Register dst, Register src) {
-        assert dst.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM;
         emitByte(0xF2);
         int encode = prefixqAndEncode(dst.encoding, src.encoding);
         emitByte(0x0F);
@@ -2032,7 +2039,7 @@
     }
 
     public final void cvtsi2ssq(Register dst, AMD64Address src) {
-        assert dst.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM;
         emitByte(0xF3);
         prefixq(src, dst);
         emitByte(0x0F);
@@ -2041,7 +2048,7 @@
     }
 
     public final void cvtsi2ssq(Register dst, Register src) {
-        assert dst.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM;
         emitByte(0xF3);
         int encode = prefixqAndEncode(dst.encoding, src.encoding);
         emitByte(0x0F);
@@ -2058,7 +2065,7 @@
     }
 
     public final void cvttsd2siq(Register dst, Register src) {
-        assert src.isFpu();
+        assert src.getRegisterCategory() == AMD64.XMM;
         emitByte(0xF2);
         int encode = prefixqAndEncode(dst.encoding, src.encoding);
         emitByte(0x0F);
@@ -2075,7 +2082,7 @@
     }
 
     public final void cvttss2siq(Register dst, Register src) {
-        assert src.isFpu();
+        assert src.getRegisterCategory() == AMD64.XMM;
         emitByte(0xF3);
         int encode = prefixqAndEncode(dst.encoding, src.encoding);
         emitByte(0x0F);
@@ -2127,7 +2134,7 @@
         if (isByte(value)) {
             emitByte(0x6B);
             emitByte(0xC0 | encode);
-            emitByte(value);
+            emitByte(value & 0xFF);
         } else {
             emitByte(0x69);
             emitByte(0xC0 | encode);
@@ -2154,13 +2161,12 @@
         // table D-1 says MMX/SSE2
         emitByte(0x66);
 
-        if (dst.isFpu()) {
-            assert dst.isFpu();
+        if (dst.getRegisterCategory() == AMD64.XMM) {
             int encode = prefixqAndEncode(dst.encoding, src.encoding);
             emitByte(0x0F);
             emitByte(0x6E);
             emitByte(0xC0 | encode);
-        } else if (src.isFpu()) {
+        } else if (src.getRegisterCategory() == AMD64.XMM) {
 
             // swap src/dst to get correct prefix
             int encode = prefixqAndEncode(src.encoding, dst.encoding);
@@ -2414,11 +2420,16 @@
         emitByte(b2 + i);
     }
 
-    public final void fld(AMD64Address src) {
+    public final void fld_d(AMD64Address src) {
         emitByte(0xDD);
         emitOperandHelper(0, src);
     }
 
+    public final void fld_s(AMD64Address src) {
+        emitByte(0xD9);
+        emitOperandHelper(0, src);
+    }
+
     public final void fldln2() {
         emitByte(0xD9);
         emitByte(0xED);
@@ -2434,11 +2445,49 @@
         emitByte(0xF1);
     }
 
-    public final void fstp(AMD64Address src) {
+    public final void fstp_s(AMD64Address src) {
+        emitByte(0xD9);
+        emitOperandHelper(3, src);
+    }
+
+    public final void fstp_d(AMD64Address src) {
         emitByte(0xDD);
         emitOperandHelper(3, src);
     }
 
+    private void emitFPUArith(int b1, int b2, int i) {
+        assert 0 <= i && i < 8 : "illegal FPU register: " + i;
+        emitByte(b1);
+        emitByte(b2 + i);
+    }
+
+    public void ffree(int i) {
+        emitFPUArith(0xDD, 0xC0, i);
+    }
+
+    public void fincstp() {
+        emitByte(0xD9);
+        emitByte(0xF7);
+    }
+
+    public void fxch(int i) {
+        emitFPUArith(0xD9, 0xC8, i);
+    }
+
+    public void fnstsw_ax() {
+        emitByte(0xDF);
+        emitByte(0xE0);
+    }
+
+    public void fwait() {
+        emitByte(0x9B);
+    }
+
+    public void fprem() {
+        emitByte(0xD9);
+        emitByte(0xF8);
+    }
+
     public final void fsin() {
         emitByte(0xD9);
         emitByte(0xFE);
--- a/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64MacroAssembler.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64MacroAssembler.java	Mon May 13 17:11:31 2013 +0200
@@ -166,21 +166,12 @@
         }
     }
 
-    public final void signExtendByte(Register reg) {
-        if (reg.isByte()) {
-            movsxb(reg, reg);
-        } else {
-            shll(reg, 24);
-            sarl(reg, 24);
-        }
-    }
-
     public final void signExtendShort(Register reg) {
         movsxw(reg, reg);
     }
 
     public final void movflt(Register dst, Register src) {
-        assert dst.isFpu() && src.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM && src.getRegisterCategory() == AMD64.XMM;
         if (UseXmmRegToRegMoveAll) {
             movaps(dst, src);
         } else {
@@ -189,17 +180,17 @@
     }
 
     public final void movflt(Register dst, AMD64Address src) {
-        assert dst.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM;
         movss(dst, src);
     }
 
     public final void movflt(AMD64Address dst, Register src) {
-        assert src.isFpu();
+        assert src.getRegisterCategory() == AMD64.XMM;
         movss(dst, src);
     }
 
     public final void movdbl(Register dst, Register src) {
-        assert dst.isFpu() && src.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM && src.getRegisterCategory() == AMD64.XMM;
         if (UseXmmRegToRegMoveAll) {
             movapd(dst, src);
         } else {
@@ -208,7 +199,7 @@
     }
 
     public final void movdbl(Register dst, AMD64Address src) {
-        assert dst.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM;
         if (UseXmmLoadAndClearUpper) {
             movsd(dst, src);
         } else {
@@ -227,17 +218,12 @@
     }
 
     public final void flog(Register dest, Register value, boolean base10) {
-        assert dest.isFpu() && value.isFpu();
-
-        AMD64Address tmp = new AMD64Address(AMD64.rsp);
         if (base10) {
             fldlg2();
         } else {
             fldln2();
         }
-        subq(AMD64.rsp, 8);
-        movsd(tmp, value);
-        fld(tmp);
+        AMD64Address tmp = trigPrologue(value);
         fyl2x();
         trigEpilogue(dest, tmp);
     }
@@ -261,18 +247,23 @@
         trigEpilogue(dest, tmp);
     }
 
+    public final void fpop() {
+        ffree(0);
+        fincstp();
+    }
+
     private AMD64Address trigPrologue(Register value) {
-        assert value.isFpu();
+        assert value.getRegisterCategory() == AMD64.XMM;
         AMD64Address tmp = new AMD64Address(AMD64.rsp);
         subq(AMD64.rsp, 8);
         movsd(tmp, value);
-        fld(tmp);
+        fld_d(tmp);
         return tmp;
     }
 
     private void trigEpilogue(Register dest, AMD64Address tmp) {
-        assert dest.isFpu();
-        fstp(tmp);
+        assert dest.getRegisterCategory() == AMD64.XMM;
+        fstp_d(tmp);
         movsd(dest, tmp);
         addq(AMD64.rsp, 8);
     }
--- a/graal/com.oracle.graal.asm.test/src/com/oracle/graal/asm/test/AssemblerTest.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.asm.test/src/com/oracle/graal/asm/test/AssemblerTest.java	Mon May 13 17:11:31 2013 +0200
@@ -59,7 +59,7 @@
         DisassemblerProvider dis = Graal.getRuntime().getCapability(DisassemblerProvider.class);
         if (dis != null) {
             String disasm = dis.disassemble(code);
-            Assert.assertTrue(String.valueOf(code.getMethod()), disasm == null || disasm.length() > 0);
+            Assert.assertTrue(code.toString(), disasm == null || disasm.length() > 0);
         }
         return code;
     }
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Mon May 13 17:11:31 2013 +0200
@@ -31,7 +31,6 @@
 
 import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.*;
 import com.oracle.graal.asm.amd64.AMD64Address.Scale;
@@ -48,6 +47,7 @@
 import com.oracle.graal.lir.amd64.AMD64Arithmetic.BinaryRegStack;
 import com.oracle.graal.lir.amd64.AMD64Arithmetic.BinaryRegStackConst;
 import com.oracle.graal.lir.amd64.AMD64Arithmetic.DivRemOp;
+import com.oracle.graal.lir.amd64.AMD64Arithmetic.FPDivRemOp;
 import com.oracle.graal.lir.amd64.AMD64Arithmetic.Unary1Op;
 import com.oracle.graal.lir.amd64.AMD64Arithmetic.Unary2Op;
 import com.oracle.graal.lir.amd64.AMD64Compare.CompareOp;
@@ -78,25 +78,22 @@
  */
 public abstract class AMD64LIRGenerator extends LIRGenerator {
 
-    public static final Descriptor ARITHMETIC_FREM = new Descriptor("arithmeticFrem", false, float.class, float.class, float.class);
-    public static final Descriptor ARITHMETIC_DREM = new Descriptor("arithmeticDrem", false, double.class, double.class, double.class);
-
     private static final RegisterValue RAX_I = AMD64.rax.asValue(Kind.Int);
     private static final RegisterValue RAX_L = AMD64.rax.asValue(Kind.Long);
     private static final RegisterValue RDX_I = AMD64.rdx.asValue(Kind.Int);
     private static final RegisterValue RDX_L = AMD64.rdx.asValue(Kind.Long);
     private static final RegisterValue RCX_I = AMD64.rcx.asValue(Kind.Int);
 
-    public static class AMD64SpillMoveFactory implements LIR.SpillMoveFactory {
+    private class AMD64SpillMoveFactory implements LIR.SpillMoveFactory {
 
         @Override
         public LIRInstruction createMove(AllocatableValue result, Value input) {
-            return AMD64LIRGenerator.createMove(result, input);
+            return AMD64LIRGenerator.this.createMove(result, input);
         }
     }
 
-    public AMD64LIRGenerator(StructuredGraph graph, CodeCacheProvider runtime, TargetDescription target, FrameMap frameMap, ResolvedJavaMethod method, LIR lir) {
-        super(graph, runtime, target, frameMap, method, lir);
+    public AMD64LIRGenerator(StructuredGraph graph, CodeCacheProvider runtime, TargetDescription target, FrameMap frameMap, CallingConvention cc, LIR lir) {
+        super(graph, runtime, target, frameMap, cc, lir);
         lir.spillMoveFactory = new AMD64SpillMoveFactory();
     }
 
@@ -143,7 +140,7 @@
         return result;
     }
 
-    private static AMD64LIRInstruction createMove(AllocatableValue dst, Value src) {
+    protected AMD64LIRInstruction createMove(AllocatableValue dst, Value src) {
         if (src instanceof AMD64AddressValue) {
             return new LeaOp(dst, (AMD64AddressValue) src);
         } else if (isRegister(src) || isStackSlot(dst)) {
@@ -177,7 +174,7 @@
 
         AllocatableValue indexRegister;
         Scale scaleEnum;
-        if (index != Value.ILLEGAL && scale != 0) {
+        if (!index.equals(Value.ILLEGAL) && scale != 0) {
             scaleEnum = Scale.fromInt(scale);
             if (isConstant(index)) {
                 finalDisp += asConstant(index).asLong() * scale;
@@ -196,7 +193,7 @@
         } else {
             displacementInt = 0;
             AllocatableValue displacementRegister = load(Constant.forLong(finalDisp));
-            if (baseRegister == Value.ILLEGAL) {
+            if (baseRegister.equals(Value.ILLEGAL)) {
                 baseRegister = displacementRegister;
             } else if (indexRegister == Value.ILLEGAL) {
                 indexRegister = displacementRegister;
@@ -525,7 +522,7 @@
     }
 
     private void emitDivRem(AMD64Arithmetic op, Value a, Value b, LIRFrameState state) {
-        AllocatableValue rax = AMD64.rax.asValue(a.getKind());
+        AllocatableValue rax = AMD64.rax.asValue(a.getPlatformKind());
         emitMove(rax, a);
         append(new DivRemOp(op, rax, asAllocatable(b), state));
     }
@@ -554,12 +551,12 @@
                 emitDivRem(LDIV, a, b, state(deopting));
                 return emitMove(RAX_L);
             case Float: {
-                Variable result = newVariable(a.getKind());
+                Variable result = newVariable(a.getPlatformKind());
                 append(new BinaryRegStack(FDIV, result, asAllocatable(a), asAllocatable(b)));
                 return result;
             }
             case Double: {
-                Variable result = newVariable(a.getKind());
+                Variable result = newVariable(a.getPlatformKind());
                 append(new BinaryRegStack(DDIV, result, asAllocatable(a), asAllocatable(b)));
                 return result;
             }
@@ -578,12 +575,14 @@
                 emitDivRem(LREM, a, b, state(deopting));
                 return emitMove(RDX_L);
             case Float: {
-                RuntimeCallTarget stub = runtime.lookupRuntimeCall(ARITHMETIC_FREM);
-                return emitCall(stub, stub.getCallingConvention(), null, a, b);
+                Variable result = newVariable(a.getPlatformKind());
+                append(new FPDivRemOp(FREM, result, load(a), load(b)));
+                return result;
             }
             case Double: {
-                RuntimeCallTarget stub = runtime.lookupRuntimeCall(ARITHMETIC_DREM);
-                return emitCall(stub, stub.getCallingConvention(), null, a, b);
+                Variable result = newVariable(a.getPlatformKind());
+                append(new FPDivRemOp(DREM, result, load(a), load(b)));
+                return result;
             }
             default:
                 throw GraalInternalError.shouldNotReachHere();
@@ -657,7 +656,7 @@
     }
 
     private Variable emitShift(AMD64Arithmetic op, Value a, Value b) {
-        Variable result = newVariable(a.getKind());
+        Variable result = newVariable(a.getPlatformKind());
         AllocatableValue input = asAllocatable(a);
         if (isConstant(b)) {
             append(new BinaryRegConst(op, result, input, asConstant(b)));
@@ -920,8 +919,7 @@
             sig[i] = node.arguments.get(i).stamp().javaType(runtime);
         }
 
-        CallingConvention cc = frameMap.registerConfig.getCallingConvention(CallingConvention.Type.JavaCall, null, sig, target(), false);
-        Value[] parameters = visitInvokeArguments(cc, node.arguments);
+        Value[] parameters = visitInvokeArguments(frameMap.registerConfig.getCallingConvention(CallingConvention.Type.JavaCall, null, sig, target(), false), node.arguments);
         append(new AMD64BreakpointOp(parameters));
     }
 
--- a/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/BasicPTXTest.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/BasicPTXTest.java	Mon May 13 17:11:31 2013 +0200
@@ -24,6 +24,7 @@
 
 import java.lang.reflect.Method;
 
+import org.junit.Ignore;
 import org.junit.Test;
 
 /**
@@ -36,7 +37,12 @@
         compile("testAddConst1I");
     }
 
-    public static int testAddConst1I(int a) {
+    @Ignore
+    public void testAddInvoke() {
+        invoke(compile("testAddConst1I"), new Integer(42));
+    }
+
+    public int testAddConst1I(int a) {
         return a + 1;
     }
 
--- a/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/PTXTestBase.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/PTXTestBase.java	Mon May 13 17:11:31 2013 +0200
@@ -22,35 +22,60 @@
  */
 package com.oracle.graal.compiler.ptx.test;
 
+import static com.oracle.graal.api.code.CodeUtil.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.runtime.*;
-import com.oracle.graal.compiler.*;
-import com.oracle.graal.compiler.ptx.*;
-import com.oracle.graal.compiler.test.*;
-import com.oracle.graal.debug.*;
-import com.oracle.graal.java.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.phases.*;
+import com.oracle.graal.api.code.CallingConvention.*;
+import com.oracle.graal.api.runtime.Graal;
+import com.oracle.graal.compiler.GraalCompiler;
+import com.oracle.graal.compiler.ptx.PTXBackend;
+import com.oracle.graal.compiler.test.GraalCompilerTest;
+import com.oracle.graal.debug.Debug;
+import com.oracle.graal.java.GraphBuilderConfiguration;
+import com.oracle.graal.java.GraphBuilderPhase;
+import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.spi.GraalCodeCacheProvider;
+import com.oracle.graal.phases.OptimisticOptimizations;
+import com.oracle.graal.phases.PhasePlan;
 import com.oracle.graal.phases.PhasePlan.PhasePosition;
-import com.oracle.graal.ptx.*;
+import com.oracle.graal.ptx.PTX;
 
 public abstract class PTXTestBase extends GraalCompilerTest {
 
+    private StructuredGraph sg;
+
     protected CompilationResult compile(String test) {
         StructuredGraph graph = parse(test);
+        sg = graph;
         Debug.dump(graph, "Graph");
         TargetDescription target = new TargetDescription(new PTX(), true, 1, 0, true);
-        PTXBackend ptxBackend = new PTXBackend(Graal.getRequiredCapability(CodeCacheProvider.class), target);
+        PTXBackend ptxBackend = new PTXBackend(Graal.getRequiredCapability(GraalCodeCacheProvider.class), target);
         PhasePlan phasePlan = new PhasePlan();
         GraphBuilderPhase graphBuilderPhase = new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getDefault(), OptimisticOptimizations.NONE);
         phasePlan.addPhase(PhasePosition.AFTER_PARSING, graphBuilderPhase);
         phasePlan.addPhase(PhasePosition.AFTER_PARSING, new PTXPhase());
         new PTXPhase().apply(graph);
-        CompilationResult result = GraalCompiler.compileMethod(runtime, graalRuntime().getReplacements(), ptxBackend, target, graph.method(), graph, null, phasePlan, OptimisticOptimizations.NONE,
+        CallingConvention cc = getCallingConvention(runtime, Type.JavaCallee, graph.method(), false);
+        CompilationResult result = GraalCompiler.compileGraph(graph, cc, graph.method(), runtime, graalRuntime().getReplacements(), ptxBackend, target, null, phasePlan, OptimisticOptimizations.NONE,
                         new SpeculationLog());
         return result;
     }
 
+    protected StructuredGraph getStructuredGraph() {
+        return sg;
+    }
+
+    @SuppressWarnings("unused")
+    protected void invoke(CompilationResult result, Object... args) {
+        try {
+            // not quite yet - need multi-architecture Method changes from JDK-8013168
+            // Object[] executeArgs = argsWithReceiver(this, args);
+            // InstalledCode installedCode =
+            // runtime.addMethod(getStructuredGraph().method(), result);
+            // installedCode.executeVarargs(executeArgs);
+        } catch (Throwable th) {
+            th.printStackTrace();
+        }
+    }
 }
--- a/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXBackend.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXBackend.java	Mon May 13 17:11:31 2013 +0200
@@ -42,17 +42,14 @@
     }
 
     @Override
-    public LIRGenerator newLIRGenerator(StructuredGraph graph, FrameMap frameMap, ResolvedJavaMethod method, LIR lir) {
-        return new PTXLIRGenerator(graph, runtime(), target, frameMap, method, lir);
+    public LIRGenerator newLIRGenerator(StructuredGraph graph, FrameMap frameMap, CallingConvention cc, LIR lir) {
+        return new PTXLIRGenerator(graph, runtime(), target, frameMap, cc, lir);
     }
 
     class HotSpotFrameContext implements FrameContext {
 
         @Override
         public void enter(TargetMethodAssembler tasm) {
-            Buffer codeBuffer = tasm.asm.codeBuffer;
-            codeBuffer.emitString(".version 1.4");
-            codeBuffer.emitString(".target sm_10");
             // codeBuffer.emitString(".address_size 32"); // PTX ISA version 2.3
         }
 
@@ -62,6 +59,11 @@
     }
 
     @Override
+    protected AbstractAssembler createAssembler(FrameMap frameMap) {
+        return new PTXAssembler(target, frameMap.registerConfig);
+    }
+
+    @Override
     public TargetMethodAssembler newAssembler(LIRGenerator lirGen, CompilationResult compilationResult) {
         // Omit the frame if the method:
         // - has no spill slots or other slots allocated during register allocation
@@ -69,22 +71,25 @@
         // - has no incoming arguments passed on the stack
         // - has no instructions with debug info
         FrameMap frameMap = lirGen.frameMap;
-        AbstractAssembler masm = new PTXAssembler(target, frameMap.registerConfig);
+        AbstractAssembler masm = createAssembler(frameMap);
         HotSpotFrameContext frameContext = new HotSpotFrameContext();
-        TargetMethodAssembler tasm = new TargetMethodAssembler(target, runtime(), frameMap, masm, frameContext, compilationResult);
+        TargetMethodAssembler tasm = new PTXTargetMethodAssembler(target, runtime(), frameMap, masm, frameContext, compilationResult);
         tasm.setFrameSize(frameMap.frameSize());
         return tasm;
     }
 
     @Override
-    public void emitCode(TargetMethodAssembler tasm, ResolvedJavaMethod method, LIRGenerator lirGen) {
+    public void emitCode(TargetMethodAssembler tasm, LIRGenerator lirGen, ResolvedJavaMethod codeCacheOwner) {
         // Emit the prologue
-        final String name = method.getName();
+        assert codeCacheOwner != null : lirGen.getGraph() + " is not associated with a method";
+        final String name = codeCacheOwner.getName();
         Buffer codeBuffer = tasm.asm.codeBuffer;
+        codeBuffer.emitString(".version 1.4");
+        codeBuffer.emitString(".target sm_10");
         codeBuffer.emitString0(".entry " + name + " (");
         codeBuffer.emitString("");
 
-        Signature signature = method.getSignature();
+        Signature signature = codeCacheOwner.getSignature();
         for (int i = 0; i < signature.getParameterCount(false); i++) {
             String param = ".param .u32 param" + i;
             codeBuffer.emitString(param);
--- a/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java	Mon May 13 17:11:31 2013 +0200
@@ -28,11 +28,7 @@
 import static com.oracle.graal.lir.ptx.PTXBitManipulationOp.IntrinsicOpcode.*;
 import static com.oracle.graal.lir.ptx.PTXCompare.*;
 
-import com.oracle.graal.api.code.CodeCacheProvider;
-import com.oracle.graal.api.code.DeoptimizationAction;
-import com.oracle.graal.api.code.RuntimeCallTarget;
-import com.oracle.graal.api.code.StackSlot;
-import com.oracle.graal.api.code.TargetDescription;
+import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.NumUtil;
@@ -85,8 +81,8 @@
         }
     }
 
-    public PTXLIRGenerator(StructuredGraph graph, CodeCacheProvider runtime, TargetDescription target, FrameMap frameMap, ResolvedJavaMethod method, LIR lir) {
-        super(graph, runtime, target, frameMap, method, lir);
+    public PTXLIRGenerator(StructuredGraph graph, CodeCacheProvider runtime, TargetDescription target, FrameMap frameMap, CallingConvention cc, LIR lir) {
+        super(graph, runtime, target, frameMap, cc, lir);
         lir.spillMoveFactory = new PTXSpillMoveFactory();
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXTargetMethodAssembler.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,61 @@
+/*
+ * 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.compiler.ptx;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.bridge.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.nodes.*;
+
+public class PTXTargetMethodAssembler extends TargetMethodAssembler {
+
+    private static CompilerToGPU toGPU = HotSpotGraalRuntime.graalRuntime().getCompilerToGPU();
+    private static boolean validDevice = toGPU.deviceInit();
+
+    // detach ??
+
+    public PTXTargetMethodAssembler(TargetDescription target, CodeCacheProvider runtime, FrameMap frameMap, AbstractAssembler asm, FrameContext frameContext, CompilationResult compilationResult) {
+        super(target, runtime, frameMap, asm, frameContext, compilationResult);
+    }
+
+    @Override
+    public CompilationResult finishTargetMethod(StructuredGraph graph) {
+        ResolvedJavaMethod method = graph.method();
+        assert method != null : graph + " is not associated wth a method";
+        CompilationResult graalCompile = super.finishTargetMethod(graph);
+
+        try {
+            if (validDevice) {
+                toGPU.generateKernel(graalCompile.getTargetCode(), method.getName());
+            }
+        } catch (Throwable th) {
+            th.printStackTrace();
+        }
+
+        return graalCompile;  // for now
+    }
+}
--- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java	Mon May 13 17:11:31 2013 +0200
@@ -38,8 +38,8 @@
  */
 public class SPARCLIRGenerator extends LIRGenerator {
 
-    public SPARCLIRGenerator(StructuredGraph graph, CodeCacheProvider runtime, TargetDescription target, FrameMap frameMap, ResolvedJavaMethod method, LIR lir) {
-        super(graph, runtime, target, frameMap, method, lir);
+    public SPARCLIRGenerator(StructuredGraph graph, CodeCacheProvider runtime, TargetDescription target, FrameMap frameMap, CallingConvention cc, LIR lir) {
+        super(graph, runtime, target, frameMap, cc, lir);
         // SPARC: Implement lir generator.
     }
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java	Mon May 13 17:11:31 2013 +0200
@@ -31,7 +31,6 @@
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
-import com.oracle.graal.virtual.nodes.*;
 import com.oracle.graal.virtual.phases.ea.*;
 
 /**
@@ -334,10 +333,6 @@
                 new CanonicalizerPhase().apply(graph, context);
                 new PartialEscapeAnalysisPhase(false, false).apply(graph, context);
 
-                for (MaterializeObjectNode materialize : graph.getNodes(MaterializeObjectNode.class)) {
-                    materialize.getVirtualObject().materializeAt(materialize, materialize.getValues(), false, materialize.getLockCount());
-                }
-
                 new CullFrameStatesPhase().apply(graph);
                 new DeadCodeEliminationPhase().apply(graph);
                 new CanonicalizerPhase().apply(graph, context);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/EliminateNestedCheckCastsTest.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/EliminateNestedCheckCastsTest.java	Mon May 13 17:11:31 2013 +0200
@@ -26,8 +26,9 @@
 
 import junit.framework.Assert;
 
-import org.junit.*;
+import org.junit.Test;
 
+import com.oracle.graal.api.code.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
@@ -61,7 +62,49 @@
 
     @Test
     public void test2() {
-        compileSnippet("test2Snippet", 5, 2);
+        compileSnippet("test2Snippet", 5, 1);
+    }
+
+    public static long test3Snippet(A1 a1) {
+        long result = a1.x1;
+        A2 a2 = (A2) a1;
+        if (a1.x1 == 42) {
+            A3 a3 = (A3) a2;
+            result = a3.x3;
+        }
+        return result;
+    }
+
+    @Test
+    public void test3() {
+        compileSnippet("test3Snippet", 2, 2);
+    }
+
+    public static long test4Snippet(A1 a1, A1 b1) {
+        A2 a2 = (A2) a1;
+        A3 b3 = (A3) b1;
+        return a2.x2 + b3.x3;
+    }
+
+    @Test
+    public void test4() {
+        compileSnippet("test4Snippet", 2, 2);
+    }
+
+    public static long test5Snippet(A1 a1) {
+        long sum = 0;
+        A2 a2 = (A2) a1;
+        A3 a3 = (A3) a2;
+        sum += a2.x2;
+        return sum + a3.x3;
+    }
+
+    @Test
+    public void test5() {
+        StructuredGraph graph = compileSnippet("test5Snippet", 2, 1);
+        for (LoadFieldNode lfn : graph.getNodes().filter(LoadFieldNode.class)) {
+            Assert.assertTrue(lfn.object() instanceof CheckCastNode);
+        }
     }
 
     private StructuredGraph compileSnippet(final String snippet, final int checkcasts, final int afterCanon) {
@@ -70,8 +113,9 @@
             @Override
             public StructuredGraph call() throws Exception {
                 StructuredGraph graph = parse(snippet);
+                Debug.dump(graph, "After parsing: " + snippet);
                 Assert.assertEquals(checkcasts, graph.getNodes().filter(CheckCastNode.class).count());
-                new CanonicalizerPhase.Instance(runtime(), null).apply(graph);
+                new CanonicalizerPhase.Instance(runtime(), new Assumptions(false)).apply(graph);
                 Assert.assertEquals(afterCanon, graph.getNodes(CheckCastNode.class).count());
                 return graph;
             }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Mon May 13 17:11:31 2013 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.compiler.test;
 
+import static com.oracle.graal.api.code.CodeUtil.*;
+
 import java.lang.reflect.*;
 import java.util.*;
 import java.util.concurrent.*;
@@ -29,6 +31,7 @@
 import org.junit.*;
 
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.code.CallingConvention.Type;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.compiler.*;
@@ -410,7 +413,8 @@
                 phasePlan.addPhase(PhasePosition.AFTER_PARSING, graphBuilderPhase);
                 phasePlan.addPhase(PhasePosition.LOW_LEVEL, new WriteBarrierAdditionPhase());
                 editPhasePlan(method, graph, phasePlan);
-                CompilationResult compResult = GraalCompiler.compileMethod(runtime(), replacements, backend, runtime().getTarget(), method, graph, null, phasePlan, OptimisticOptimizations.ALL,
+                CallingConvention cc = getCallingConvention(runtime, Type.JavaCallee, graph.method(), false);
+                CompilationResult compResult = GraalCompiler.compileGraph(graph, cc, method, runtime, replacements, backend, runtime().getTarget(), null, phasePlan, OptimisticOptimizations.ALL,
                                 new SpeculationLog());
                 if (printCompilation) {
                     TTY.println(String.format("@%-6d Graal %-70s %-45s %-50s | %4dms %5dB", id, "", "", "", System.currentTimeMillis() - start, compResult.getTargetCodeSize()));
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InfopointReasonTest.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InfopointReasonTest.java	Mon May 13 17:11:31 2013 +0200
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.compiler.test;
 
+import static com.oracle.graal.api.code.CodeUtil.*;
 import static org.junit.Assert.*;
 
 import java.lang.reflect.*;
@@ -29,6 +30,7 @@
 import org.junit.*;
 
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.code.CallingConvention.Type;
 import com.oracle.graal.api.code.CompilationResult.Call;
 import com.oracle.graal.api.code.CompilationResult.Infopoint;
 import com.oracle.graal.compiler.*;
@@ -56,7 +58,8 @@
     public void callInfopoints() {
         final Method method = getMethod("testMethod");
         final StructuredGraph graph = parse(method);
-        final CompilationResult cr = GraalCompiler.compileMethod(runtime, replacements, backend, runtime.getTarget(), runtime.lookupJavaMethod(method), graph, null, getDefaultPhasePlan(),
+        CallingConvention cc = getCallingConvention(runtime, Type.JavaCallee, graph.method(), false);
+        final CompilationResult cr = GraalCompiler.compileGraph(graph, cc, graph.method(), runtime, replacements, backend, runtime.getTarget(), null, getDefaultPhasePlan(),
                         OptimisticOptimizations.ALL, new SpeculationLog());
         for (Infopoint sp : cr.getInfopoints()) {
             assertNotNull(sp.reason);
@@ -77,7 +80,8 @@
             }
         }
         assertTrue(graphLineSPs > 0);
-        final CompilationResult cr = GraalCompiler.compileMethod(runtime, replacements, backend, runtime.getTarget(), runtime.lookupJavaMethod(method), graph, null, getDefaultPhasePlan(true),
+        CallingConvention cc = getCallingConvention(runtime, Type.JavaCallee, graph.method(), false);
+        final CompilationResult cr = GraalCompiler.compileGraph(graph, cc, graph.method(), runtime, replacements, backend, runtime.getTarget(), null, getDefaultPhasePlan(true),
                         OptimisticOptimizations.ALL, new SpeculationLog());
         int lineSPs = 0;
         for (Infopoint sp : cr.getInfopoints()) {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java	Mon May 13 17:11:31 2013 +0200
@@ -146,7 +146,7 @@
     @Test
     public void testLoop1() {
         SchedulePhase schedule = getFinalSchedule("testLoop1Snippet", TestMode.WITHOUT_FRAMESTATES);
-        assertEquals(7, schedule.getCFG().getBlocks().length);
+        assertEquals(6, schedule.getCFG().getBlocks().length);
         assertReadWithinStartBlock(schedule, true);
     }
 
@@ -170,7 +170,7 @@
     @Test
     public void testLoop2() {
         SchedulePhase schedule = getFinalSchedule("testLoop2Snippet", TestMode.WITHOUT_FRAMESTATES);
-        assertEquals(7, schedule.getCFG().getBlocks().length);
+        assertEquals(6, schedule.getCFG().getBlocks().length);
         assertReadWithinStartBlock(schedule, false);
     }
 
@@ -185,7 +185,7 @@
     @Test
     public void testArrayCopy() {
         SchedulePhase schedule = getFinalSchedule("testArrayCopySnippet", TestMode.INLINED_WITHOUT_FRAMESTATES);
-        StructuredGraph graph = (StructuredGraph) schedule.getCFG().getStartBlock().getBeginNode().graph();
+        StructuredGraph graph = schedule.getCFG().getStartBlock().getBeginNode().graph();
         ReturnNode ret = graph.getNodes(ReturnNode.class).first();
         assertTrue(ret.result() instanceof FloatingReadNode);
         assertEquals(schedule.getCFG().blockFor(ret), schedule.getCFG().blockFor(ret.result()));
@@ -219,11 +219,12 @@
             @Override
             public SchedulePhase call() throws Exception {
                 StructuredGraph graph = parse(snippet);
+                Assumptions assumptions = new Assumptions(false);
+                new CanonicalizerPhase.Instance(runtime, assumptions).apply(graph);
                 if (mode == TestMode.INLINED_WITHOUT_FRAMESTATES) {
-                    Assumptions assumptions = new Assumptions(false);
                     new InliningPhase(runtime(), null, replacements, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph);
                 }
-                HighTierContext context = new HighTierContext(runtime(), new Assumptions(false), replacements);
+                HighTierContext context = new HighTierContext(runtime(), assumptions, replacements);
                 new LoweringPhase(LoweringType.BEFORE_GUARDS).apply(graph, context);
                 if (mode == TestMode.WITHOUT_FRAMESTATES || mode == TestMode.INLINED_WITHOUT_FRAMESTATES) {
                     for (Node node : graph.getNodes()) {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/PushNodesThroughPiTest.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/PushNodesThroughPiTest.java	Mon May 13 17:11:31 2013 +0200
@@ -32,7 +32,8 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.spi.Lowerable.*;
+import com.oracle.graal.nodes.spi.Lowerable.LoweringType;
+import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
 
@@ -65,17 +66,24 @@
             public void run() {
                 StructuredGraph graph = compileTestSnippet(snippet);
 
+                int counter = 0;
                 for (ReadNode rn : graph.getNodes().filter(ReadNode.class)) {
-                    Object locId = rn.location().locationIdentity();
-                    if (locId instanceof ResolvedJavaField) {
-                        ResolvedJavaField field = (ResolvedJavaField) locId;
-                        if (field.getName().equals("x")) {
-                            Assert.assertTrue(rn.object() instanceof LocalNode);
-                        } else {
-                            Assert.assertTrue(rn.object() instanceof UnsafeCastNode);
+                    if (rn.location() instanceof ConstantLocationNode && rn.object().stamp() instanceof ObjectStamp) {
+                        long disp = ((ConstantLocationNode) rn.location()).getDisplacement();
+                        ResolvedJavaType receiverType = rn.object().objectStamp().type();
+                        ResolvedJavaField field = receiverType.findInstanceFieldWithOffset(disp);
+
+                        if (field != null) {
+                            if (field.getName().equals("x")) {
+                                Assert.assertTrue(rn.object() instanceof LocalNode);
+                            } else {
+                                Assert.assertTrue(rn.object() instanceof UnsafeCastNode);
+                            }
+                            counter++;
                         }
                     }
                 }
+                Assert.assertEquals(2, counter);
 
                 Assert.assertTrue(graph.getNodes().filter(IsNullNode.class).count() == 1);
             }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ReadAfterCheckCastTest.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ReadAfterCheckCastTest.java	Mon May 13 17:11:31 2013 +0200
@@ -22,15 +22,11 @@
  */
 package com.oracle.graal.compiler.test;
 
-import java.util.*;
-
 import org.junit.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.debug.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.Lowerable.*;
 import com.oracle.graal.phases.common.*;
@@ -96,36 +92,10 @@
 
                 Debug.dump(graph, "After lowering");
 
-                ArrayList<MergeNode> merges = new ArrayList<>();
-                ArrayList<FloatingReadNode> reads = new ArrayList<>();
-                for (Node n : graph.getNodes()) {
-                    if (n instanceof MergeNode) {
-                        // check shape
-                        MergeNode merge = (MergeNode) n;
-
-                        if (merge.inputs().count() == 2) {
-                            for (EndNode m : merge.forwardEnds()) {
-                                if (m.predecessor() != null && m.predecessor() instanceof BeginNode && m.predecessor().predecessor() instanceof IfNode) {
-                                    IfNode o = (IfNode) m.predecessor().predecessor();
-                                    if (o.falseSuccessor().next() instanceof DeoptimizeNode) {
-                                        merges.add(merge);
-                                    }
-                                }
-                            }
-                        }
-                    }
-                    if (n instanceof IntegerAddNode) {
-                        IntegerAddNode ian = (IntegerAddNode) n;
-
-                        Assert.assertTrue(ian.y() instanceof ConstantNode);
-                        Assert.assertTrue(ian.x() instanceof FloatingReadNode);
-                        reads.add((FloatingReadNode) ian.x());
-                    }
-                }
-
-                Assert.assertTrue(merges.size() >= reads.size());
-                for (int i = 0; i < reads.size(); i++) {
-                    assertOrderedAfterSchedule(graph, merges.get(i), reads.get(i));
+                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() == LocationNode.FINAL_LOCATION);
                 }
             }
         });
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SimpleCFGTest.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SimpleCFGTest.java	Mon May 13 17:11:31 2013 +0200
@@ -22,25 +22,34 @@
  */
 package com.oracle.graal.compiler.test;
 
-import static org.junit.Assert.*;
-
 import org.junit.*;
 
+import com.oracle.graal.debug.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.cfg.*;
 
-public class SimpleCFGTest {
+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");
+            }
+        });
+    }
 
     @Test
     public void testImplies() {
         StructuredGraph graph = new StructuredGraph();
 
-        EndNode trueEnd = graph.add(new EndNode());
-        EndNode falseEnd = graph.add(new EndNode());
+        AbstractEndNode trueEnd = graph.add(new EndNode());
+        AbstractEndNode falseEnd = graph.add(new EndNode());
 
-        BeginNode trueBegin = graph.add(new BeginNode());
+        AbstractBeginNode trueBegin = graph.add(new BeginNode());
         trueBegin.setNext(trueEnd);
-        BeginNode falseBegin = graph.add(new BeginNode());
+        AbstractBeginNode falseBegin = graph.add(new BeginNode());
         falseBegin.setNext(falseEnd);
 
         IfNode ifNode = graph.add(new IfNode(null, trueBegin, falseBegin, 0.5));
@@ -52,6 +61,8 @@
         ReturnNode returnNode = graph.add(new ReturnNode(null));
         merge.setNext(returnNode);
 
+        dumpGraph(graph);
+
         ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, true, true);
 
         Block[] blocks = cfg.getBlocks();
@@ -88,15 +99,15 @@
     }
 
     public static void assertDominator(Block block, Block expectedDominator) {
-        assertEquals("dominator of " + block, expectedDominator, block.getDominator());
+        Assert.assertEquals("dominator of " + block, expectedDominator, block.getDominator());
     }
 
     public static void assertDominatedSize(Block block, int size) {
-        assertEquals("number of dominated blocks of " + block, size, block.getDominated().size());
+        Assert.assertEquals("number of dominated blocks of " + block, size, block.getDominated().size());
     }
 
     public static void assertPostdominator(Block block, Block expectedPostdominator) {
-        assertEquals("postdominator of " + block, expectedPostdominator, block.getPostdominator());
+        Assert.assertEquals("postdominator of " + block, expectedPostdominator, block.getPostdominator());
     }
 
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/WriteBarrierVerificationTest.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,713 @@
+/*
+ * 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.compiler.test;
+
+import java.util.*;
+import java.util.concurrent.*;
+
+import org.junit.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.internal.*;
+import com.oracle.graal.hotspot.phases.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.spi.Lowerable.LoweringType;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.graph.*;
+import com.oracle.graal.phases.graph.ReentrantNodeIterator.NodeIteratorClosure;
+import com.oracle.graal.phases.tiers.*;
+
+/**
+ * The following tests validate the write barrier verification phase. For every tested snippet, an
+ * array of write barrier indices and the total write barrier number are passed as parameters. The
+ * indices denote the barriers that will be manually removed. The write barrier verification phase
+ * runs after the write barrier removal and depending on the result an assertion might be generated.
+ * The tests anticipate the presence or not of an assertion generated by the verification phase.
+ */
+public class WriteBarrierVerificationTest extends GraalCompilerTest {
+
+    public static int barrierIndex;
+
+    public static class Container {
+
+        public Container a;
+        public Container b;
+    }
+
+    private static native void safepoint();
+
+    public static void test1Snippet() {
+        Container main = new Container();
+        Container temp1 = new Container();
+        Container temp2 = new Container();
+        barrierIndex = 0;
+        safepoint();
+        barrierIndex = 1;
+        main.a = temp1;
+        safepoint();
+        barrierIndex = 2;
+        main.b = temp2;
+        safepoint();
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test1() {
+        test("test1Snippet", 2, new int[]{1});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test2() {
+        test("test1Snippet", 2, new int[]{2});
+    }
+
+    public static void test2Snippet() {
+        Container main = new Container();
+        Container temp1 = new Container();
+        Container temp2 = new Container();
+        barrierIndex = 0;
+        safepoint();
+        barrierIndex = 1;
+        main.a = temp1;
+        barrierIndex = 2;
+        main.b = temp2;
+        safepoint();
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test3() {
+        test("test2Snippet", 2, new int[]{1});
+    }
+
+    @Test
+    public void test4() {
+        test("test2Snippet", 2, new int[]{2});
+    }
+
+    public static void test3Snippet(boolean test) {
+        Container main = new Container();
+        Container temp1 = new Container();
+        Container temp2 = new Container();
+        barrierIndex = 0;
+        safepoint();
+        for (int i = 0; i < 10; i++) {
+            if (test) {
+                barrierIndex = 1;
+                main.a = temp1;
+                barrierIndex = 2;
+                main.b = temp2;
+            } else {
+                barrierIndex = 3;
+                main.a = temp1;
+                barrierIndex = 4;
+                main.b = temp2;
+            }
+        }
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test5() {
+        test("test3Snippet", 4, new int[]{1, 2});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test6() {
+        test("test3Snippet", 4, new int[]{3, 4});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test7() {
+        test("test3Snippet", 4, new int[]{1});
+    }
+
+    @Test
+    public void test8() {
+        test("test3Snippet", 4, new int[]{2});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test9() {
+        test("test3Snippet", 4, new int[]{3});
+    }
+
+    @Test
+    public void test10() {
+        test("test3Snippet", 4, new int[]{4});
+    }
+
+    public static void test4Snippet(boolean test) {
+        Container main = new Container();
+        Container temp1 = new Container();
+        Container temp2 = new Container();
+        safepoint();
+        barrierIndex = 1;
+        main.a = temp1;
+        for (int i = 0; i < 10; i++) {
+            if (test) {
+                barrierIndex = 2;
+                main.a = temp1;
+                barrierIndex = 3;
+                main.b = temp2;
+            } else {
+                barrierIndex = 4;
+                main.a = temp2;
+                barrierIndex = 5;
+                main.b = temp1;
+            }
+        }
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test11() {
+        test("test4Snippet", 5, new int[]{2, 3});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test12() {
+        test("test4Snippet", 5, new int[]{4, 5});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test13() {
+        test("test4Snippet", 5, new int[]{1});
+    }
+
+    public static void test5Snippet() {
+        Container main = new Container();
+        Container temp1 = new Container();
+        Container temp2 = new Container();
+        safepoint();
+        barrierIndex = 1;
+        main.a = temp1;
+        if (main.a == main.b) {
+            barrierIndex = 2;
+            main.a = temp1;
+            barrierIndex = 3;
+            main.b = temp2;
+        } else {
+            barrierIndex = 4;
+            main.a = temp2;
+            barrierIndex = 5;
+            main.b = temp1;
+        }
+        safepoint();
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test14() {
+        test("test5Snippet", 5, new int[]{1});
+    }
+
+    @Test
+    public void test15() {
+        test("test5Snippet", 5, new int[]{2});
+    }
+
+    @Test
+    public void test16() {
+        test("test5Snippet", 5, new int[]{4});
+    }
+
+    @Test
+    public void test17() {
+        test("test5Snippet", 5, new int[]{3});
+    }
+
+    @Test
+    public void test18() {
+        test("test5Snippet", 5, new int[]{5});
+    }
+
+    @Test
+    public void test19() {
+        test("test5Snippet", 5, new int[]{2, 3});
+    }
+
+    @Test
+    public void test20() {
+        test("test5Snippet", 5, new int[]{4, 5});
+    }
+
+    public static void test6Snippet(boolean test) {
+        Container main = new Container();
+        Container temp1 = new Container();
+        Container temp2 = new Container();
+        safepoint();
+        barrierIndex = 1;
+        main.a = temp1;
+        if (test) {
+            barrierIndex = 2;
+            main.a = temp1;
+            barrierIndex = 3;
+            main.b = temp1.a.a;
+        } else {
+            barrierIndex = 4;
+            main.a = temp2;
+            barrierIndex = 5;
+            main.b = temp2.a.a;
+        }
+        safepoint();
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test21() {
+        test("test6Snippet", 5, new int[]{1});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test22() {
+        test("test6Snippet", 5, new int[]{1, 2});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test23() {
+        test("test6Snippet", 5, new int[]{3});
+    }
+
+    @Test
+    public void test24() {
+        test("test6Snippet", 5, new int[]{4});
+    }
+
+    public static void test7Snippet(boolean test) {
+        Container main = new Container();
+        Container temp1 = new Container();
+        Container temp2 = new Container();
+        safepoint();
+        barrierIndex = 1;
+        main.a = temp1;
+        if (test) {
+            barrierIndex = 2;
+            main.a = temp1;
+        }
+        barrierIndex = 3;
+        main.b = temp2;
+        safepoint();
+    }
+
+    @Test
+    public void test25() {
+        test("test7Snippet", 3, new int[]{2});
+    }
+
+    @Test
+    public void test26() {
+        test("test7Snippet", 3, new int[]{3});
+    }
+
+    @Test
+    public void test27() {
+        test("test7Snippet", 3, new int[]{2, 3});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test28() {
+        test("test7Snippet", 3, new int[]{1});
+    }
+
+    public static void test8Snippet(boolean test) {
+        Container main = new Container();
+        Container temp1 = new Container();
+        Container temp2 = new Container();
+        safepoint();
+        if (test) {
+            barrierIndex = 1;
+            main.a = temp1;
+        }
+        barrierIndex = 2;
+        main.b = temp2;
+        safepoint();
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test29() {
+        test("test8Snippet", 2, new int[]{1});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test30() {
+        test("test8Snippet", 2, new int[]{2});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test31() {
+        test("test8Snippet", 2, new int[]{1, 2});
+    }
+
+    public static void test9Snippet(boolean test) {
+        Container main1 = new Container();
+        Container main2 = new Container();
+        Container temp1 = new Container();
+        Container temp2 = new Container();
+        safepoint();
+        if (test) {
+            barrierIndex = 1;
+            main1.a = temp1;
+        } else {
+            barrierIndex = 2;
+            main2.a = temp1;
+        }
+        barrierIndex = 3;
+        main1.b = temp2;
+        barrierIndex = 4;
+        main2.b = temp2;
+        safepoint();
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test32() {
+        test("test9Snippet", 4, new int[]{1});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test33() {
+        test("test9Snippet", 4, new int[]{2});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test34() {
+        test("test9Snippet", 4, new int[]{3});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test35() {
+        test("test9Snippet", 4, new int[]{4});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test36() {
+        test("test9Snippet", 4, new int[]{1, 2});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test37() {
+        test("test9Snippet", 4, new int[]{3, 4});
+    }
+
+    public static void test10Snippet(boolean test) {
+        Container main1 = new Container();
+        Container main2 = new Container();
+        Container temp1 = new Container();
+        Container temp2 = new Container();
+        safepoint();
+        if (test) {
+            barrierIndex = 1;
+            main1.a = temp1;
+            barrierIndex = 2;
+            main2.a = temp2;
+        } else {
+            barrierIndex = 3;
+            main2.a = temp1;
+        }
+        barrierIndex = 4;
+        main1.b = temp2;
+        barrierIndex = 5;
+        main2.b = temp2;
+        safepoint();
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test38() {
+        test("test10Snippet", 5, new int[]{1});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test39() {
+        test("test10Snippet", 5, new int[]{2});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test40() {
+        test("test10Snippet", 5, new int[]{3});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test41() {
+        test("test10Snippet", 5, new int[]{4});
+    }
+
+    @Test
+    public void test42() {
+        test("test10Snippet", 5, new int[]{5});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test43() {
+        test("test10Snippet", 5, new int[]{1, 2});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test44() {
+        test("test10Snippet", 5, new int[]{1, 2, 3});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test45() {
+        test("test10Snippet", 5, new int[]{3, 4});
+    }
+
+    public static void test11Snippet(boolean test) {
+        Container main1 = new Container();
+        Container main2 = new Container();
+        Container main3 = new Container();
+        Container temp1 = new Container();
+        Container temp2 = new Container();
+        safepoint();
+        if (test) {
+            barrierIndex = 1;
+            main1.a = temp1;
+            barrierIndex = 2;
+            main3.a = temp1;
+            if (!test) {
+                barrierIndex = 3;
+                main2.a = temp2;
+            } else {
+                barrierIndex = 4;
+                main1.a = temp2;
+                barrierIndex = 5;
+                main3.a = temp2;
+            }
+        } else {
+            barrierIndex = 6;
+            main1.b = temp2;
+            for (int i = 0; i < 10; i++) {
+                barrierIndex = 7;
+                main3.a = temp1;
+            }
+            barrierIndex = 8;
+            main3.b = temp2;
+        }
+        barrierIndex = 9;
+        main1.b = temp2;
+        barrierIndex = 10;
+        main2.b = temp2;
+        barrierIndex = 11;
+        main3.b = temp2;
+        safepoint();
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test46() {
+        test("test11Snippet", 11, new int[]{1});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test47() {
+        test("test11Snippet", 11, new int[]{2});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test48() {
+        test("test11Snippet", 11, new int[]{3});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test49() {
+        test("test11Snippet", 11, new int[]{6});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test50() {
+        test("test11Snippet", 11, new int[]{7});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test51() {
+        test("test11Snippet", 11, new int[]{8});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test52() {
+        test("test11Snippet", 11, new int[]{9});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test53() {
+        test("test11Snippet", 11, new int[]{10});
+    }
+
+    @Test
+    public void test54() {
+        test("test11Snippet", 11, new int[]{4});
+    }
+
+    @Test
+    public void test55() {
+        test("test11Snippet", 11, new int[]{5});
+    }
+
+    @Test
+    public void test56() {
+        test("test11Snippet", 11, new int[]{11});
+    }
+
+    public static void test12Snippet(boolean test) {
+        Container main = new Container();
+        Container main1 = new Container();
+        Container temp1 = new Container();
+        Container temp2 = new Container();
+        barrierIndex = 0;
+        safepoint();
+        barrierIndex = 7;
+        main1.a = temp1;
+        for (int i = 0; i < 10; i++) {
+            if (test) {
+                barrierIndex = 1;
+                main.a = temp1;
+                barrierIndex = 2;
+                main.b = temp2;
+            } else {
+                barrierIndex = 3;
+                main.a = temp1;
+                barrierIndex = 4;
+                main.b = temp2;
+            }
+        }
+        barrierIndex = 5;
+        main.a = temp1;
+        barrierIndex = 6;
+        main.b = temp1;
+        barrierIndex = 8;
+        main1.b = temp1;
+        safepoint();
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test57() {
+        test("test12Snippet", 8, new int[]{5});
+    }
+
+    @Test
+    public void test58() {
+        test("test12Snippet", 8, new int[]{6});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test59() {
+        test("test12Snippet", 8, new int[]{7});
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test60() {
+        test("test12Snippet", 8, new int[]{8});
+    }
+
+    private void test(final String snippet, final int expectedBarriers, final int... removedBarrierIndices) {
+
+        AssertionError expectedError = Debug.scope("WriteBarrierVerificationTest", new DebugDumpScope(snippet), new Callable<AssertionError>() {
+
+            public AssertionError call() {
+                final StructuredGraph graph = parse(snippet);
+                HighTierContext highTierContext = new HighTierContext(runtime(), new Assumptions(false), replacements);
+                MidTierContext midTierContext = new MidTierContext(runtime(), new Assumptions(false), replacements, runtime().getTarget(), OptimisticOptimizations.ALL);
+
+                new LoweringPhase(LoweringType.BEFORE_GUARDS).apply(graph, highTierContext);
+                new GuardLoweringPhase().apply(graph, midTierContext);
+                new SafepointInsertionPhase().apply(graph);
+                new WriteBarrierAdditionPhase().apply(graph);
+
+                // First, the total number of expected barriers is checked.
+                final int barriers = graph.getNodes(SerialWriteBarrier.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.getLocationIdentities()[0];
+                            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) {
+                            // Remove flagged write barriers.
+                            if (currentState) {
+                                graph.removeFixed(((SerialWriteBarrier) 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;
+                            }
+                        }
+                        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;
+                    }
+
+                    @Override
+                    protected Boolean afterSplit(AbstractBeginNode node, Boolean oldState) {
+                        return false;
+                    }
+                };
+
+                DebugConfig config = DebugScope.getConfig();
+                try {
+                    ReentrantNodeIterator.apply(closure, graph.start(), false, null);
+                    Debug.setConfig(Debug.fixedConfig(false, false, false, false, config.dumpHandlers(), config.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().equals("Write barrier must be present"));
+                    return error;
+                } finally {
+                    Debug.setConfig(config);
+                }
+                return null;
+            }
+        });
+        if (expectedError != null) {
+            throw expectedError;
+        }
+    }
+}
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/backend/AllocatorTest.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/backend/AllocatorTest.java	Mon May 13 17:11:31 2013 +0200
@@ -22,12 +22,15 @@
  */
 package com.oracle.graal.compiler.test.backend;
 
+import static com.oracle.graal.api.code.CodeUtil.*;
+
 import java.util.*;
 import java.util.concurrent.*;
 
 import org.junit.*;
 
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.code.CallingConvention.Type;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.*;
 import com.oracle.graal.compiler.test.*;
@@ -97,7 +100,7 @@
                 Value def = move.getResult();
                 Value use = move.getInput();
                 if (ValueUtil.isRegister(def)) {
-                    if (ValueUtil.isRegister(use) && ValueUtil.asRegister(def) != ValueUtil.asRegister(use)) {
+                    if (ValueUtil.isRegister(use)) {
                         regRegMoves++;
                     }
                 } else if (ValueUtil.isStackSlot(def)) {
@@ -123,7 +126,8 @@
 
             @Override
             public RegisterStats call() {
-                GraalCompiler.emitLIR(backend, backend.target, lir, graph, graph.method());
+                CallingConvention cc = getCallingConvention(runtime, Type.JavaCallee, graph.method(), false);
+                GraalCompiler.emitLIR(backend, backend.target, lir, graph, cc);
                 return new RegisterStats(lir);
             }
         });
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java	Mon May 13 17:11:31 2013 +0200
@@ -35,16 +35,15 @@
 import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
-import com.oracle.graal.virtual.nodes.*;
 import com.oracle.graal.virtual.phases.ea.*;
 
 /**
- * In these test cases the probability of all invokes is set to a high value, such that an
- * InliningPhase should inline them all. After that, the EscapeAnalysisPhase is expected to remove
- * all allocations and return the correct values.
+ * The PartialEscapeAnalysisPhase is expected to remove all allocations and return the correct
+ * values.
  */
 public class EscapeAnalysisTest extends GraalCompilerTest {
 
@@ -230,7 +229,7 @@
                     Assert.assertTrue(returnNode.result().toString(), returnNode.result().isConstant());
                     Assert.assertEquals(expectedConstantResult, returnNode.result().asConstant());
                 }
-                int newInstanceCount = graph.getNodes(NewInstanceNode.class).count() + graph.getNodes(NewArrayNode.class).count() + graph.getNodes(MaterializeObjectNode.class).count();
+                int newInstanceCount = graph.getNodes(NewInstanceNode.class).count() + graph.getNodes(NewArrayNode.class).count() + graph.getNodes(CommitAllocationNode.class).count();
                 Assert.assertEquals(0, newInstanceCount);
                 return returnNode;
             }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java	Mon May 13 17:11:31 2013 +0200
@@ -35,17 +35,16 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.util.*;
+import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.graph.*;
 import com.oracle.graal.phases.tiers.*;
-import com.oracle.graal.virtual.nodes.*;
 import com.oracle.graal.virtual.phases.ea.*;
 
 /**
- * In these test cases the probability of all invokes is set to a high value, such that an
- * InliningPhase should inline them all. After that, the PartialEscapeAnalysisPhase is expected to
- * remove all allocations and return the correct values.
+ * The PartialEscapeAnalysisPhase is expected to remove all allocations and return the correct
+ * values.
  */
 public class PartialEscapeAnalysisTest extends GraalCompilerTest {
 
@@ -137,9 +136,9 @@
             NodesToDoubles nodeProbabilities = new ComputeProbabilityClosure(result).apply();
             double probabilitySum = 0;
             int materializeCount = 0;
-            for (MaterializeObjectNode materialize : result.getNodes(MaterializeObjectNode.class)) {
-                probabilitySum += nodeProbabilities.get(materialize);
-                materializeCount++;
+            for (CommitAllocationNode materialize : result.getNodes(CommitAllocationNode.class)) {
+                probabilitySum += nodeProbabilities.get(materialize) * materialize.getVirtualObjects().size();
+                materializeCount += materialize.getVirtualObjects().size();
             }
             Assert.assertEquals("unexpected number of MaterializeObjectNodes", expectedCount, materializeCount);
             Assert.assertEquals("unexpected probability of MaterializeObjectNodes", expectedProbability, probabilitySum, 0.01);
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Mon May 13 17:11:31 2013 +0200
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.compiler;
 
-import java.lang.reflect.*;
 import java.util.*;
 import java.util.concurrent.*;
 
@@ -45,17 +44,29 @@
 import com.oracle.graal.phases.graph.*;
 import com.oracle.graal.phases.schedule.*;
 import com.oracle.graal.phases.tiers.*;
+import com.oracle.graal.phases.verify.*;
 import com.oracle.graal.virtual.phases.ea.*;
 
+/**
+ * Static methods for orchestrating the compilation of a {@linkplain StructuredGraph graph}.
+ */
 public class GraalCompiler {
 
-    public static CompilationResult compileMethod(final GraalCodeCacheProvider runtime, final Replacements replacements, final Backend backend, final TargetDescription target,
-                    final ResolvedJavaMethod method, final StructuredGraph graph, final GraphCache cache, final PhasePlan plan, final OptimisticOptimizations optimisticOpts,
+    /**
+     * Requests compilation of a given graph.
+     * 
+     * @param graph the graph to be compiled
+     * @param cc the calling convention for calls to the code compiled for {@code graph}
+     * @param installedCodeOwner the method the compiled code will be
+     *            {@linkplain InstalledCode#getMethod() associated} with once installed. This
+     *            argument can be null.
+     * @return the result of the compilation
+     */
+    public static CompilationResult compileGraph(final StructuredGraph graph, final CallingConvention cc, final ResolvedJavaMethod installedCodeOwner, final GraalCodeCacheProvider runtime,
+                    final Replacements replacements, final Backend backend, final TargetDescription target, final GraphCache cache, final PhasePlan plan, final OptimisticOptimizations optimisticOpts,
                     final SpeculationLog speculationLog) {
-        assert (method.getModifiers() & Modifier.NATIVE) == 0 : "compiling native methods is not supported";
-
         final CompilationResult compilationResult = new CompilationResult();
-        Debug.scope("GraalCompiler", new Object[]{graph, method, runtime}, new Runnable() {
+        Debug.scope("GraalCompiler", new Object[]{graph, runtime}, new Runnable() {
 
             public void run() {
                 final Assumptions assumptions = new Assumptions(GraalOptions.OptAssumptions);
@@ -68,13 +79,13 @@
                 final LIRGenerator lirGen = Debug.scope("BackEnd", lir, new Callable<LIRGenerator>() {
 
                     public LIRGenerator call() {
-                        return emitLIR(backend, target, lir, graph, method);
+                        return emitLIR(backend, target, lir, graph, cc);
                     }
                 });
                 Debug.scope("CodeGen", lirGen, new Runnable() {
 
                     public void run() {
-                        emitCode(backend, getLeafGraphIdArray(graph), assumptions, method, lirGen, compilationResult);
+                        emitCode(backend, getLeafGraphIdArray(graph), assumptions, lirGen, compilationResult, installedCodeOwner);
                     }
 
                 });
@@ -114,6 +125,7 @@
         } else {
             Debug.dump(graph, "initial state");
         }
+        new VerifyValueUsage(runtime).apply(graph);
 
         if (GraalOptions.OptCanonicalizer) {
             new CanonicalizerPhase.Instance(runtime, assumptions).apply(graph);
@@ -135,12 +147,13 @@
             }
             InliningPhase.storeHighLevelStatistics(graph);
         }
+        TypeProfileProxyNode.cleanFromGraph(graph);
 
         plan.runPhases(PhasePosition.HIGH_LEVEL, graph);
         Suites.DEFAULT.getHighTier().apply(graph, highTierContext);
         InliningPhase.storeMidLevelStatistics(graph);
 
-        MidTierContext midTierContext = new MidTierContext(runtime, assumptions, replacements, target);
+        MidTierContext midTierContext = new MidTierContext(runtime, assumptions, replacements, target, optimisticOpts);
         Suites.DEFAULT.getMidTier().apply(graph, midTierContext);
 
         plan.runPhases(PhasePosition.LOW_LEVEL, graph);
@@ -175,9 +188,9 @@
 
     }
 
-    public static LIRGenerator emitLIR(Backend backend, final TargetDescription target, final LIR lir, StructuredGraph graph, final ResolvedJavaMethod method) {
+    public static LIRGenerator emitLIR(Backend backend, final TargetDescription target, final LIR lir, StructuredGraph graph, CallingConvention cc) {
         final FrameMap frameMap = backend.newFrameMap();
-        final LIRGenerator lirGen = backend.newLIRGenerator(graph, frameMap, method, lir);
+        final LIRGenerator lirGen = backend.newLIRGenerator(graph, frameMap, cc, lir);
 
         Debug.scope("LIRGen", lirGen, new Runnable() {
 
@@ -206,16 +219,16 @@
         Debug.scope("Allocator", new Runnable() {
 
             public void run() {
-                new LinearScan(target, method, lir, lirGen, frameMap).allocate();
+                new LinearScan(target, lir, lirGen, frameMap).allocate();
             }
         });
         return lirGen;
     }
 
-    public static void emitCode(Backend backend, long[] leafGraphIds, Assumptions assumptions, ResolvedJavaMethod method, LIRGenerator lirGen, CompilationResult compilationResult) {
+    public static void emitCode(Backend backend, long[] leafGraphIds, Assumptions assumptions, LIRGenerator lirGen, CompilationResult compilationResult, ResolvedJavaMethod installedCodeOwner) {
         TargetMethodAssembler tasm = backend.newAssembler(lirGen, compilationResult);
-        backend.emitCode(tasm, method, lirGen);
-        CompilationResult result = tasm.finishTargetMethod(method, false);
+        backend.emitCode(tasm, lirGen, installedCodeOwner);
+        CompilationResult result = tasm.finishTargetMethod(lirGen.getGraph());
         if (!assumptions.isEmpty()) {
             result.setAssumptions(assumptions);
         }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalDebugConfig.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalDebugConfig.java	Mon May 13 17:11:31 2013 +0200
@@ -29,6 +29,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.*;
 
@@ -94,6 +95,24 @@
         return filter != null && filter.matches(currentScope);
     }
 
+    /**
+     * Extracts a {@link JavaMethod} from an opaque debug context.
+     * 
+     * @return the {@link JavaMethod} represented by {@code context} or null
+     */
+    public static JavaMethod asJavaMethod(Object context) {
+        if (context instanceof JavaMethod) {
+            return (JavaMethod) context;
+        }
+        if (context instanceof StructuredGraph) {
+            ResolvedJavaMethod method = ((StructuredGraph) context).method();
+            if (method != null) {
+                return method;
+            }
+        }
+        return null;
+    }
+
     private boolean checkMethodFilter() {
         if (methodFilter == null && extraFilters.isEmpty()) {
             return true;
@@ -102,9 +121,10 @@
                 if (extraFilters.contains(o)) {
                     return true;
                 } else if (methodFilter != null) {
-                    if (o instanceof JavaMethod) {
+                    JavaMethod method = asJavaMethod(o);
+                    if (method != null) {
                         for (MethodFilter filter : methodFilter) {
-                            if (filter.matches((JavaMethod) o)) {
+                            if (filter.matches(method)) {
                                 return true;
                             }
                         }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/Interval.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/Interval.java	Mon May 13 17:11:31 2013 +0200
@@ -430,7 +430,7 @@
     /**
      * The kind of this interval.
      */
-    private Kind kind;
+    private PlatformKind kind;
 
     /**
      * The head of the list of ranges describing this interval. This list is sorted by
@@ -501,15 +501,15 @@
     void assignLocation(AllocatableValue newLocation) {
         if (isRegister(newLocation)) {
             assert this.location == null : "cannot re-assign location for " + this;
-            if (newLocation.getKind() == Kind.Illegal && kind != Kind.Illegal) {
+            if (newLocation.getPlatformKind() == Kind.Illegal && kind != Kind.Illegal) {
                 this.location = asRegister(newLocation).asValue(kind);
                 return;
             }
         } else {
             assert this.location == null || isRegister(this.location) : "cannot re-assign location for " + this;
             assert isStackSlot(newLocation);
-            assert newLocation.getKind() != Kind.Illegal;
-            assert newLocation.getKind() == this.kind;
+            assert newLocation.getPlatformKind() != Kind.Illegal;
+            assert newLocation.getPlatformKind() == this.kind;
         }
         this.location = newLocation;
     }
@@ -522,14 +522,13 @@
         return location;
     }
 
-    public Kind kind() {
+    public PlatformKind kind() {
         assert !isRegister(operand) : "cannot access type for fixed interval";
         return kind;
     }
 
-    void setKind(Kind kind) {
+    void setKind(PlatformKind kind) {
         assert isRegister(operand) || this.kind() == Kind.Illegal || this.kind() == kind : "overwriting existing type";
-        assert kind == kind.getStackKind() || kind == Kind.Short : "these kinds should have int type registers";
         this.kind = kind;
     }
 
@@ -714,12 +713,12 @@
 
                 assert i1.splitParent() == this : "not a split child of this interval";
                 assert i1.kind() == kind() : "must be equal for all split children";
-                assert i1.spillSlot() == spillSlot() : "must be equal for all split children";
+                assert (i1.spillSlot() == null && spillSlot == null) || i1.spillSlot().equals(spillSlot()) : "must be equal for all split children";
 
                 for (int j = i + 1; j < splitChildren.size(); j++) {
                     Interval i2 = splitChildren.get(j);
 
-                    assert i1.operand != i2.operand : "same register number";
+                    assert !i1.operand.equals(i2.operand) : "same register number";
 
                     if (i1.from() < i2.from()) {
                         assert i1.to() <= i2.from() && i1.to() < i2.to() : "intervals overlapping";
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java	Mon May 13 17:11:31 2013 +0200
@@ -56,7 +56,6 @@
 public final class LinearScan {
 
     final TargetDescription target;
-    final JavaMethod method;
     final LIR ir;
     final LIRGenerator gen;
     final FrameMap frameMap;
@@ -156,9 +155,8 @@
      */
     private final int firstVariableNumber;
 
-    public LinearScan(TargetDescription target, ResolvedJavaMethod method, LIR ir, LIRGenerator gen, FrameMap frameMap) {
+    public LinearScan(TargetDescription target, LIR ir, LIRGenerator gen, FrameMap frameMap) {
         this.target = target;
-        this.method = method;
         this.ir = ir;
         this.gen = gen;
         this.frameMap = frameMap;
@@ -305,7 +303,7 @@
             intervals = Arrays.copyOf(intervals, intervals.length * 2);
         }
         intervalsSize++;
-        Variable variable = new Variable(source.kind(), ir.nextVariable(), asVariable(source.operand).flag);
+        Variable variable = new Variable(source.kind(), ir.nextVariable());
         assert variables.size() == variable.index;
         variables.add(variable);
 
@@ -413,7 +411,7 @@
      */
     boolean hasCall(int opId) {
         assert isEven(opId) : "opId not even";
-        return instructionForId(opId).hasCall();
+        return instructionForId(opId).destroysCallerSavedRegisters();
     }
 
     /**
@@ -884,7 +882,7 @@
     }
 
     private void reportFailure(int numBlocks) {
-        TTY.println(method.toString());
+        TTY.println(gen.getGraph().toString());
         TTY.println("Error: liveIn set of first block must be empty (when this fails, variables are used before they are defined)");
         TTY.print("affected registers:");
         TTY.println(blockData.get(ir.cfg.getStartBlock()).liveIn.toString());
@@ -968,7 +966,7 @@
         TTY.println(blockData.get(block).liveOut.toString());
     }
 
-    void addUse(AllocatableValue operand, int from, int to, RegisterPriority registerPriority, Kind kind) {
+    void addUse(AllocatableValue operand, int from, int to, RegisterPriority registerPriority, PlatformKind kind) {
         if (!isProcessed(operand)) {
             return;
         }
@@ -987,7 +985,7 @@
         interval.addUsePos(to & ~1, registerPriority);
     }
 
-    void addTemp(AllocatableValue operand, int tempPos, RegisterPriority registerPriority, Kind kind) {
+    void addTemp(AllocatableValue operand, int tempPos, RegisterPriority registerPriority, PlatformKind kind) {
         if (!isProcessed(operand)) {
             return;
         }
@@ -1008,7 +1006,7 @@
         return !isRegister(operand) || attributes(asRegister(operand)).isAllocatable();
     }
 
-    void addDef(AllocatableValue operand, int defPos, RegisterPriority registerPriority, Kind kind) {
+    void addDef(AllocatableValue operand, int defPos, RegisterPriority registerPriority, PlatformKind kind) {
         if (!isProcessed(operand)) {
             return;
         }
@@ -1181,7 +1179,7 @@
                 final int opId = op.id();
 
                 // add a temp range for each register if operation destroys caller-save registers
-                if (op.hasCall()) {
+                if (op.destroysCallerSavedRegisters()) {
                     for (Register r : callerSaveRegs) {
                         if (attributes(r).isAllocatable()) {
                             addTemp(r.asValue(), opId, RegisterPriority.None, Kind.Illegal);
@@ -1197,7 +1195,7 @@
                     @Override
                     public Value doValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
                         if (isVariableOrRegister(operand)) {
-                            addDef((AllocatableValue) operand, opId, registerPriorityOfOutputOperand(op), operand.getKind().getStackKind());
+                            addDef((AllocatableValue) operand, opId, registerPriorityOfOutputOperand(op), operand.getPlatformKind());
                             addRegisterHint(op, operand, mode, flags, true);
                         }
                         return operand;
@@ -1208,7 +1206,7 @@
                     @Override
                     public Value doValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
                         if (isVariableOrRegister(operand)) {
-                            addTemp((AllocatableValue) operand, opId, RegisterPriority.MustHaveRegister, operand.getKind().getStackKind());
+                            addTemp((AllocatableValue) operand, opId, RegisterPriority.MustHaveRegister, operand.getPlatformKind());
                             addRegisterHint(op, operand, mode, flags, false);
                         }
                         return operand;
@@ -1220,7 +1218,7 @@
                     public Value doValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
                         if (isVariableOrRegister(operand)) {
                             RegisterPriority p = registerPriorityOfInputOperand(flags);
-                            addUse((AllocatableValue) operand, blockFrom, opId + 1, p, operand.getKind().getStackKind());
+                            addUse((AllocatableValue) operand, blockFrom, opId + 1, p, operand.getPlatformKind());
                             addRegisterHint(op, operand, mode, flags, false);
                         }
                         return operand;
@@ -1232,7 +1230,7 @@
                     public Value doValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
                         if (isVariableOrRegister(operand)) {
                             RegisterPriority p = registerPriorityOfInputOperand(flags);
-                            addUse((AllocatableValue) operand, blockFrom, opId, p, operand.getKind().getStackKind());
+                            addUse((AllocatableValue) operand, blockFrom, opId, p, operand.getPlatformKind());
                             addRegisterHint(op, operand, mode, flags, false);
                         }
                         return operand;
@@ -1247,7 +1245,7 @@
 
                     @Override
                     public Value doValue(Value operand) {
-                        addUse((AllocatableValue) operand, blockFrom, opId + 1, RegisterPriority.None, operand.getKind().getStackKind());
+                        addUse((AllocatableValue) operand, blockFrom, opId + 1, RegisterPriority.None, operand.getPlatformKind());
                         return operand;
                     }
                 });
@@ -1483,7 +1481,7 @@
             Interval fromInterval = intervalAtBlockEnd(fromBlock, liveOperand);
             Interval toInterval = intervalAtBlockBegin(toBlock, liveOperand);
 
-            if (fromInterval != toInterval && (fromInterval.location() != toInterval.location())) {
+            if (fromInterval != toInterval && !fromInterval.location().equals(toInterval.location())) {
                 // need to insert move instruction
                 moveResolver.addMapping(fromInterval, toInterval);
             }
@@ -1681,7 +1679,7 @@
             // before we've consumed the inputs.
             if (op.id() < interval.currentTo()) {
                 // caller-save registers must not be included into oop-maps at calls
-                assert !op.hasCall() || !isRegister(operand) || !isCallerSave(operand) : "interval is in a caller-save register at a call . register will be overwritten";
+                assert !op.destroysCallerSavedRegisters() || !isRegister(operand) || !isCallerSave(operand) : "interval is in a caller-save register at a call . register will be overwritten";
 
                 frameMap.setReference(interval.location(), registerRefMap, frameRefMap);
 
@@ -1703,7 +1701,7 @@
     }
 
     private void computeDebugInfo(IntervalWalker iw, final LIRInstruction op, LIRFrameState info) {
-        BitSet registerRefMap = op.hasCall() ? null : frameMap.initRegisterRefMap();
+        BitSet registerRefMap = op.destroysCallerSavedRegisters() ? null : frameMap.initRegisterRefMap();
         BitSet frameRefMap = frameMap.initFrameRefMap();
         computeOopMap(iw, op, registerRefMap, frameRefMap);
 
@@ -1782,7 +1780,7 @@
             // remove useless moves
             if (op instanceof MoveOp) {
                 MoveOp move = (MoveOp) op;
-                if (move.getInput() == move.getResult()) {
+                if (move.getInput().equals(move.getResult())) {
                     instructions.set(j, null);
                     hasDead = true;
                 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScanWalker.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScanWalker.java	Mon May 13 17:11:31 2013 +0200
@@ -29,7 +29,6 @@
 import java.util.*;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.Register.RegisterFlag;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.alloc.Interval.RegisterBinding;
 import com.oracle.graal.compiler.alloc.Interval.RegisterPriority;
@@ -811,14 +810,15 @@
     }
 
     void initVarsForAlloc(Interval interval) {
-        EnumMap<RegisterFlag, Register[]> categorizedRegs = allocator.frameMap.registerConfig.getCategorizedAllocatableRegisters();
-        availableRegs = categorizedRegs.get(asVariable(interval.operand).flag);
+        availableRegs = allocator.frameMap.registerConfig.getAllocatableRegisters(interval.kind());
     }
 
     static boolean isMove(LIRInstruction op, Interval from, Interval to) {
         if (op instanceof MoveOp) {
             MoveOp move = (MoveOp) op;
-            return isVariable(move.getInput()) && isVariable(move.getResult()) && move.getInput() == from.operand && move.getResult() == to.operand;
+            if (isVariable(move.getInput()) && isVariable(move.getResult())) {
+                return move.getInput() != null && move.getInput().equals(from.operand) && move.getResult() != null && move.getResult().equals(to.operand);
+            }
         }
         return false;
     }
@@ -936,7 +936,7 @@
         if (interval.insertMoveWhenActivated()) {
             assert interval.isSplitChild();
             assert interval.currentSplitChild() != null;
-            assert interval.currentSplitChild().operand != operand : "cannot insert move between same interval";
+            assert !interval.currentSplitChild().operand.equals(operand) : "cannot insert move between same interval";
             if (GraalOptions.TraceLinearScanLevel >= 4) {
                 TTY.println("Inserting move from interval %d to %d because insertMoveWhenActivated is set", interval.currentSplitChild().operandNumber, interval.operandNumber);
             }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/MoveResolver.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/MoveResolver.java	Mon May 13 17:11:31 2013 +0200
@@ -134,7 +134,7 @@
         }
         for (i = 0; i < mappingTo.size(); i++) {
             Interval interval = mappingTo.get(i);
-            assert !usedRegs.contains(interval.location()) || interval.location() == mappingFrom.get(i).location() : "stack slots used in mappingFrom must be disjoint to mappingTo";
+            assert !usedRegs.contains(interval.location()) || interval.location().equals(mappingFrom.get(i).location()) : "stack slots used in mappingFrom must be disjoint to mappingTo";
         }
 
         return true;
@@ -169,7 +169,7 @@
 
         Value reg = to.location();
         if (isRegister(reg)) {
-            if (registerBlocked(asRegister(reg).number) > 1 || (registerBlocked(asRegister(reg).number) == 1 && reg != fromReg)) {
+            if (registerBlocked(asRegister(reg).number) > 1 || (registerBlocked(asRegister(reg).number) == 1 && !reg.equals(fromReg))) {
                 return false;
             }
         }
@@ -192,7 +192,7 @@
     }
 
     private void insertMove(Interval fromInterval, Interval toInterval) {
-        assert fromInterval.operand != toInterval.operand : "from and to interval equal: " + fromInterval;
+        assert !fromInterval.operand.equals(toInterval.operand) : "from and to interval equal: " + fromInterval;
         assert fromInterval.kind() == toInterval.kind() : "move between different types";
         assert insertIdx != -1 : "must setup insert position first";
 
@@ -207,7 +207,7 @@
     }
 
     private void insertMove(Value fromOpr, Interval toInterval) {
-        assert fromOpr.getKind() == toInterval.kind() : "move between different types";
+        assert fromOpr.getPlatformKind() == toInterval.kind() : "move between different types";
         assert insertIdx != -1 : "must setup insert position first";
 
         AllocatableValue toOpr = toInterval.operand;
@@ -331,7 +331,7 @@
             TTY.println("MoveResolver: adding mapping from interval %d (%s) to interval %d (%s)", fromInterval.operandNumber, fromInterval.location(), toInterval.operandNumber, toInterval.location());
         }
 
-        assert fromInterval.operand != toInterval.operand : "from and to interval equal: " + fromInterval;
+        assert !fromInterval.operand.equals(toInterval.operand) : "from and to interval equal: " + fromInterval;
         assert fromInterval.kind() == toInterval.kind();
         mappingFrom.add(fromInterval);
         mappingFromOpr.add(Value.ILLEGAL);
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/RegisterVerifier.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/RegisterVerifier.java	Mon May 13 17:11:31 2013 +0200
@@ -248,7 +248,7 @@
             // check if input operands are correct
             op.forEachInput(useProc);
             // invalidate all caller save registers at calls
-            if (op.hasCall()) {
+            if (op.destroysCallerSavedRegisters()) {
                 for (Register r : allocator.frameMap.registerConfig.getCallerSaveRegisters()) {
                     statePut(inputState, r.asValue(), null);
                 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Mon May 13 17:11:31 2013 +0200
@@ -165,7 +165,6 @@
                 throw new GraalInternalError("no mapping found for virtual object %s", obj);
             }
             if (state instanceof MaterializedObjectState) {
-                assert !(((MaterializedObjectState) state).materializedValue() instanceof VirtualObjectNode);
                 return toValue(((MaterializedObjectState) state).materializedValue());
             } else {
                 assert obj.entryCount() == 0 || state instanceof VirtualObjectState;
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Mon May 13 17:11:31 2013 +0200
@@ -61,7 +61,7 @@
     protected final StructuredGraph graph;
     protected final CodeCacheProvider runtime;
     protected final TargetDescription target;
-    protected final ResolvedJavaMethod method;
+    protected final CallingConvention cc;
 
     protected final DebugInfoBuilder debugInfoBuilder;
 
@@ -85,12 +85,18 @@
      */
     public abstract boolean canStoreConstant(Constant c);
 
-    public LIRGenerator(StructuredGraph graph, CodeCacheProvider runtime, TargetDescription target, FrameMap frameMap, ResolvedJavaMethod method, LIR lir) {
+    public LIRGenerator(StructuredGraph graph, CodeCacheProvider runtime, TargetDescription target, FrameMap frameMap, CallingConvention cc, LIR lir) {
         this.graph = graph;
         this.runtime = runtime;
         this.target = target;
         this.frameMap = frameMap;
-        this.method = method;
+        if (graph.getEntryBCI() == StructuredGraph.INVOCATION_ENTRY_BCI) {
+            this.cc = cc;
+        } else {
+            JavaType[] parameterTypes = new JavaType[]{runtime.lookupJavaType(long.class)};
+            CallingConvention tmp = frameMap.registerConfig.getCallingConvention(JavaCallee, runtime.lookupJavaType(void.class), parameterTypes, target, false);
+            this.cc = new CallingConvention(cc.getStackSize(), cc.getReturn(), tmp.getArgument(0));
+        }
         this.nodeOperands = graph.createNodeMap();
         this.lir = lir;
         this.debugInfoBuilder = createDebugInfoBuilder(nodeOperands);
@@ -112,8 +118,8 @@
         return runtime;
     }
 
-    public ResolvedJavaMethod method() {
-        return method;
+    public StructuredGraph getGraph() {
+        return graph;
     }
 
     /**
@@ -132,7 +138,7 @@
 
     public ValueNode valueForOperand(Value value) {
         for (Entry<Node, Value> entry : nodeOperands.entries()) {
-            if (entry.getValue() == value) {
+            if (entry.getValue().equals(value)) {
                 return (ValueNode) entry.getKey();
             }
         }
@@ -142,23 +148,18 @@
     /**
      * Creates a new {@linkplain Variable variable}.
      * 
-     * @param kind The kind of the new variable.
+     * @param platformKind The kind of the new variable.
      * @return a new variable
      */
     @Override
-    public Variable newVariable(Kind kind) {
-        Kind stackKind = kind.getStackKind();
-        switch (stackKind) {
-            case Int:
-            case Long:
-            case Object:
-                return new Variable(stackKind, lir.nextVariable(), Register.RegisterFlag.CPU);
-            case Float:
-            case Double:
-                return new Variable(stackKind, lir.nextVariable(), Register.RegisterFlag.FPU);
-            default:
-                throw GraalInternalError.shouldNotReachHere();
+    public Variable newVariable(PlatformKind platformKind) {
+        PlatformKind stackKind;
+        if (platformKind instanceof Kind) {
+            stackKind = ((Kind) platformKind).getStackKind();
+        } else {
+            stackKind = platformKind;
         }
+        return new Variable(stackKind, lir.nextVariable());
     }
 
     @Override
@@ -428,12 +429,8 @@
         ((LIRLowerable) node).generate(this);
     }
 
-    protected CallingConvention createCallingConvention() {
-        return frameMap.registerConfig.getCallingConvention(JavaCallee, method.getSignature().getReturnType(null), MetaUtil.signatureToTypes(method), target, false);
-    }
-
     protected void emitPrologue() {
-        CallingConvention incomingArguments = createCallingConvention();
+        CallingConvention incomingArguments = cc;
 
         Value[] params = new Value[incomingArguments.getArgumentCount()];
         for (int i = 0; i < params.length; i++) {
@@ -476,7 +473,7 @@
     }
 
     @Override
-    public void visitEndNode(EndNode end) {
+    public void visitEndNode(AbstractEndNode end) {
         moveToPhi(end.merge(), end);
     }
 
@@ -487,7 +484,7 @@
     public void visitLoopEnd(LoopEndNode x) {
     }
 
-    private void moveToPhi(MergeNode merge, EndNode pred) {
+    private void moveToPhi(MergeNode merge, AbstractEndNode pred) {
         if (GraalOptions.TraceLIRGeneratorLevel >= 1) {
             TTY.println("MOVE TO PHI from " + pred + " to " + merge);
         }
@@ -599,10 +596,10 @@
     @Override
     public void emitInvoke(Invoke x) {
         LoweredCallTargetNode callTarget = (LoweredCallTargetNode) x.callTarget();
-        CallingConvention cc = frameMap.registerConfig.getCallingConvention(callTarget.callType(), x.asNode().stamp().javaType(runtime), callTarget.signature(), target(), false);
-        frameMap.callsMethod(cc);
+        CallingConvention invokeCc = frameMap.registerConfig.getCallingConvention(callTarget.callType(), x.asNode().stamp().javaType(runtime), callTarget.signature(), target(), false);
+        frameMap.callsMethod(invokeCc);
 
-        Value[] parameters = visitInvokeArguments(cc, callTarget.arguments());
+        Value[] parameters = visitInvokeArguments(invokeCc, callTarget.arguments());
 
         LabelRef exceptionEdge = null;
         if (x instanceof InvokeWithExceptionNode) {
@@ -610,11 +607,11 @@
         }
         LIRFrameState callState = stateWithExceptionEdge(x, exceptionEdge);
 
-        Value result = cc.getReturn();
+        Value result = invokeCc.getReturn();
         if (callTarget instanceof DirectCallTargetNode) {
-            emitDirectCall((DirectCallTargetNode) callTarget, result, parameters, cc.getTemporaries(), callState);
+            emitDirectCall((DirectCallTargetNode) callTarget, result, parameters, invokeCc.getTemporaries(), callState);
         } else if (callTarget instanceof IndirectCallTargetNode) {
-            emitIndirectCall((IndirectCallTargetNode) callTarget, result, parameters, cc.getTemporaries(), callState);
+            emitIndirectCall((IndirectCallTargetNode) callTarget, result, parameters, invokeCc.getTemporaries(), callState);
         } else {
             throw GraalInternalError.shouldNotReachHere();
         }
@@ -645,13 +642,13 @@
         return value;
     }
 
-    public Value[] visitInvokeArguments(CallingConvention cc, Collection<ValueNode> arguments) {
+    public Value[] visitInvokeArguments(CallingConvention invokeCc, Collection<ValueNode> arguments) {
         // for each argument, load it into the correct location
         Value[] result = new Value[arguments.size()];
         int j = 0;
         for (ValueNode arg : arguments) {
             if (arg != null) {
-                AllocatableValue operand = toStackKind(cc.getArgument(j));
+                AllocatableValue operand = toStackKind(invokeCc.getArgument(j));
                 emitMove(operand, operand(arg));
                 result[j] = operand;
                 j++;
@@ -663,23 +660,23 @@
     }
 
     @Override
-    public Variable emitCall(RuntimeCallTarget callTarget, CallingConvention cc, DeoptimizingNode info, Value... args) {
+    public Variable emitCall(RuntimeCallTarget callTarget, CallingConvention callCc, DeoptimizingNode info, Value... args) {
         LIRFrameState state = info != null ? state(info) : null;
 
         // move the arguments into the correct location
-        frameMap.callsMethod(cc);
-        assert cc.getArgumentCount() == args.length : "argument count mismatch";
+        frameMap.callsMethod(callCc);
+        assert callCc.getArgumentCount() == args.length : "argument count mismatch";
         Value[] argLocations = new Value[args.length];
         for (int i = 0; i < args.length; i++) {
             Value arg = args[i];
-            AllocatableValue loc = cc.getArgument(i);
+            AllocatableValue loc = callCc.getArgument(i);
             emitMove(loc, arg);
             argLocations[i] = loc;
         }
-        emitCall(callTarget, cc.getReturn(), argLocations, cc.getTemporaries(), state);
+        emitCall(callTarget, callCc.getReturn(), argLocations, callCc.getTemporaries(), state);
 
-        if (isLegal(cc.getReturn())) {
-            return emitMove(cc.getReturn());
+        if (isLegal(callCc.getReturn())) {
+            return emitMove(callCc.getReturn());
         } else {
             return null;
         }
@@ -688,12 +685,12 @@
     @Override
     public void visitRuntimeCall(RuntimeCallNode x) {
         RuntimeCallTarget call = runtime.lookupRuntimeCall(x.getDescriptor());
-        CallingConvention cc = call.getCallingConvention();
-        frameMap.callsMethod(cc);
-        Value resultOperand = cc.getReturn();
-        Value[] args = visitInvokeArguments(cc, x.arguments());
+        CallingConvention callCc = call.getCallingConvention();
+        frameMap.callsMethod(callCc);
+        Value resultOperand = callCc.getReturn();
+        Value[] args = visitInvokeArguments(callCc, x.arguments());
 
-        emitCall(call, resultOperand, args, cc.getTemporaries(), state(x));
+        emitCall(call, resultOperand, args, callCc.getTemporaries(), state(x));
 
         if (isLegal(resultOperand)) {
             setResult(x, emitMove(resultOperand));
@@ -830,6 +827,35 @@
     public void beforeRegisterAllocation() {
     }
 
+    /**
+     * Gets an garbage vale for a given kind.
+     */
+    protected Constant zapValueForKind(PlatformKind kind) {
+        long dead = 0xDEADDEADDEADDEADL;
+        switch ((Kind) kind) {
+            case Boolean:
+                return Constant.FALSE;
+            case Byte:
+                return Constant.forByte((byte) dead);
+            case Char:
+                return Constant.forChar((char) dead);
+            case Short:
+                return Constant.forShort((short) dead);
+            case Int:
+                return Constant.forInt((int) dead);
+            case Double:
+                return Constant.forDouble(Double.longBitsToDouble(dead));
+            case Float:
+                return Constant.forFloat(Float.intBitsToFloat((int) dead));
+            case Long:
+                return Constant.forLong(dead);
+            case Object:
+                return Constant.NULL_OBJECT;
+            default:
+                throw new IllegalArgumentException(kind.toString());
+        }
+    }
+
     public abstract void emitBitCount(Variable result, Value operand);
 
     public abstract void emitBitScanForward(Variable result, Value operand);
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java	Mon May 13 17:11:31 2013 +0200
@@ -34,16 +34,10 @@
     public HighTier() {
         if (GraalOptions.FullUnroll) {
             addPhase(new LoopFullUnrollPhase());
-            if (GraalOptions.OptCanonicalizer) {
-                addPhase(new CanonicalizerPhase());
-            }
         }
 
         if (GraalOptions.OptTailDuplication) {
             addPhase(new TailDuplicationPhase());
-            if (GraalOptions.OptCanonicalizer) {
-                addPhase(new CanonicalizerPhase());
-            }
         }
 
         if (GraalOptions.PartialEscapeAnalysis) {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LowTier.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LowTier.java	Mon May 13 17:11:31 2013 +0200
@@ -34,6 +34,8 @@
 
         addPhase(new FrameStateAssignmentPhase());
 
+        addPhase(new ExpandLogicPhase());
+
         addPhase(new DeadCodeEliminationPhase());
     }
 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/MidTier.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/MidTier.java	Mon May 13 17:11:31 2013 +0200
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.compiler.phases;
 
+import com.oracle.graal.loop.phases.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
@@ -66,7 +67,8 @@
             addPhase(new CanonicalizerPhase());
         }
 
-        // Add safepoints to loops
+        addPhase(new LoopSafepointEliminationPhase());
+
         addPhase(new SafepointInsertionPhase());
 
         addPhase(new GuardLoweringPhase());
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java	Mon May 13 17:11:31 2013 +0200
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.*;
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
@@ -50,15 +51,18 @@
         return new FrameMap(runtime, target, runtime.lookupRegisterConfig());
     }
 
-    public abstract LIRGenerator newLIRGenerator(StructuredGraph graph, FrameMap frameMap, ResolvedJavaMethod method, LIR lir);
+    public abstract LIRGenerator newLIRGenerator(StructuredGraph graph, FrameMap frameMap, CallingConvention cc, LIR lir);
+
+    protected abstract AbstractAssembler createAssembler(FrameMap frameMap);
 
     public abstract TargetMethodAssembler newAssembler(LIRGenerator lirGen, CompilationResult compilationResult);
 
     /**
-     * Emits the code for a given method. This includes any architecture/runtime specific
-     * prefix/suffix. A prefix typically contains the code for setting up the frame, spilling
-     * callee-save registers, stack overflow checking, handling multiple entry points etc. A suffix
-     * may contain out-of-line stubs and method end guard instructions.
+     * Emits the code for a given graph.
+     * 
+     * @param installedCodeOwner the method the compiled code will be
+     *            {@linkplain InstalledCode#getMethod() associated} with once installed. This
+     *            argument can be null.
      */
-    public abstract void emitCode(TargetMethodAssembler tasm, ResolvedJavaMethod method, LIRGenerator lirGen);
+    public abstract void emitCode(TargetMethodAssembler tasm, LIRGenerator lirGen, ResolvedJavaMethod installedCodeOwner);
 }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Mon May 13 17:11:31 2013 +0200
@@ -47,7 +47,8 @@
     private int deletedNodeCount;
     private GraphEventLog eventLog;
 
-    InputChangedListener inputChanged;
+    NodeChangedListener inputChanged;
+    NodeChangedListener usagesDroppedZero;
     private final HashMap<CacheEntry, Node> cachedNodes = new HashMap<>();
 
     private static final class CacheEntry {
@@ -152,12 +153,12 @@
         return node;
     }
 
-    public interface InputChangedListener {
+    public interface NodeChangedListener {
 
-        void inputChanged(Node node);
+        void nodeChanged(Node node);
     }
 
-    public void trackInputChange(InputChangedListener inputChangedListener) {
+    public void trackInputChange(NodeChangedListener inputChangedListener) {
         this.inputChanged = inputChangedListener;
     }
 
@@ -165,6 +166,14 @@
         inputChanged = null;
     }
 
+    public void trackUsagesDroppedZero(NodeChangedListener usagesDroppedZeroListener) {
+        this.usagesDroppedZero = usagesDroppedZeroListener;
+    }
+
+    public void stopTrackingUsagesDroppedZero() {
+        usagesDroppedZero = null;
+    }
+
     /**
      * Adds a new node to the graph, if a <i>similar</i> node already exists in the graph, the
      * provided node will not be added to the graph but the <i>similar</i> node will be returned
@@ -468,7 +477,11 @@
     }
 
     public <T> NodeMap<T> createNodeMap() {
-        return new NodeMap<>(this);
+        return createNodeMap(false);
+    }
+
+    public <T> NodeMap<T> createNodeMap(boolean autoGrow) {
+        return new NodeMap<>(this, autoGrow);
     }
 
     public NodeFlood createNodeFlood() {
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Mon May 13 17:11:31 2013 +0200
@@ -25,7 +25,7 @@
 import java.lang.annotation.*;
 import java.util.*;
 
-import com.oracle.graal.graph.Graph.InputChangedListener;
+import com.oracle.graal.graph.Graph.NodeChangedListener;
 import com.oracle.graal.graph.NodeClass.*;
 import com.oracle.graal.graph.iterators.*;
 
@@ -193,12 +193,17 @@
                 assert assertTrue(result, "not found in usages, old input: %s", oldInput);
             }
             if (newInput != null) {
-                InputChangedListener inputChanged = graph.inputChanged;
+                NodeChangedListener inputChanged = graph.inputChanged;
                 if (inputChanged != null) {
-                    inputChanged.inputChanged(this);
+                    inputChanged.nodeChanged(this);
                 }
                 assert newInput.usages != null : "not yet added? " + newInput;
                 newInput.usages.add(this);
+            } else if (oldInput != null && oldInput.usages().isEmpty()) {
+                NodeChangedListener nodeChangedListener = graph.usagesDroppedZero;
+                if (nodeChangedListener != null) {
+                    nodeChangedListener.nodeChanged(oldInput);
+                }
             }
         }
     }
@@ -253,9 +258,9 @@
             boolean result = usage.getNodeClass().replaceFirstInput(usage, this, other);
             assert assertTrue(result, "not found in inputs, usage: %s", usage);
             if (other != null) {
-                InputChangedListener inputChanged = graph.inputChanged;
+                NodeChangedListener inputChanged = graph.inputChanged;
                 if (inputChanged != null) {
-                    inputChanged.inputChanged(usage);
+                    inputChanged.nodeChanged(usage);
                 }
                 other.usages.add(usage);
             }
@@ -299,6 +304,12 @@
 
         for (Node input : inputs()) {
             removeThisFromUsages(input);
+            if (input.usages().isEmpty()) {
+                NodeChangedListener nodeChangedListener = graph.usagesDroppedZero;
+                if (nodeChangedListener != null) {
+                    nodeChangedListener.nodeChanged(input);
+                }
+            }
         }
         getNodeClass().clearInputs(this);
     }
@@ -447,7 +458,7 @@
      * Provides a {@link Map} of properties of this node for use in debugging (e.g., to view in the
      * ideal graph visualizer).
      */
-    public Map<Object, Object> getDebugProperties() {
+    public final Map<Object, Object> getDebugProperties() {
         return getDebugProperties(new HashMap<>());
     }
 
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Mon May 13 17:11:31 2013 +0200
@@ -192,7 +192,7 @@
                 if (INPUT_LIST_CLASS.isAssignableFrom(type)) {
                     inputListOffsets.add(offset);
                 } else {
-                    assert NODE_CLASS.isAssignableFrom(type) : "invalid input type: " + type;
+                    assert NODE_CLASS.isAssignableFrom(type) || type.isInterface() : "invalid input type: " + type;
                     inputOffsets.add(offset);
                 }
                 if (field.getAnnotation(Node.Input.class).notDataflow()) {
@@ -759,8 +759,11 @@
     }
 
     public boolean edgesEqual(Node node, Node other) {
+        return inputsEqual(node, other) && successorsEqual(node, other);
+    }
+
+    public boolean inputsEqual(Node node, Node other) {
         assert node.getClass() == clazz && other.getClass() == clazz;
-
         int index = 0;
         while (index < directInputCount) {
             if (getNode(other, inputOffsets[index]) != getNode(node, inputOffsets[index])) {
@@ -775,8 +778,12 @@
             }
             index++;
         }
+        return true;
+    }
 
-        index = 0;
+    public boolean successorsEqual(Node node, Node other) {
+        assert node.getClass() == clazz && other.getClass() == clazz;
+        int index = 0;
         while (index < directSuccessorCount) {
             if (getNode(other, successorOffsets[index]) != getNode(node, successorOffsets[index])) {
                 return false;
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeMap.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeMap.java	Mon May 13 17:11:31 2013 +0200
@@ -29,19 +29,23 @@
 public final class NodeMap<T> {
 
     private final Graph graph;
+    private final boolean autogrow;
     private Object[] values;
-    private int size;
 
     public NodeMap(Graph graph) {
+        this(graph, false);
+    }
+
+    public NodeMap(Graph graph, boolean autogrow) {
         this.graph = graph;
-        values = new Object[graph.nodeIdCount()];
-        size = values.length;
+        this.values = new Object[graph.nodeIdCount()];
+        this.autogrow = autogrow;
     }
 
     public NodeMap(NodeMap<T> copyFrom) {
         this.graph = copyFrom.graph;
         this.values = Arrays.copyOf(copyFrom.values, copyFrom.values.length);
-        this.size = copyFrom.size;
+        this.autogrow = copyFrom.autogrow;
     }
 
     @SuppressWarnings("unchecked")
@@ -60,14 +64,21 @@
     }
 
     public int size() {
-        return size;
+        return values.length;
     }
 
     public boolean isNew(Node node) {
-        return node.id() >= size;
+        return node.id() >= size();
+    }
+
+    public void grow() {
+        this.values = Arrays.copyOf(values, graph.nodeIdCount());
     }
 
     private void check(Node node) {
+        if (autogrow && isNew(node)) {
+            grow();
+        }
         assert node.graph() == graph : "this node is not part of the graph";
         assert !isNew(node) : "this node was added to the graph after creating the node map : " + node;
     }
--- a/graal/com.oracle.graal.hotspot.amd64.test/src/com/oracle/graal/hotspot/amd64/test/AMD64HotSpotFrameOmissionTest.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64.test/src/com/oracle/graal/hotspot/amd64/test/AMD64HotSpotFrameOmissionTest.java	Mon May 13 17:11:31 2013 +0200
@@ -30,7 +30,6 @@
 import org.junit.*;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.Register.RegisterFlag;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.asm.amd64.*;
@@ -71,7 +70,7 @@
 
             @Override
             public void generateCode(AMD64Assembler asm) {
-                Register arg = getArgumentRegister(0, RegisterFlag.CPU);
+                Register arg = getArgumentRegister(0, Kind.Int);
                 asm.addl(arg, 5);
                 asm.movl(rax, arg);
                 asm.ret(0);
@@ -89,7 +88,7 @@
 
             @Override
             public void generateCode(AMD64Assembler asm) {
-                Register arg = getArgumentRegister(0, RegisterFlag.CPU);
+                Register arg = getArgumentRegister(0, Kind.Long);
                 asm.addq(arg, 1);
                 asm.movq(rax, arg);
                 asm.ret(0);
@@ -117,8 +116,8 @@
         Assert.assertArrayEquals(expectedCode, actualCode);
     }
 
-    private Register getArgumentRegister(int index, RegisterFlag flag) {
-        Register[] regs = runtime.lookupRegisterConfig().getCallingConventionRegisters(CallingConvention.Type.JavaCall, flag);
+    private Register getArgumentRegister(int index, Kind kind) {
+        Register[] regs = runtime.lookupRegisterConfig().getCallingConventionRegisters(CallingConvention.Type.JavaCall, kind);
         return regs[index];
     }
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DeoptimizeOp.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DeoptimizeOp.java	Mon May 13 17:11:31 2013 +0200
@@ -22,23 +22,21 @@
  */
 package com.oracle.graal.hotspot.amd64;
 
+import static com.oracle.graal.hotspot.HotSpotBackend.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.LIRInstruction.*;
+import com.oracle.graal.lir.LIRInstruction.Opcode;
 import com.oracle.graal.lir.amd64.*;
 import com.oracle.graal.lir.asm.*;
 
 @Opcode("DEOPT")
 final class AMD64DeoptimizeOp extends AMD64LIRInstruction {
 
-    public static final Descriptor DEOPTIMIZE = new Descriptor("deoptimize", true, void.class);
-
     private DeoptimizationAction action;
     private DeoptimizationReason reason;
     @State private LIRFrameState info;
@@ -54,6 +52,6 @@
         HotSpotGraalRuntime runtime = graalRuntime();
         Register thread = runtime.getRuntime().threadRegister();
         masm.movl(new AMD64Address(thread, runtime.getConfig().pendingDeoptimizationOffset), tasm.runtime.encodeDeoptActionAndReason(action, reason));
-        AMD64Call.directCall(tasm, masm, tasm.runtime.lookupRuntimeCall(DEOPTIMIZE), null, false, info);
+        AMD64Call.directCall(tasm, masm, tasm.runtime.lookupRuntimeCall(UNCOMMON_TRAP), null, false, info);
     }
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Mon May 13 17:11:31 2013 +0200
@@ -26,15 +26,14 @@
 import static com.oracle.graal.api.code.CallingConvention.Type.*;
 import static com.oracle.graal.api.code.ValueUtil.*;
 import static com.oracle.graal.phases.GraalOptions.*;
+import static java.lang.reflect.Modifier.*;
 
-import java.lang.reflect.*;
 import java.util.*;
 
 import sun.misc.*;
 
 import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.*;
 import com.oracle.graal.asm.amd64.*;
@@ -45,7 +44,8 @@
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.LIRInstruction.*;
+import com.oracle.graal.lir.LIRInstruction.ValueProcedure;
+import com.oracle.graal.lir.StandardOp.ParametersOp;
 import com.oracle.graal.lir.amd64.*;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.nodes.*;
@@ -58,17 +58,14 @@
 public class AMD64HotSpotBackend extends HotSpotBackend {
 
     private static final Unsafe unsafe = Unsafe.getUnsafe();
-    public static final Descriptor EXCEPTION_HANDLER = new Descriptor("exceptionHandler", true, void.class);
-    public static final Descriptor DEOPT_HANDLER = new Descriptor("deoptHandler", true, void.class);
-    public static final Descriptor IC_MISS_HANDLER = new Descriptor("icMissHandler", true, void.class);
 
     public AMD64HotSpotBackend(HotSpotRuntime runtime, TargetDescription target) {
         super(runtime, target);
     }
 
     @Override
-    public LIRGenerator newLIRGenerator(StructuredGraph graph, FrameMap frameMap, ResolvedJavaMethod method, LIR lir) {
-        return new AMD64HotSpotLIRGenerator(graph, runtime(), target, frameMap, method, lir);
+    public LIRGenerator newLIRGenerator(StructuredGraph graph, FrameMap frameMap, CallingConvention cc, LIR lir) {
+        return new AMD64HotSpotLIRGenerator(graph, runtime(), target, frameMap, cc, lir);
     }
 
     /**
@@ -99,13 +96,21 @@
 
     class HotSpotFrameContext implements FrameContext {
 
+        final boolean isStub;
+
+        HotSpotFrameContext(boolean isStub) {
+            this.isStub = isStub;
+        }
+
         @Override
         public void enter(TargetMethodAssembler tasm) {
             FrameMap frameMap = tasm.frameMap;
             int frameSize = frameMap.frameSize();
 
             AMD64MacroAssembler asm = (AMD64MacroAssembler) tasm.asm;
-            emitStackOverflowCheck(tasm, false);
+            if (!isStub) {
+                emitStackOverflowCheck(tasm, false);
+            }
             asm.decrementq(rsp, frameSize);
             if (GraalOptions.ZapStackOnMethodEntry) {
                 final int intSize = 4;
@@ -139,6 +144,11 @@
     }
 
     @Override
+    protected AbstractAssembler createAssembler(FrameMap frameMap) {
+        return new AMD64MacroAssembler(target, frameMap.registerConfig);
+    }
+
+    @Override
     public TargetMethodAssembler newAssembler(LIRGenerator lirGen, CompilationResult compilationResult) {
         // Omit the frame if the method:
         // - has no spill slots or other slots allocated during register allocation
@@ -150,53 +160,75 @@
         LIR lir = gen.lir;
         boolean omitFrame = CanOmitFrame && !frameMap.frameNeedsAllocating() && !lir.hasArgInCallerFrame();
 
-        AbstractAssembler masm = new AMD64MacroAssembler(target, frameMap.registerConfig);
-        HotSpotFrameContext frameContext = omitFrame ? null : new HotSpotFrameContext();
+        Stub stub = gen.getStub();
+        AbstractAssembler masm = createAssembler(frameMap);
+        HotSpotFrameContext frameContext = omitFrame ? null : new HotSpotFrameContext(stub != null);
         TargetMethodAssembler tasm = new TargetMethodAssembler(target, runtime(), frameMap, masm, frameContext, compilationResult);
         tasm.setFrameSize(frameMap.frameSize());
         StackSlot deoptimizationRescueSlot = gen.deoptimizationRescueSlot;
-        if (deoptimizationRescueSlot != null) {
+        if (deoptimizationRescueSlot != null && stub == null) {
             tasm.compilationResult.setCustomStackAreaOffset(frameMap.offsetForStackSlot(deoptimizationRescueSlot));
         }
 
-        Stub stub = runtime().asStub(lirGen.method());
         if (stub != null) {
-            final Set<Register> definedRegisters = new HashSet<>();
-            ValueProcedure defProc = new ValueProcedure() {
+
+            final Set<Register> definedRegisters = gatherDefinedRegisters(lir);
+            stub.initDestroyedRegisters(definedRegisters);
 
-                @Override
-                public Value doValue(Value value) {
-                    if (ValueUtil.isRegister(value)) {
-                        final Register reg = ValueUtil.asRegister(value);
-                        definedRegisters.add(reg);
-                    }
-                    return value;
-                }
-            };
-            for (Block block : lir.codeEmittingOrder()) {
-                for (LIRInstruction op : lir.lir(block)) {
-                    op.forEachTemp(defProc);
-                    op.forEachOutput(defProc);
-                }
+            // Eliminate unnecessary register preservation and
+            // record where preserved registers are saved
+            for (Map.Entry<LIRFrameState, AMD64RegistersPreservationOp> e : gen.calleeSaveInfo.entrySet()) {
+                AMD64RegistersPreservationOp save = e.getValue();
+                save.update(definedRegisters, e.getKey().debugInfo(), frameMap);
             }
-            stub.initDefinedRegisters(definedRegisters);
         }
 
         return tasm;
     }
 
+    /**
+     * Finds all the registers that are defined by some given LIR.
+     * 
+     * @param lir the LIR to examine
+     * @return the registers that are defined by or used as temps for any instruction in {@code lir}
+     */
+    private static Set<Register> gatherDefinedRegisters(LIR lir) {
+        final Set<Register> definedRegisters = new HashSet<>();
+        ValueProcedure defProc = new ValueProcedure() {
+
+            @Override
+            public Value doValue(Value value) {
+                if (ValueUtil.isRegister(value)) {
+                    final Register reg = ValueUtil.asRegister(value);
+                    definedRegisters.add(reg);
+                }
+                return value;
+            }
+        };
+        for (Block block : lir.codeEmittingOrder()) {
+            for (LIRInstruction op : lir.lir(block)) {
+                if (op instanceof ParametersOp) {
+                    // Don't consider this as a definition
+                } else {
+                    op.forEachTemp(defProc);
+                    op.forEachOutput(defProc);
+                }
+            }
+        }
+        return definedRegisters;
+    }
+
     @Override
-    public void emitCode(TargetMethodAssembler tasm, ResolvedJavaMethod method, LIRGenerator lirGen) {
+    public void emitCode(TargetMethodAssembler tasm, LIRGenerator lirGen, ResolvedJavaMethod installedCodeOwner) {
         AMD64MacroAssembler asm = (AMD64MacroAssembler) tasm.asm;
         FrameMap frameMap = tasm.frameMap;
         RegisterConfig regConfig = frameMap.registerConfig;
         HotSpotVMConfig config = runtime().config;
-        boolean isStatic = Modifier.isStatic(method.getModifiers());
-        Label unverifiedStub = isStatic ? null : new Label();
+        Label unverifiedStub = installedCodeOwner == null || isStatic(installedCodeOwner.getModifiers()) ? null : new Label();
 
         // Emit the prefix
 
-        if (!isStatic) {
+        if (unverifiedStub != null) {
             tasm.recordMark(Marks.MARK_UNVERIFIED_ENTRY);
             CallingConvention cc = regConfig.getCallingConvention(JavaCallee, null, new JavaType[]{runtime().lookupJavaType(Object.class)}, target, false);
             Register inlineCacheKlass = rax; // see definition of IC_Klass in
@@ -215,8 +247,8 @@
         // Emit code for the LIR
         lirGen.lir.emitCode(tasm);
 
-        boolean frameOmitted = tasm.frameContext == null;
-        if (!frameOmitted) {
+        HotSpotFrameContext frameContext = (HotSpotFrameContext) tasm.frameContext;
+        if (frameContext != null && !frameContext.isStub) {
             tasm.recordMark(Marks.MARK_EXCEPTION_HANDLER_ENTRY);
             AMD64Call.directCall(tasm, asm, runtime().lookupRuntimeCall(EXCEPTION_HANDLER), null, false, null);
             tasm.recordMark(Marks.MARK_DEOPT_HANDLER_ENTRY);
@@ -224,7 +256,7 @@
         } else {
             // No need to emit the stubs for entries back into the method since
             // it has no calls that can cause such "return" entries
-            assert !frameMap.accessesCallerFrame() : method;
+            assert !frameMap.accessesCallerFrame() : lirGen.getGraph();
         }
 
         if (unverifiedStub != null) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCRuntimeCallEpilogueOp.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.amd64;
+
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.lir.LIRInstruction.Opcode;
+import com.oracle.graal.lir.amd64.*;
+import com.oracle.graal.lir.asm.*;
+
+@Opcode("CRUNTIME_CALL_EPILOGUE")
+final class AMD64HotSpotCRuntimeCallEpilogueOp extends AMD64LIRInstruction {
+
+    @Override
+    public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
+        // reset last Java frame:
+        HotSpotVMConfig config = graalRuntime().getConfig();
+        Register thread = graalRuntime().getRuntime().threadRegister();
+
+        masm.movslq(new AMD64Address(thread, config.threadLastJavaSpOffset), 0);
+        masm.movslq(new AMD64Address(thread, config.threadLastJavaFpOffset), 0);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCRuntimeCallPrologueOp.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,44 @@
+/*
+ * 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.hotspot.amd64;
+
+import static com.oracle.graal.amd64.AMD64.*;
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.lir.LIRInstruction.Opcode;
+import com.oracle.graal.lir.amd64.*;
+import com.oracle.graal.lir.asm.*;
+
+@Opcode("CRUNTIME_CALL_PROLOGUE")
+final class AMD64HotSpotCRuntimeCallPrologueOp extends AMD64LIRInstruction {
+
+    @Override
+    public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
+
+        // save last Java frame
+        Register thread = graalRuntime().getRuntime().threadRegister();
+        masm.movq(new AMD64Address(thread, graalRuntime().getConfig().threadLastJavaSpOffset), rsp);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotDeoptimizeCallerOp.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.amd64;
+
+import static com.oracle.graal.hotspot.HotSpotBackend.*;
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.lir.LIRInstruction.Opcode;
+import com.oracle.graal.lir.amd64.*;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * Removes the current frame and tail calls the uncommon trap routine.
+ */
+@Opcode("DEOPT_CALLER")
+final class AMD64HotSpotDeoptimizeCallerOp extends AMD64HotSpotEpilogueOp {
+
+    private final DeoptimizationAction action;
+    private final DeoptimizationReason reason;
+
+    AMD64HotSpotDeoptimizeCallerOp(DeoptimizationAction action, DeoptimizationReason reason) {
+        this.action = action;
+        this.reason = reason;
+    }
+
+    @Override
+    public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
+        leaveFrameAndRestoreRbp(tasm, masm);
+
+        HotSpotGraalRuntime runtime = graalRuntime();
+        Register thread = runtime.getRuntime().threadRegister();
+        masm.movl(new AMD64Address(thread, runtime.getConfig().pendingDeoptimizationOffset), tasm.runtime.encodeDeoptActionAndReason(action, reason));
+        AMD64Call.directJmp(tasm, masm, tasm.runtime.lookupRuntimeCall(UNCOMMON_TRAP));
+    }
+}
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotEpilogueOp.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotEpilogueOp.java	Mon May 13 17:11:31 2013 +0200
@@ -22,12 +22,16 @@
  */
 package com.oracle.graal.hotspot.amd64;
 
+import static com.oracle.graal.amd64.AMD64.*;
+import static com.oracle.graal.api.code.ValueUtil.*;
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.amd64.*;
+import com.oracle.graal.lir.asm.*;
 
 /**
  * Superclass for operations that use the value of RBP saved in a method's prologue.
@@ -39,7 +43,22 @@
      * initial LIR generation is finished. Until then, we use a placeholder variable so that LIR
      * verification is successful.
      */
-    private static final Variable PLACEHOLDER = new Variable(Kind.Long, Integer.MAX_VALUE, Register.RegisterFlag.CPU);
+    private static final Variable PLACEHOLDER = new Variable(Kind.Long, Integer.MAX_VALUE);
 
     @Use({REG, STACK}) protected AllocatableValue savedRbp = PLACEHOLDER;
+
+    protected void leaveFrameAndRestoreRbp(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
+        if (isStackSlot(savedRbp)) {
+            // Restoring RBP from the stack must be done before the frame is removed
+            masm.movq(rbp, (AMD64Address) tasm.asAddress(savedRbp));
+        } else {
+            Register framePointer = asRegister(savedRbp);
+            if (framePointer != rbp) {
+                masm.movq(rbp, framePointer);
+            }
+        }
+        if (tasm.frameContext != null) {
+            tasm.frameContext.leave(tasm);
+        }
+    }
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotGraalRuntime.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotGraalRuntime.java	Mon May 13 17:11:31 2013 +0200
@@ -30,9 +30,9 @@
 /**
  * AMD64 specific implementation of {@link HotSpotGraalRuntime}.
  */
-final class AMD64HotSpotGraalRuntime extends HotSpotGraalRuntime {
+public class AMD64HotSpotGraalRuntime extends HotSpotGraalRuntime {
 
-    private AMD64HotSpotGraalRuntime() {
+    protected AMD64HotSpotGraalRuntime() {
     }
 
     /**
@@ -40,16 +40,25 @@
      */
     public static HotSpotGraalRuntime makeInstance() {
         if (graalRuntime() == null) {
-            setInstance(new AMD64HotSpotGraalRuntime());
+            HotSpotGraalRuntimeFactory factory = findFactory("AMD64");
+            if (factory != null) {
+                setInstance(factory.createRuntime());
+            } else {
+                setInstance(new AMD64HotSpotGraalRuntime());
+            }
         }
         return graalRuntime();
     }
 
+    protected Architecture createArchitecture() {
+        return new AMD64(config.useSSE, config.useAVX);
+    }
+
     @Override
     protected TargetDescription createTarget() {
         final int stackFrameAlignment = 16;
         final int implicitNullCheckLimit = 4096;
-        return new TargetDescription(new AMD64(config.useSSE, config.useAVX), true, stackFrameAlignment, implicitNullCheckLimit, true);
+        return new TargetDescription(createArchitecture(), true, stackFrameAlignment, implicitNullCheckLimit, true);
     }
 
     @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotJumpToExceptionHandlerInCallerOp.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,70 @@
+/*
+ * 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.hotspot.amd64;
+
+import static com.oracle.graal.amd64.AMD64.*;
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.asm.amd64.AMD64Assembler.ConditionFlag;
+import com.oracle.graal.lir.LIRInstruction.Opcode;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * Sets up the arguments for an exception handler in the callers frame, removes the current frame
+ * and jumps to the handler.
+ */
+@Opcode("JUMP_TO_EXCEPTION_HANDLER_IN_CALLER")
+final class AMD64HotSpotJumpToExceptionHandlerInCallerOp extends AMD64HotSpotEpilogueOp {
+
+    @Use(REG) AllocatableValue handlerInCallerPc;
+    @Use(REG) AllocatableValue exception;
+    @Use(REG) AllocatableValue exceptionPc;
+
+    AMD64HotSpotJumpToExceptionHandlerInCallerOp(AllocatableValue handlerInCallerPc, AllocatableValue exception, AllocatableValue exceptionPc) {
+        this.handlerInCallerPc = handlerInCallerPc;
+        this.exception = exception;
+        this.exceptionPc = exceptionPc;
+    }
+
+    @Override
+    public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
+        leaveFrameAndRestoreRbp(tasm, masm);
+
+        // Discard the return address, thus completing restoration of caller frame
+        masm.incrementq(rsp, 8);
+
+        // Restore rsp from rbp if the exception PC is a method handle call site.
+        Register thread = graalRuntime().getRuntime().threadRegister();
+        int isMethodHandleReturnOffset = graalRuntime().getConfig().threadIsMethodHandleReturnOffset;
+        AMD64Address dst = new AMD64Address(thread, isMethodHandleReturnOffset);
+        masm.cmpl(dst, 0);
+        masm.cmovq(ConditionFlag.NotEqual, rsp, rbp);
+
+        masm.jmp(asRegister(handlerInCallerPc));
+    }
+}
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Mon May 13 17:11:31 2013 +0200
@@ -23,9 +23,8 @@
 package com.oracle.graal.hotspot.amd64;
 
 import static com.oracle.graal.amd64.AMD64.*;
-import static com.oracle.graal.api.code.CallingConvention.Type.*;
 import static com.oracle.graal.api.code.ValueUtil.*;
-import static com.oracle.graal.hotspot.amd64.AMD64HotSpotUnwindOp.*;
+import static com.oracle.graal.hotspot.HotSpotBackend.*;
 
 import java.lang.reflect.*;
 import java.util.*;
@@ -54,14 +53,14 @@
 /**
  * LIR generator specialized for AMD64 HotSpot.
  */
-final class AMD64HotSpotLIRGenerator extends AMD64LIRGenerator implements HotSpotLIRGenerator {
+public class AMD64HotSpotLIRGenerator extends AMD64LIRGenerator implements HotSpotLIRGenerator {
 
     private HotSpotRuntime runtime() {
         return (HotSpotRuntime) runtime;
     }
 
-    AMD64HotSpotLIRGenerator(StructuredGraph graph, CodeCacheProvider runtime, TargetDescription target, FrameMap frameMap, ResolvedJavaMethod method, LIR lir) {
-        super(graph, runtime, target, frameMap, method, lir);
+    protected AMD64HotSpotLIRGenerator(StructuredGraph graph, CodeCacheProvider runtime, TargetDescription target, FrameMap frameMap, CallingConvention cc, LIR lir) {
+        super(graph, runtime, target, frameMap, cc, lir);
     }
 
     /**
@@ -115,6 +114,14 @@
      */
     List<AMD64HotSpotEpilogueOp> epilogueOps = new ArrayList<>(2);
 
+    @Override
+    public void append(LIRInstruction op) {
+        super.append(op);
+        if (op instanceof AMD64HotSpotEpilogueOp) {
+            epilogueOps.add((AMD64HotSpotEpilogueOp) op);
+        }
+    }
+
     @SuppressWarnings("hiding")
     @Override
     protected DebugInfoBuilder createDebugInfoBuilder(NodeMap<Value> nodeOperands) {
@@ -131,7 +138,7 @@
     @Override
     protected void emitPrologue() {
 
-        CallingConvention incomingArguments = createCallingConvention();
+        CallingConvention incomingArguments = cc;
 
         RegisterValue rbpParam = rbp.asValue(Kind.Long);
         Value[] params = new Value[incomingArguments.getArgumentCount() + 1];
@@ -145,8 +152,8 @@
             }
         }
         params[params.length - 1] = rbpParam;
+        ParametersOp paramsOp = new ParametersOp(params);
 
-        ParametersOp paramsOp = new ParametersOp(params);
         append(paramsOp);
 
         saveRbp = new SaveRbp(new PlaceholderOp(currentBlock, lir.lir(currentBlock).size()));
@@ -161,29 +168,102 @@
 
     @Override
     protected void emitReturn(Value input) {
-        AMD64HotSpotReturnOp op = new AMD64HotSpotReturnOp(input);
-        epilogueOps.add(op);
-        append(op);
+        append(new AMD64HotSpotReturnOp(input));
     }
 
     @Override
     protected boolean needOnlyOopMaps() {
         // Stubs only need oop maps
-        return runtime().asStub(method) != null;
+        return graph.start() instanceof StubStartNode;
+    }
+
+    /**
+     * Map from debug infos that need to be updated with callee save information to the operations
+     * that provide the information.
+     */
+    Map<LIRFrameState, AMD64RegistersPreservationOp> calleeSaveInfo = new HashMap<>();
+
+    private LIRFrameState currentRuntimeCallInfo;
+
+    @Override
+    protected void emitCall(RuntimeCallTarget callTarget, Value result, Value[] arguments, Value[] temps, LIRFrameState info) {
+        currentRuntimeCallInfo = info;
+        super.emitCall(callTarget, result, arguments, temps, info);
+    }
+
+    protected AMD64SaveRegistersOp emitSaveRegisters(Register[] savedRegisters, StackSlot[] savedRegisterLocations) {
+        AMD64SaveRegistersOp save = new AMD64SaveRegistersOp(savedRegisters, savedRegisterLocations);
+        append(save);
+        return save;
+    }
+
+    protected void emitRestoreRegisters(AMD64SaveRegistersOp save) {
+        append(new AMD64RestoreRegistersOp(save.getSlots().clone(), save));
+    }
+
+    Stub getStub() {
+        if (graph.start() instanceof StubStartNode) {
+            return ((StubStartNode) graph.start()).getStub();
+        }
+        return null;
     }
 
     @Override
-    protected CallingConvention createCallingConvention() {
-        Stub stub = runtime().asStub(method);
-        if (stub != null) {
-            return stub.getLinkage().getCallingConvention();
+    public Variable emitCall(RuntimeCallTarget callTarget, CallingConvention callCc, DeoptimizingNode info, Value... args) {
+        Stub stub = getStub();
+        boolean isCRuntimeCall = ((HotSpotRuntimeCallTarget) callTarget).isCRuntimeCall();
+        assert !isCRuntimeCall || stub != null : "direct call to C runtime can only be made from compiled stubs, not from " + graph;
+
+        AMD64SaveRegistersOp save = null;
+        StackSlot[] savedRegisterLocations = null;
+        if (isCRuntimeCall) {
+            if (stub.preservesRegisters()) {
+                Register[] savedRegisters = frameMap.registerConfig.getAllocatableRegisters();
+                savedRegisterLocations = new StackSlot[savedRegisters.length];
+                for (int i = 0; i < savedRegisters.length; i++) {
+                    PlatformKind kind = target.arch.getLargestStorableKind(savedRegisters[i].getRegisterCategory());
+                    assert kind != Kind.Illegal;
+                    StackSlot spillSlot = frameMap.allocateSpillSlot(kind);
+                    savedRegisterLocations[i] = spillSlot;
+                }
+                save = emitSaveRegisters(savedRegisters, savedRegisterLocations);
+            }
+            append(new AMD64HotSpotCRuntimeCallPrologueOp());
         }
 
-        if (graph.getEntryBCI() == StructuredGraph.INVOCATION_ENTRY_BCI) {
-            return super.createCallingConvention();
-        } else {
-            return frameMap.registerConfig.getCallingConvention(JavaCallee, method.getSignature().getReturnType(null), new JavaType[]{runtime.lookupJavaType(long.class)}, target, false);
+        Variable result = super.emitCall(callTarget, callCc, info, args);
+
+        if (isCRuntimeCall) {
+            append(new AMD64HotSpotCRuntimeCallEpilogueOp());
+            if (stub.preservesRegisters()) {
+                assert !calleeSaveInfo.containsKey(currentRuntimeCallInfo);
+                calleeSaveInfo.put(currentRuntimeCallInfo, save);
+
+                emitRestoreRegisters(save);
+            } else {
+                assert zapRegisters();
+            }
         }
+
+        return result;
+    }
+
+    protected AMD64ZapRegistersOp emitZapRegisters(Register[] zappedRegisters, Constant[] zapValues) {
+        AMD64ZapRegistersOp zap = new AMD64ZapRegistersOp(zappedRegisters, zapValues);
+        append(zap);
+        return zap;
+    }
+
+    protected boolean zapRegisters() {
+        Register[] zappedRegisters = frameMap.registerConfig.getAllocatableRegisters();
+        Constant[] zapValues = new Constant[zappedRegisters.length];
+        for (int i = 0; i < zappedRegisters.length; i++) {
+            PlatformKind kind = target.arch.getLargestStorableKind(zappedRegisters[i].getRegisterCategory());
+            assert kind != Kind.Illegal;
+            zapValues[i] = zapValueForKind(kind);
+        }
+        calleeSaveInfo.put(currentRuntimeCallInfo, emitZapRegisters(zappedRegisters, zapValues));
+        return true;
     }
 
     @Override
@@ -224,7 +304,6 @@
     @Override
     public void emitTailcall(Value[] args, Value address) {
         append(new AMD64TailcallOp(args, address));
-
     }
 
     @Override
@@ -252,11 +331,12 @@
 
     @Override
     public void emitUnwind(Value exception) {
-        RegisterValue exceptionParameter = EXCEPTION.asValue();
+        RuntimeCallTarget stub = getRuntime().lookupRuntimeCall(HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER);
+        CallingConvention stubCc = stub.getCallingConvention();
+        assert stubCc.getArgumentCount() == 2;
+        RegisterValue exceptionParameter = (RegisterValue) stubCc.getArgument(0);
         emitMove(exceptionParameter, exception);
-        AMD64HotSpotUnwindOp op = new AMD64HotSpotUnwindOp(exceptionParameter);
-        epilogueOps.add(op);
-        append(op);
+        append(new AMD64HotSpotUnwindOp(exceptionParameter));
     }
 
     @Override
@@ -265,6 +345,30 @@
     }
 
     @Override
+    public void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason) {
+        append(new AMD64HotSpotDeoptimizeCallerOp(action, reason));
+    }
+
+    @Override
+    public void emitPatchReturnAddress(ValueNode address) {
+        append(new AMD64HotSpotPatchReturnAddressOp(load(operand(address))));
+    }
+
+    @Override
+    public void emitJumpToExceptionHandlerInCaller(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc) {
+        Variable handler = load(operand(handlerInCallerPc));
+        RuntimeCallTarget stub = getRuntime().lookupRuntimeCall(EXCEPTION_HANDLER_IN_CALLER);
+        CallingConvention stubCc = stub.getCallingConvention();
+        assert stubCc.getArgumentCount() == 2;
+        RegisterValue exceptionFixed = (RegisterValue) stubCc.getArgument(0);
+        RegisterValue exceptionPcFixed = (RegisterValue) stubCc.getArgument(1);
+        emitMove(exceptionFixed, operand(exception));
+        emitMove(exceptionPcFixed, operand(exceptionPc));
+        AMD64HotSpotJumpToExceptionHandlerInCallerOp op = new AMD64HotSpotJumpToExceptionHandlerInCallerOp(handler, exceptionFixed, exceptionPcFixed);
+        append(op);
+    }
+
+    @Override
     public void beforeRegisterAllocation() {
         boolean hasDebugInfo = lir.hasDebugInfo();
         AllocatableValue savedRbp = saveRbp.finalize(hasDebugInfo);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotPatchReturnAddressOp.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.amd64;
+
+import static com.oracle.graal.amd64.AMD64.*;
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.lir.LIRInstruction.Opcode;
+import com.oracle.graal.lir.amd64.*;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * Patch the return address of the current frame.
+ */
+@Opcode("PATCH_RETURN")
+final class AMD64HotSpotPatchReturnAddressOp extends AMD64LIRInstruction {
+
+    @Use(REG) AllocatableValue address;
+
+    AMD64HotSpotPatchReturnAddressOp(AllocatableValue address) {
+        this.address = address;
+    }
+
+    @Override
+    public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
+        int frameSize = tasm.frameMap.frameSize();
+        masm.movq(new AMD64Address(rsp, frameSize), asRegister(address));
+    }
+}
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRegisterConfig.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRegisterConfig.java	Mon May 13 17:11:31 2013 +0200
@@ -29,7 +29,6 @@
 import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.code.CallingConvention.Type;
-import com.oracle.graal.api.code.Register.RegisterFlag;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
@@ -38,25 +37,39 @@
 // @formatter:off
 public class AMD64HotSpotRegisterConfig implements RegisterConfig {
 
+    private final Architecture architecture;
+
     private final Register[] allocatable = initAllocatable();
 
-    private final EnumMap<RegisterFlag, Register[]> categorized = Register.categorize(allocatable);
+    private final HashMap<PlatformKind, Register[]> categorized = new HashMap<>();
 
     private final RegisterAttributes[] attributesMap;
 
     @Override
     public Register[] getAllocatableRegisters() {
-        return allocatable;
+        return allocatable.clone();
     }
 
-    @Override
-    public EnumMap<RegisterFlag, Register[]> getCategorizedAllocatableRegisters() {
-        return categorized;
+    public Register[] getAllocatableRegisters(PlatformKind kind) {
+        if (categorized.containsKey(kind)) {
+            return categorized.get(kind);
+        }
+
+        ArrayList<Register> list = new ArrayList<>();
+        for (Register reg : getAllocatableRegisters()) {
+            if (architecture.canStoreValue(reg.getRegisterCategory(), kind)) {
+                list.add(reg);
+            }
+        }
+
+        Register[] ret = list.toArray(new Register[0]);
+        categorized.put(kind, ret);
+        return ret;
     }
 
     @Override
     public RegisterAttributes[] getAttributesMap() {
-        return attributesMap;
+        return attributesMap.clone();
     }
 
     private final Register[] javaGeneralParameterRegisters;
@@ -93,7 +106,9 @@
         return allocatable;
     }
 
-    public AMD64HotSpotRegisterConfig(HotSpotVMConfig config, boolean globalStubConfig) {
+    public AMD64HotSpotRegisterConfig(Architecture architecture, HotSpotVMConfig config, boolean globalStubConfig) {
+        this.architecture = architecture;
+
         if (config.windowsOs) {
             javaGeneralParameterRegisters = new Register[] {rdx, r8, r9, rdi, rsi, rcx};
             nativeGeneralParameterRegisters = new Register[] {rcx, rdx, r8, r9};
@@ -109,7 +124,7 @@
                 xmm0, xmm1, xmm2,  xmm3,  xmm4,  xmm5,  xmm6,  xmm7,
                 xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15
             };
-            csl = new CalleeSaveLayout(0, -1, 8, regs);
+            csl = new CalleeSaveLayout(architecture, 0, -1, 8, regs);
         } else {
             csl = null;
         }
@@ -135,10 +150,11 @@
         return callingConvention(javaGeneralParameterRegisters, returnType, parameterTypes, type, target, stackOnly);
     }
 
-    public Register[] getCallingConventionRegisters(Type type, RegisterFlag flag) {
-        if (flag == RegisterFlag.FPU) {
+    public Register[] getCallingConventionRegisters(Type type, Kind kind) {
+        if (architecture.canStoreValue(XMM, kind)) {
             return xmmParameterRegisters;
         }
+        assert architecture.canStoreValue(CPU, kind);
         return type == Type.NativeCall ? nativeGeneralParameterRegisters : javaGeneralParameterRegisters;
     }
 
@@ -178,7 +194,7 @@
 
             if (locations[i] == null) {
                 locations[i] = StackSlot.get(kind.getStackKind(), currentStackOffset, !type.out);
-                currentStackOffset += Math.max(target.sizeInBytes(kind), target.wordSize);
+                currentStackOffset += Math.max(target.arch.getSizeInBytes(kind), target.wordSize);
             }
         }
 
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotReturnOp.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotReturnOp.java	Mon May 13 17:11:31 2013 +0200
@@ -22,18 +22,15 @@
  */
 package com.oracle.graal.hotspot.amd64;
 
-import static com.oracle.graal.amd64.AMD64.*;
-import static com.oracle.graal.api.code.ValueUtil.*;
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.lir.LIRInstruction.Opcode;
 import com.oracle.graal.lir.asm.*;
 
 /**
- * Performs an unwind to throw an exception.
+ * Returns from a function.
  */
 @Opcode("RETURN")
 final class AMD64HotSpotReturnOp extends AMD64HotSpotEpilogueOp {
@@ -46,18 +43,7 @@
 
     @Override
     public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
-        if (isStackSlot(savedRbp)) {
-            // Restoring RBP from the stack must be done before the frame is removed
-            masm.movq(rbp, (AMD64Address) tasm.asAddress(savedRbp));
-        } else {
-            Register framePointer = asRegister(savedRbp);
-            if (framePointer != rbp) {
-                masm.movq(rbp, framePointer);
-            }
-        }
-        if (tasm.frameContext != null) {
-            tasm.frameContext.leave(tasm);
-        }
+        leaveFrameAndRestoreRbp(tasm, masm);
         masm.ret(0);
     }
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRuntime.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRuntime.java	Mon May 13 17:11:31 2013 +0200
@@ -23,28 +23,12 @@
 package com.oracle.graal.hotspot.amd64;
 
 import static com.oracle.graal.amd64.AMD64.*;
-import static com.oracle.graal.compiler.amd64.AMD64LIRGenerator.*;
-import static com.oracle.graal.hotspot.amd64.AMD64DeoptimizeOp.*;
-import static com.oracle.graal.hotspot.amd64.AMD64HotSpotUnwindOp.*;
-import static com.oracle.graal.hotspot.nodes.IdentityHashCodeStubCall.*;
-import static com.oracle.graal.hotspot.nodes.MonitorEnterStubCall.*;
-import static com.oracle.graal.hotspot.nodes.MonitorExitStubCall.*;
-import static com.oracle.graal.hotspot.nodes.NewArraySlowStubCall.*;
-import static com.oracle.graal.hotspot.nodes.NewArrayStubCall.*;
-import static com.oracle.graal.hotspot.nodes.NewInstanceSlowStubCall.*;
-import static com.oracle.graal.hotspot.nodes.NewInstanceStubCall.*;
-import static com.oracle.graal.hotspot.nodes.NewMultiArrayStubCall.*;
-import static com.oracle.graal.hotspot.nodes.ThreadIsInterruptedStubCall.*;
-import static com.oracle.graal.hotspot.nodes.VMErrorNode.*;
-import static com.oracle.graal.hotspot.nodes.VerifyOopStubCall.*;
-import static com.oracle.graal.hotspot.nodes.WriteBarrierPostStubCall.*;
-import static com.oracle.graal.hotspot.nodes.WriteBarrierPreStubCall.*;
+import static com.oracle.graal.hotspot.HotSpotBackend.*;
 import static com.oracle.graal.hotspot.replacements.AESCryptSubstitutions.DecryptBlockStubCall.*;
 import static com.oracle.graal.hotspot.replacements.AESCryptSubstitutions.EncryptBlockStubCall.*;
 import static com.oracle.graal.hotspot.replacements.CipherBlockChainingSubstitutions.DecryptAESCryptStubCall.*;
 import static com.oracle.graal.hotspot.replacements.CipherBlockChainingSubstitutions.EncryptAESCryptStubCall.*;
 
-import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
@@ -62,98 +46,18 @@
         Kind word = graalRuntime.getTarget().wordKind;
 
         // @formatter:off
-        addRuntimeCall(UNWIND_EXCEPTION, config.unwindExceptionStub,
-               /*           temps */ null,
-               /*             ret */ ret(Kind.Void),
-               /* arg0: exception */ rax.asValue(Kind.Object));
-
-        addRuntimeCall(DEOPTIMIZE, config.deoptimizeStub,
-                /*           temps */ null,
-                /*             ret */ ret(Kind.Void));
-
-        addRuntimeCall(ARITHMETIC_FREM, config.arithmeticFremStub,
-                /*           temps */ new Register[]{AMD64.rax},
-                /*             ret */ ret(Kind.Float),
-                /* arg0:         a */ javaCallingConvention(Kind.Float,
-                /* arg1:         b */                       Kind.Float));
-
-        addRuntimeCall(ARITHMETIC_DREM, config.arithmeticDremStub,
-                /*           temps */ new Register[]{AMD64.rax},
-                /*             ret */ ret(Kind.Double),
-                /* arg0:         a */ javaCallingConvention(Kind.Double,
-                /* arg1:         b */                       Kind.Double));
-
-        addRuntimeCall(MONITORENTER, config.monitorEnterStub,
-                /*        temps */ null,
-                /*          ret */ ret(Kind.Void),
-                /* arg0: object */ javaCallingConvention(Kind.Object,
-                /* arg1:   lock */                       word));
-
-       addRuntimeCall(WBPRECALL, config.wbPreCallStub,
-                /*        temps */ null,
-                /*          ret */ ret(Kind.Void),
-                /* arg0: object */ javaCallingConvention(Kind.Object));
-
-       addRuntimeCall(WBPOSTCALL, config.wbPostCallStub,
-                /*        temps */ null,
-                /*          ret */ ret(Kind.Void),
-                /* arg0: object */ javaCallingConvention(Kind.Object, word));
-
-        addRuntimeCall(MONITOREXIT, config.monitorExitStub,
-                /*        temps */ null,
-                /*          ret */ ret(Kind.Void),
-                /* arg0: object */ javaCallingConvention(Kind.Object,
-                /* arg1:   lock */                       word));
 
-        addStubCall(NEW_ARRAY,
-                /*          ret */ rax.asValue(Kind.Object),
-                /* arg0:    hub */ rdx.asValue(word),
-                /* arg1: length */ rbx.asValue(Kind.Int));
-
-        addRuntimeCall(NEW_ARRAY_SLOW, config.newArrayStub,
-                /*        temps */ null,
-                /*          ret */ rax.asValue(Kind.Object),
-                /* arg0:    hub */ rdx.asValue(word),
-                /* arg1: length */ rbx.asValue(Kind.Int));
-
-        addStubCall(NEW_INSTANCE,
-                /*          ret */ rax.asValue(Kind.Object),
-                /* arg0:    hub */ rdx.asValue(word));
-
-        addRuntimeCall(NEW_INSTANCE_SLOW, config.newInstanceStub,
-                /*        temps */ null,
-                /*          ret */ rax.asValue(Kind.Object),
-                /* arg0:    hub */ rdx.asValue(word));
+        // The calling convention for the exception handler stub is (only?) defined in
+        // TemplateInterpreterGenerator::generate_throw_exception()
+        // in templateInterpreter_x86_64.cpp around line 1923 
+        addStubCall(EXCEPTION_HANDLER,
+                /*            ret */ ret(Kind.Void),
+               /* arg0: exception */ rax.asValue(Kind.Object),
+             /* arg1: exceptionPc */ rdx.asValue(word));
 
-        addRuntimeCall(NEW_MULTI_ARRAY, config.newMultiArrayStub,
-                /*        temps */ null,
-                /*          ret */ rax.asValue(Kind.Object),
-                /* arg0:    hub */ rax.asValue(word),
-                /* arg1:   rank */ rbx.asValue(Kind.Int),
-                /* arg2:   dims */ rcx.asValue(word));
-
-        addRuntimeCall(VERIFY_OOP, config.verifyOopStub,
-                /*        temps */ null,
-                /*          ret */ ret(Kind.Void),
-                /* arg0: object */ r13.asValue(Kind.Object));
-
-        addRuntimeCall(VM_ERROR, config.vmErrorStub,
-                /*        temps */ null,
-                /*          ret */ ret(Kind.Void),
-                /* arg0:  where */ javaCallingConvention(Kind.Object,
-                /* arg1: format */                       Kind.Object,
-                /* arg2:  value */                       Kind.Long));
-
-        addRuntimeCall(IDENTITY_HASHCODE, config.identityHashCodeStub,
-                /*        temps */ null,
-                /*          ret */ rax.asValue(Kind.Int),
-                /* arg0:    obj */ javaCallingConvention(Kind.Object));
-
-        addRuntimeCall(THREAD_IS_INTERRUPTED, config.threadIsInterruptedStub,
-                /*        temps */ null,
-                /*          ret */ rax.asValue(Kind.Boolean),
-                /* arg0: thread */ javaCallingConvention(Kind.Object,
-      /* arg1: clearInterrupted */                       Kind.Boolean));
+        addJump(EXCEPTION_HANDLER_IN_CALLER,
+                /* arg0: exception */ rax.asValue(Kind.Object),
+               /* arg1: exceptionPc */ rdx.asValue(word));
 
         addRuntimeCall(ENCRYPT_BLOCK, config.aescryptEncryptBlockStub,
                 /*        temps */ null,
@@ -186,18 +90,6 @@
                 /* arg2:    key */                         word,
                 /* arg3:      r */                         word,
               /* arg4: inLength */                         Kind.Int));
-
-        addRuntimeCall(AMD64HotSpotBackend.EXCEPTION_HANDLER, config.handleExceptionStub,
-                /*        temps */ null,
-                /*          ret */ ret(Kind.Void));
-
-        addRuntimeCall(AMD64HotSpotBackend.DEOPT_HANDLER, config.handleDeoptStub,
-                /*        temps */ null,
-                /*          ret */ ret(Kind.Void));
-
-        addRuntimeCall(AMD64HotSpotBackend.IC_MISS_HANDLER, config.inlineCacheMissStub,
-                /*        temps */ null,
-                /*          ret */ ret(Kind.Void));
         // @formatter:on
 
     }
@@ -231,6 +123,6 @@
 
     @Override
     protected RegisterConfig createRegisterConfig(boolean globalStubConfig) {
-        return new AMD64HotSpotRegisterConfig(config, globalStubConfig);
+        return new AMD64HotSpotRegisterConfig(graalRuntime.getTarget().arch, config, globalStubConfig);
     }
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotUnwindOp.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotUnwindOp.java	Mon May 13 17:11:31 2013 +0200
@@ -24,53 +24,42 @@
 
 import static com.oracle.graal.amd64.AMD64.*;
 import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.hotspot.HotSpotBackend.*;
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 
-import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.lir.LIRInstruction.Opcode;
 import com.oracle.graal.lir.amd64.*;
 import com.oracle.graal.lir.asm.*;
 
 /**
- * Performs an unwind to throw an exception.
+ * Removes the current frame and jumps to the {@link UnwindExceptionToCallerStub}.
  */
 @Opcode("UNWIND")
 final class AMD64HotSpotUnwindOp extends AMD64HotSpotEpilogueOp {
 
-    public static final Descriptor UNWIND_EXCEPTION = new Descriptor("unwindException", true, void.class, Object.class);
+    @Use({REG}) protected RegisterValue exception;
 
-    /**
-     * Unwind stub expects the exception in RAX.
-     */
-    public static final Register EXCEPTION = AMD64.rax;
-
-    @Use({REG}) protected AllocatableValue exception;
-
-    AMD64HotSpotUnwindOp(AllocatableValue exception) {
+    AMD64HotSpotUnwindOp(RegisterValue exception) {
         this.exception = exception;
-        assert asRegister(exception) == EXCEPTION;
     }
 
     @Override
     public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
-        // Copy the saved RBP value into the slot just below the return address
-        // so that the stub can pick it up from there.
-        AMD64Address rbpSlot;
-        int rbpSlotOffset = tasm.frameMap.frameSize() - 8;
-        if (isStackSlot(savedRbp)) {
-            rbpSlot = (AMD64Address) tasm.asAddress(savedRbp);
-            assert rbpSlot.getDisplacement() == rbpSlotOffset;
-        } else {
-            rbpSlot = new AMD64Address(rsp, rbpSlotOffset);
-            masm.movq(rbpSlot, asRegister(savedRbp));
-        }
+        leaveFrameAndRestoreRbp(tasm, masm);
 
-        // Pass the address of the RBP slot in RBP itself
-        masm.leaq(rbp, rbpSlot);
-        AMD64Call.directCall(tasm, masm, tasm.runtime.lookupRuntimeCall(UNWIND_EXCEPTION), AMD64.r10, false, null);
+        RuntimeCallTarget stub = tasm.runtime.lookupRuntimeCall(UNWIND_EXCEPTION_TO_CALLER);
+        CallingConvention cc = stub.getCallingConvention();
+        assert cc.getArgumentCount() == 2;
+        assert exception.equals(cc.getArgument(0));
+
+        // Get return address (is on top of stack after leave).
+        Register returnAddress = asRegister(cc.getArgument(1));
+        masm.movq(returnAddress, new AMD64Address(rsp, 0));
+
+        AMD64Call.directJmp(tasm, masm, tasm.runtime.lookupRuntimeCall(HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER));
     }
 }
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java	Mon May 13 17:11:31 2013 +0200
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.*;
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.sparc.*;
 import com.oracle.graal.hotspot.*;
@@ -42,8 +43,14 @@
     }
 
     @Override
-    public LIRGenerator newLIRGenerator(StructuredGraph graph, FrameMap frameMap, ResolvedJavaMethod method, LIR lir) {
-        return new SPARCLIRGenerator(graph, this.runtime(), this.target, frameMap, method, lir);
+    public LIRGenerator newLIRGenerator(StructuredGraph graph, FrameMap frameMap, CallingConvention cc, LIR lir) {
+        return new SPARCLIRGenerator(graph, this.runtime(), this.target, frameMap, cc, lir);
+    }
+
+    @Override
+    protected AbstractAssembler createAssembler(FrameMap frameMap) {
+        // SPARC: Create assembler.
+        return null;
     }
 
     @Override
@@ -53,7 +60,7 @@
     }
 
     @Override
-    public void emitCode(TargetMethodAssembler tasm, ResolvedJavaMethod method, LIRGenerator lirGen) {
+    public void emitCode(TargetMethodAssembler tasm, LIRGenerator lirGen, ResolvedJavaMethod codeCacheOwner) {
         // SPARC: Emit code
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Mon May 13 17:11:31 2013 +0200
@@ -22,12 +22,14 @@
  */
 package com.oracle.graal.hotspot;
 
+import static com.oracle.graal.api.code.CodeUtil.*;
 import static com.oracle.graal.nodes.StructuredGraph.*;
 
 import java.lang.reflect.Modifier;
 import java.util.concurrent.*;
 
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.code.CallingConvention.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.*;
 import com.oracle.graal.debug.*;
@@ -157,8 +159,10 @@
                             graph = graph.copy();
                         }
                         InliningUtil.InlinedBytecodes.add(method.getCodeSize());
-                        return GraalCompiler.compileMethod(graalRuntime.getRuntime(), replacements, graalRuntime.getBackend(), graalRuntime.getTarget(), method, graph, graalRuntime.getCache(), plan,
-                                        optimisticOpts, method.getSpeculationLog());
+                        HotSpotRuntime runtime = graalRuntime.getRuntime();
+                        CallingConvention cc = getCallingConvention(runtime, Type.JavaCallee, graph.method(), false);
+                        return GraalCompiler.compileGraph(graph, cc, method, runtime, replacements, graalRuntime.getBackend(), graalRuntime.getTarget(), graalRuntime.getCache(), plan, optimisticOpts,
+                                        method.getSpeculationLog());
                     }
                 });
             } finally {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java	Mon May 13 17:11:31 2013 +0200
@@ -22,15 +22,52 @@
  */
 package com.oracle.graal.hotspot;
 
+import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.compiler.target.*;
+import com.oracle.graal.hotspot.bridge.*;
 import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.stubs.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.word.*;
 
 /**
  * HotSpot specific backend.
  */
 public abstract class HotSpotBackend extends Backend {
 
+    /**
+     * Descriptor for SharedRuntime::deopt_blob()->uncommon_trap().
+     */
+    public static final Descriptor UNCOMMON_TRAP = new Descriptor("deoptimize", true, void.class);
+
+    /**
+     * Descriptor for {@link ExceptionHandlerStub}. This stub is called by the
+     * {@linkplain Marks#MARK_EXCEPTION_HANDLER_ENTRY exception handler} in a compiled method.
+     */
+    public static final Descriptor EXCEPTION_HANDLER = new Descriptor("exceptionHandler", true, void.class, Object.class, Word.class);
+
+    /**
+     * Descriptor for SharedRuntime::deopt_blob()->unpack().
+     */
+    public static final Descriptor DEOPT_HANDLER = new Descriptor("deoptHandler", true, void.class);
+
+    /**
+     * Descriptor for SharedRuntime::get_ic_miss_stub().
+     */
+    public static final Descriptor IC_MISS_HANDLER = new Descriptor("icMissHandler", true, void.class);
+
+    /**
+     * Descriptor for {@link UnwindExceptionToCallerStub}. This stub is called by code generated
+     * from {@link UnwindNode}.
+     */
+    public static final Descriptor UNWIND_EXCEPTION_TO_CALLER = new Descriptor("unwindExceptionToCaller", true, void.class, Object.class, Word.class);
+
+    /**
+     * Descriptor for the arguments when unwinding to an exception handler in a caller.
+     */
+    public static final Descriptor EXCEPTION_HANDLER_IN_CALLER = new Descriptor("exceptionHandlerInCaller", false, void.class, Object.class, Word.class);
+
     public HotSpotBackend(HotSpotRuntime runtime, TargetDescription target) {
         super(runtime, target);
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompilationResult.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompilationResult.java	Mon May 13 17:11:31 2013 +0200
@@ -22,11 +22,20 @@
  */
 package com.oracle.graal.hotspot;
 
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+
 import java.util.*;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.CompilationResult.*;
+import com.oracle.graal.api.code.CompilationResult.Call;
+import com.oracle.graal.api.code.CompilationResult.DataPatch;
+import com.oracle.graal.api.code.CompilationResult.ExceptionHandler;
+import com.oracle.graal.api.code.CompilationResult.Infopoint;
+import com.oracle.graal.api.code.CompilationResult.Mark;
+import com.oracle.graal.api.code.CompilationResult.Site;
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.stubs.*;
 
 /**
  * Augments a {@link CompilationResult} with HotSpot-specific information.
@@ -35,27 +44,66 @@
 
     private static final long serialVersionUID = 7807321392203253218L;
     public final CompilationResult comp;
-    public final HotSpotResolvedJavaMethod method; // used only for methods
-    public final int entryBCI; // used only for methods
-    public final String name; // used only for stubs
+
+    /**
+     * Non-null for installation of an nmethod.
+     */
+    public final HotSpotResolvedJavaMethod method;
+    public final int entryBCI;
+
+    /**
+     * Non-null for installation of a RuntimeStub.
+     */
+    public final String stubName;
 
     public final Site[] sites;
     public final ExceptionHandler[] exceptionHandlers;
 
     public HotSpotCompilationResult(HotSpotResolvedJavaMethod method, int entryBCI, CompilationResult comp) {
         this.method = method;
+        this.stubName = null;
         this.comp = comp;
         this.entryBCI = entryBCI;
-        this.name = null;
 
         sites = getSortedSites(comp);
-        if (comp.getExceptionHandlers() == null) {
+        if (comp.getExceptionHandlers().isEmpty()) {
             exceptionHandlers = null;
         } else {
             exceptionHandlers = comp.getExceptionHandlers().toArray(new ExceptionHandler[comp.getExceptionHandlers().size()]);
         }
     }
 
+    public HotSpotCompilationResult(Stub stub, CompilationResult comp) {
+        assert checkStubInvariants(comp);
+        this.method = null;
+        this.stubName = stub.toString();
+        this.comp = comp;
+        this.entryBCI = 0;
+
+        sites = getSortedSites(comp);
+        assert comp.getExceptionHandlers().isEmpty();
+        exceptionHandlers = null;
+    }
+
+    /**
+     * Checks the conditions a compilation must satisfy to be installed as a RuntimeStub.
+     */
+    private boolean checkStubInvariants(CompilationResult compResult) {
+        for (DataPatch data : compResult.getDataReferences()) {
+            Constant constant = data.constant;
+            assert constant.getKind() != Kind.Object : this + " cannot have embedded object constant: " + constant;
+            assert constant.getPrimitiveAnnotation() == null : this + " cannot have embedded metadata: " + constant;
+        }
+        for (Infopoint infopoint : compResult.getInfopoints()) {
+            assert infopoint instanceof Call : this + " cannot have non-call infopoint: " + infopoint;
+            Call call = (Call) infopoint;
+            assert call.target instanceof HotSpotRuntimeCallTarget : this + " cannot have non runtime call: " + call.target;
+            HotSpotRuntimeCallTarget callTarget = (HotSpotRuntimeCallTarget) call.target;
+            assert callTarget.getAddress() == graalRuntime().getConfig().uncommonTrapStub || callTarget.isCRuntimeCall() : this + "must only call C runtime or deoptimization stub, not " + call.target;
+        }
+        return true;
+    }
+
     static class SiteComparator implements Comparator<Site> {
 
         public int compare(Site s1, Site s2) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java	Mon May 13 17:11:31 2013 +0200
@@ -84,6 +84,15 @@
         runtime.compilerToVm = toVM;
     }
 
+    protected static HotSpotGraalRuntimeFactory findFactory(String architecture) {
+        for (HotSpotGraalRuntimeFactory factory : ServiceLoader.loadInstalled(HotSpotGraalRuntimeFactory.class)) {
+            if (factory.getArchitecture().equals(architecture) && factory.getName().equals(GraalOptions.GraalRuntime)) {
+                return factory;
+            }
+        }
+        return null;
+    }
+
     private static Kind wordKind;
 
     /**
@@ -114,8 +123,9 @@
         return unsafe.getInt(object, offset);
     }
 
-    protected/* final */CompilerToVM compilerToVm;
-    protected/* final */VMToCompiler vmToCompiler;
+    protected/* final */CompilerToVM  compilerToVm;
+    protected/* final */CompilerToGPU compilerToGpu;
+    protected/* final */VMToCompiler  vmToCompiler;
 
     protected final HotSpotRuntime runtime;
     protected final TargetDescription target;
@@ -128,12 +138,14 @@
     private final HotSpotBackend backend;
 
     protected HotSpotGraalRuntime() {
-        CompilerToVM toVM = new CompilerToVMImpl();
+        CompilerToVM  toVM  = new CompilerToVMImpl();
+        CompilerToGPU toGPU = new CompilerToGPUImpl();
 
         // initialize VmToCompiler
         VMToCompiler toCompiler = new VMToCompilerImpl(this);
 
-        compilerToVm = toVM;
+        compilerToVm  = toVM;
+        compilerToGpu = toGPU;
         vmToCompiler = toCompiler;
         config = new HotSpotVMConfig();
         compilerToVm.initializeConfiguration(config);
@@ -215,6 +227,10 @@
         return vmToCompiler;
     }
 
+    public CompilerToGPU getCompilerToGPU() {
+        return compilerToGpu;
+    }
+
     public JavaType lookupType(String name, HotSpotResolvedObjectType accessingClass, boolean eagerResolve) {
         if (name.length() == 1 && vmToCompiler instanceof VMToCompilerImpl) {
             VMToCompilerImpl impl = (VMToCompilerImpl) vmToCompiler;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntimeFactory.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2011, 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.hotspot;
+
+public interface HotSpotGraalRuntimeFactory {
+
+    HotSpotGraalRuntime createRuntime();
+
+    String getArchitecture();
+
+    String getName();
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRGenerator.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRGenerator.java	Mon May 13 17:11:31 2013 +0200
@@ -26,6 +26,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 
 /**
@@ -42,6 +43,12 @@
      */
     void emitTailcall(Value[] args, Value address);
 
+    void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason);
+
+    void emitPatchReturnAddress(ValueNode address);
+
+    void emitJumpToExceptionHandlerInCaller(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc);
+
     void visitDirectCompareAndSwap(DirectCompareAndSwapNode x);
 
     /**
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotRuntimeCallTarget.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotRuntimeCallTarget.java	Mon May 13 17:11:31 2013 +0200
@@ -36,6 +36,11 @@
 public class HotSpotRuntimeCallTarget implements RuntimeCallTarget, InvokeTarget {
 
     /**
+     * Sentinel marker for a computed jump address.
+     */
+    public static final long JUMP_ADDRESS = 0xDEADDEADBEEFBEEFL;
+
+    /**
      * The descriptor of the stub. This is for informational purposes only.
      */
     public final Descriptor descriptor;
@@ -46,7 +51,7 @@
     private long address;
 
     /**
-     * Non-null (eventually) iff this is a call to a snippet-based {@linkplain Stub stub}.
+     * Non-null (eventually) iff this is a call to a compiled {@linkplain Stub stub}.
      */
     private Stub stub;
 
@@ -57,8 +62,11 @@
 
     private final CompilerToVM vm;
 
-    public HotSpotRuntimeCallTarget(Descriptor descriptor, long address, CallingConvention cc, CompilerToVM vm) {
+    private final boolean isCRuntimeCall;
+
+    public HotSpotRuntimeCallTarget(Descriptor descriptor, long address, boolean isCRuntimeCall, CallingConvention cc, CompilerToVM vm) {
         this.address = address;
+        this.isCRuntimeCall = isCRuntimeCall;
         this.descriptor = descriptor;
         this.cc = cc;
         this.vm = vm;
@@ -66,7 +74,7 @@
 
     @Override
     public String toString() {
-        return (stub == null ? descriptor.toString() : MetaUtil.format("%h.%n", stub.getMethod())) + "@0x" + Long.toHexString(address) + ":" + cc;
+        return (stub == null ? descriptor.toString() : stub) + "@0x" + Long.toHexString(address) + ":" + cc;
     }
 
     public CallingConvention getCallingConvention() {
@@ -88,7 +96,7 @@
 
     public void finalizeAddress(Backend backend) {
         if (address == 0) {
-            assert stub != null : "linkage without an address must be a stub";
+            assert stub != null : "linkage without an address must be a stub - forgot to register a Stub associated with " + descriptor + "?";
             InstalledCode code = stub.getCode(backend);
 
             AllocatableValue[] argumentLocations = new AllocatableValue[cc.getArgumentCount()];
@@ -96,10 +104,10 @@
                 argumentLocations[i] = cc.getArgument(i);
             }
 
-            Set<Register> definedRegisters = stub.getDefinedRegisters();
-            AllocatableValue[] temporaryLocations = new AllocatableValue[definedRegisters.size()];
+            Set<Register> destroyedRegisters = stub.getDestroyedRegisters();
+            AllocatableValue[] temporaryLocations = new AllocatableValue[destroyedRegisters.size()];
             int i = 0;
-            for (Register reg : definedRegisters) {
+            for (Register reg : destroyedRegisters) {
                 temporaryLocations[i++] = reg.asValue();
             }
             // Update calling convention with temporaries
@@ -108,9 +116,30 @@
         }
     }
 
+    public long getAddress() {
+        assert address != 0L : "address not yet finalized: " + this;
+        return address;
+    }
+
     @Override
-    public boolean preservesRegisters() {
-        assert address != 0;
-        return true;
+    public boolean destroysRegisters() {
+        if (isCRuntimeCall) {
+            // Even though most native ABIs define some callee saved registers,
+            // for simplicity we force the register allocator to save all live
+            // registers across a C runtime call as such calls are only made from
+            // compiled stubs which a) are slow path and b) will typically only
+            // have very few live registers across a C runtime call
+            return true;
+        }
+        // This is a call to a compiled (or assembler) stub which saves
+        // all registers (apart from its temporaries)
+        return false;
+    }
+
+    /**
+     * Determines if this is a link to a C/C++ function in the HotSpot runtime.
+     */
+    public boolean isCRuntimeCall() {
+        return isCRuntimeCall;
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Mon May 13 17:11:31 2013 +0200
@@ -33,7 +33,8 @@
     }
 
     // os information, register layout, code generation, ...
-    public boolean windowsOs;
+    public boolean cAssertions;
+    public final boolean windowsOs = System.getProperty("os.name", "").startsWith("Windows");
     public int codeEntryAlignment;
     public boolean verifyOops;
     public boolean ciTime;
@@ -136,6 +137,9 @@
      */
     public int threadTlabEndOffset;
 
+    /**
+     * The value of JavaThread::threadObj_offset().
+     */
     public int threadObjectOffset;
 
     /**
@@ -179,6 +183,14 @@
     public int uninitializedIdentityHashCodeValue;
 
     /**
+     * Offset of the _pending_exception field in ThreadShadow (defined in exceptions.hpp). This
+     * field is used to propagate exceptions through C/C++ calls.
+     * <p>
+     * <b>NOTE: This is not the same as {@link #threadExceptionOopOffset}.</b>
+     */
+    public int pendingExceptionOffset;
+
+    /**
      * Offset of the pending deoptimization field.
      */
     public int pendingDeoptimizationOffset;
@@ -223,7 +235,24 @@
      */
     public int klassHasFinalizerFlag;
 
+    /**
+     * The value of JavaThread::is_method_handle_return_offset().
+     */
+    public int threadIsMethodHandleReturnOffset;
+
+    public long verifyOopCounterAddress;
+    public long verifyOopMask;
+    public long verifyOopBits;
+
+    /**
+     * Offset of the _exception_oop field in Thread (defined in thread.hpp). This field is used to
+     * pass exception objects into and out of the runtime system during exception handling for
+     * compiled code.
+     * <p>
+     * <b>NOTE: This is not the same as {@link #pendingExceptionOffset}.</b>
+     */
     public int threadExceptionOopOffset;
+
     public int threadExceptionPcOffset;
     public long cardtableStartAddress;
     public int cardtableShift;
@@ -302,6 +331,10 @@
     public int threadTlabStartOffset;
     public int threadTlabSizeOffset;
     public int threadAllocatedBytesOffset;
+    public int threadLastJavaSpOffset;
+    public int threadLastJavaFpOffset;
+    public int threadLastJavaPcOffset;
+    public int threadObjectResultOffset;
     public int tlabRefillWasteLimitOffset;
     public int tlabRefillWasteIncrement;
     public int tlabAlignmentReserve;
@@ -334,44 +367,43 @@
     public int typeProfileWidth;
 
     // runtime stubs
-    public long newInstanceStub;
-    public long newArrayStub;
-    public long newMultiArrayStub;
     public long inlineCacheMissStub;
-    public long handleExceptionStub;
     public long handleDeoptStub;
-    public long monitorEnterStub;
-    public long monitorExitStub;
-    public long wbPreCallStub;
-    public long wbPostCallStub;
 
-    public long verifyOopStub;
-    public long vmErrorStub;
-    public long deoptimizeStub;
+    public long uncommonTrapStub;
     public long unwindExceptionStub;
-    public long osrMigrationEndStub;
-    public long registerFinalizerStub;
-    public long createNullPointerExceptionStub;
-    public long createOutOfBoundsExceptionStub;
     public long javaTimeMillisStub;
     public long javaTimeNanosStub;
-    public long arithmeticFremStub;
-    public long arithmeticDremStub;
     public long arithmeticSinStub;
     public long arithmeticCosStub;
     public long arithmeticTanStub;
-    public long logPrimitiveStub;
-    public long logObjectStub;
-    public long logPrintfStub;
-    public long stubPrintfStub;
     public int deoptReasonNone;
-    public long threadIsInterruptedStub;
-    public long identityHashCodeStub;
     public long aescryptEncryptBlockStub;
     public long aescryptDecryptBlockStub;
     public long cipherBlockChainingEncryptAESCryptStub;
     public long cipherBlockChainingDecryptAESCryptStub;
 
+    public long newInstanceAddress;
+    public long newArrayAddress;
+    public long newMultiArrayAddress;
+    public long registerFinalizerAddress;
+    public long threadIsInterruptedAddress;
+    public long vmMessageAddress;
+    public long identityHashCodeAddress;
+    public long exceptionHandlerForPcAddress;
+    public long exceptionHandlerForReturnAddressAddress;
+    public long osrMigrationEndAddress;
+    public long monitorenterAddress;
+    public long monitorexitAddress;
+    public long createNullPointerExceptionAddress;
+    public long createOutOfBoundsExceptionAddress;
+    public long logPrimitiveAddress;
+    public long logObjectAddress;
+    public long logPrintfAddress;
+    public long vmErrorAddress;
+    public long writeBarrierPreAddress;
+    public long writeBarrierPostAddress;
+
     public int deoptReasonNullCheck;
     public int deoptReasonRangeCheck;
     public int deoptReasonClassCheck;
@@ -384,6 +416,7 @@
     public int deoptReasonJsrMismatch;
     public int deoptReasonDiv0Check;
     public int deoptReasonConstraint;
+    public int deoptReasonLoopLimitCheck;
 
     public int deoptActionNone;
     public int deoptActionMaybeRecompile;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToGPU.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,55 @@
+/*
+ * 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.hotspot.bridge;
+
+import com.oracle.graal.api.code.InvalidInstalledCodeException;
+
+/**
+ * Calls from Java into the GPU.
+ */
+public interface CompilerToGPU {
+
+    /**
+     * Attempts to initialize and create a valid context with the GPU.
+     * 
+     * @return whether the GPU context has been initialized and is valid.
+     */
+    boolean deviceInit();
+
+    /**
+     * Attempts to detach from a valid GPU context.
+     * 
+     * @return whether the GPU context has been properly disposed.
+     */
+    boolean deviceDetach();
+
+    /**
+     * Attempts to generate and return a bound function to the
+     * loaded method kernel on the GPU.
+     * 
+     * @param code the text or binary values for a method kernel
+     * @return the value of the bound kernel in GPU space.
+     */
+    long generateKernel(byte[] code, String name) throws InvalidInstalledCodeException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToGPUImpl.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.hotspot.bridge;
+
+import com.oracle.graal.api.code.InvalidInstalledCodeException;
+
+
+/**
+ * Entries into the HotSpot GPU interface from Java code.
+ */
+public class CompilerToGPUImpl implements CompilerToGPU {
+
+    public native boolean deviceInit();
+
+    public native long generateKernel(byte[] code, String name) throws InvalidInstalledCodeException;
+
+    public native boolean deviceDetach();
+
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java	Mon May 13 17:11:31 2013 +0200
@@ -151,8 +151,7 @@
      * Installs the result of a compilation into the code cache.
      * 
      * @param compResult the result of a compilation
-     * @param code if not null, then the code is installed as the non-default compiled code for the
-     *            associated method and the details of the installation are written to this object
+     * @param code the details of the installed CodeBlob are written to this object
      * @return the outcome of the installation as a {@link CodeInstallResult}.
      */
     CodeInstallResult installCode(HotSpotCompilationResult compResult, HotSpotInstalledCode code, SpeculationLog cache);
@@ -192,25 +191,27 @@
 
     HotSpotResolvedJavaField getJavaField(Field reflectionField);
 
-    long getMaxCallTargetOffset(long stub);
+    long getMaxCallTargetOffset(long address);
 
-    String disassembleNMethod(long nmethod);
+    String disassembleCodeBlob(long codeBlob);
 
     /**
-     * Gets a copy of the machine code for an nmethod.
+     * Gets a copy of the machine code for a CodeBlob.
      * 
-     * @return the machine code for {@code nmethod} if it is valid, null otherwise
+     * @return the machine code for {@code codeBlob} if it is valid, null otherwise
      */
-    byte[] getCode(long nmethod);
+    byte[] getCode(long codeBlob);
 
     StackTraceElement getStackTraceElement(long metaspaceMethod, int bci);
 
-    Object executeCompiledMethod(Object arg1, Object arg2, Object arg3, long nativeMethod) throws InvalidInstalledCodeException;
+    Object executeCompiledMethod(Object arg1, Object arg2, Object arg3, long nmethod) throws InvalidInstalledCodeException;
 
-    Object executeCompiledMethodVarargs(Object[] args, long nativeMethod) throws InvalidInstalledCodeException;
+    Object executeCompiledMethodVarargs(Object[] args, long nmethod) throws InvalidInstalledCodeException;
 
     int getVtableEntryOffset(long metaspaceMethod);
 
+    boolean hasVtableEntry(long metaspaceMethod);
+
     long[] getDeoptedLeafGraphIds();
 
     long[] getLineNumberTable(HotSpotResolvedJavaMethod method);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java	Mon May 13 17:11:31 2013 +0200
@@ -127,24 +127,27 @@
     public native int getCompiledCodeSize(long metaspaceMethod);
 
     @Override
-    public native long getMaxCallTargetOffset(long stub);
+    public native long getMaxCallTargetOffset(long address);
 
     @Override
-    public native String disassembleNMethod(long nmethod);
+    public native String disassembleCodeBlob(long codeBlob);
 
     @Override
-    public native byte[] getCode(long nmethod);
+    public native byte[] getCode(long codeBlob);
 
     @Override
     public native StackTraceElement getStackTraceElement(long metaspaceMethod, int bci);
 
     @Override
-    public native Object executeCompiledMethodVarargs(Object[] args, long nativeMethod);
+    public native Object executeCompiledMethodVarargs(Object[] args, long nmethod);
 
     @Override
     public native int getVtableEntryOffset(long metaspaceMethod);
 
     @Override
+    public native boolean hasVtableEntry(long metaspaceMethod);
+
+    @Override
     public native long[] getDeoptedLeafGraphIds();
 
     @Override
@@ -172,16 +175,16 @@
     public native boolean isInstalledCodeValid(long nativeMethod);
 
     @Override
-    public Object executeCompiledMethod(Object arg1, Object arg2, Object arg3, long nativeMethod) throws InvalidInstalledCodeException {
-        return executeCompiledMethodIntrinsic(arg1, arg2, arg3, nativeMethod);
+    public Object executeCompiledMethod(Object arg1, Object arg2, Object arg3, long nmethod) throws InvalidInstalledCodeException {
+        return executeCompiledMethodIntrinsic(arg1, arg2, arg3, nmethod);
     }
 
     /**
-     * Direct call to the given nativeMethod 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
+     * 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
      * interpreter and from compiled code) are directly pointing to a manually generated assembly
      * stub that does the necessary argument shuffling and a tail call via an indirect jump to the
      * verified entry point of the given native method.
      */
-    private static native Object executeCompiledMethodIntrinsic(Object arg1, Object arg2, Object arg3, long nativeMethod);
+    private static native Object executeCompiledMethodIntrinsic(Object arg1, Object arg2, Object arg3, long nmethod);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInstalledCode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInstalledCode.java	Mon May 13 17:11:31 2013 +0200
@@ -30,34 +30,49 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.stubs.*;
 
 /**
- * Implementation of {@link InstalledCode} for HotSpot. Stores a reference to the nmethod which
- * contains the compiled code. The nmethod also stores a weak reference to the HotSpotCompiledMethod
- * instance which is necessary to keep the nmethod from being unloaded.
+ * Implementation of {@link InstalledCode} for HotSpot. If the code is installed as an nmethod (as
+ * opposed to some other subclass of CodeBlob such as RuntimeStub), then the nmethod stores a weak
+ * reference to an instance of this class. This is necessary to keep the nmethod from being unloaded
+ * while the associated {@link HotSpotInstalledCode} instance is alive.
+ * <p>
+ * Note that there is no (current) way for the reference from an nmethod to a
+ * {@link HotSpotInstalledCode} instance to be anything but weak. This is due to the fact that
+ * HotSpot does not treat nmethods as strong GC roots.
  */
 public class HotSpotInstalledCode extends CompilerObject implements InstalledCode {
 
     private static final long serialVersionUID = 156632908220561612L;
 
     private final HotSpotResolvedJavaMethod method;
+    private final Stub stub;
     private final boolean isDefault;
     private final Graph graph;
-    long nmethod;
+    long codeBlob;
     long start;
 
     public HotSpotInstalledCode(HotSpotResolvedJavaMethod method, Graph graph, boolean isDefault) {
         this.method = method;
+        this.stub = null;
         this.graph = graph;
         this.isDefault = isDefault;
     }
 
+    public HotSpotInstalledCode(Stub stub) {
+        this.method = null;
+        this.stub = stub;
+        this.graph = null;
+        this.isDefault = false;
+    }
+
     public boolean isDefault() {
         return isDefault;
     }
 
-    public long getMethodAddress() {
-        return nmethod;
+    public long getCodeBlob() {
+        return codeBlob;
     }
 
     public Graph getGraph() {
@@ -71,26 +86,32 @@
 
     @Override
     public boolean isValid() {
-        return graalRuntime().getCompilerToVM().isInstalledCodeValid(nmethod);
+        return stub != null || graalRuntime().getCompilerToVM().isInstalledCodeValid(codeBlob);
     }
 
     @Override
     public void invalidate() {
-        graalRuntime().getCompilerToVM().invalidateInstalledCode(nmethod);
+        if (stub == null) {
+            graalRuntime().getCompilerToVM().invalidateInstalledCode(codeBlob);
+        }
     }
 
     @Override
     public String toString() {
-        return String.format("InstalledCode[method=%s, nmethod=0x%x]", method, nmethod);
+        if (stub != null) {
+            return String.format("InstalledCode[stub=%s, codeBlob=0x%x]", stub, codeBlob);
+        }
+        return String.format("InstalledCode[method=%s, codeBlob=0x%x, isDefault=%b]", method, codeBlob, isDefault);
     }
 
     @Override
     public Object execute(Object arg1, Object arg2, Object arg3) throws InvalidInstalledCodeException {
+        assert stub == null;
         assert method.getSignature().getParameterCount(!Modifier.isStatic(method.getModifiers())) == 3;
         assert method.getSignature().getParameterKind(0) == Kind.Object;
         assert method.getSignature().getParameterKind(1) == Kind.Object;
         assert !Modifier.isStatic(method.getModifiers()) || method.getSignature().getParameterKind(2) == Kind.Object;
-        return graalRuntime().getCompilerToVM().executeCompiledMethod(arg1, arg2, arg3, nmethod);
+        return graalRuntime().getCompilerToVM().executeCompiledMethod(arg1, arg2, arg3, codeBlob);
     }
 
     private boolean checkArgs(Object... args) {
@@ -109,8 +130,9 @@
 
     @Override
     public Object executeVarargs(Object... args) throws InvalidInstalledCodeException {
+        assert stub == null;
         assert checkArgs(args);
-        return graalRuntime().getCompilerToVM().executeCompiledMethodVarargs(args, nmethod);
+        return graalRuntime().getCompilerToVM().executeCompiledMethodVarargs(args, codeBlob);
     }
 
     @Override
@@ -120,6 +142,6 @@
 
     @Override
     public byte[] getCode() {
-        return graalRuntime().getCompilerToVM().getCode(nmethod);
+        return graalRuntime().getCompilerToVM().getCode(codeBlob);
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMonitorValue.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMonitorValue.java	Mon May 13 17:11:31 2013 +0200
@@ -63,4 +63,23 @@
     public String toString() {
         return "monitor[" + owner + (slot != null ? ", " + slot : "") + (eliminated ? ", eliminated" : "") + "]";
     }
+
+    @Override
+    public int hashCode() {
+        final int prime = 43;
+        int result = super.hashCode();
+        result = prime * result + (eliminated ? 1231 : 1237);
+        result = prime * result + owner.hashCode();
+        result = prime * result + slot.hashCode();
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof HotSpotMonitorValue) {
+            HotSpotMonitorValue other = (HotSpotMonitorValue) obj;
+            return super.equals(obj) && eliminated == other.eliminated && owner.equals(other.owner) && slot.equals(other.slot);
+        }
+        return false;
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField.java	Mon May 13 17:11:31 2013 +0200
@@ -31,13 +31,14 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.hotspot.*;
+import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.replacements.*;
 
 /**
  * Represents a field in a HotSpot type.
  */
-public class HotSpotResolvedJavaField extends CompilerObject implements ResolvedJavaField {
+public class HotSpotResolvedJavaField extends CompilerObject implements ResolvedJavaField, LocationIdentity {
 
     // Must not conflict with any fields flags used by the VM - the assertion in the constructor
     // checks this assumption
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java	Mon May 13 17:11:31 2013 +0200
@@ -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.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.debug.*;
 import com.oracle.graal.phases.*;
@@ -53,6 +54,10 @@
     private final HotSpotResolvedObjectType holder;
     private/* final */int codeSize;
     private/* final */int exceptionHandlerCount;
+    private boolean callerSensitive;
+    private boolean forceInline;
+    private boolean dontInline;
+    private boolean ignoredBySecurityStackWalk;
     private HotSpotSignature signature;
     private Boolean hasBalancedMonitors;
     private Map<Object, Object> compilerStorage;
@@ -84,6 +89,11 @@
     }
 
     @Override
+    public Constant getEncoding() {
+        return getMetaspaceMethodConstant();
+    }
+
+    @Override
     public int getModifiers() {
         HotSpotVMConfig config = graalRuntime().getConfig();
         return unsafe.getInt(metaspaceMethod + config.methodAccessFlagsOffset) & Modifier.methodModifiers();
@@ -124,6 +134,43 @@
         return graalRuntime().getCompilerToVM().initializeExceptionHandlers(metaspaceMethod, handlers);
     }
 
+    /**
+     * Returns true if this method has a CallerSensitive annotation.
+     * 
+     * @return true if CallerSensitive annotation present, false otherwise
+     */
+    public boolean isCallerSensitive() {
+        return callerSensitive;
+    }
+
+    /**
+     * Returns true if this method has a ForceInline annotation.
+     * 
+     * @return true if ForceInline annotation present, false otherwise
+     */
+    public boolean isForceInline() {
+        return forceInline;
+    }
+
+    /**
+     * Returns true if this method has a DontInline annotation.
+     * 
+     * @return true if DontInline annotation present, false otherwise
+     */
+    public boolean isDontInline() {
+        return dontInline;
+    }
+
+    /**
+     * Returns true if this method is one of the special methods that is ignored by security stack
+     * walks.
+     * 
+     * @return true if special method ignored by security stack walks, false otherwise
+     */
+    public boolean ignoredBySecurityStackWalk() {
+        return ignoredBySecurityStackWalk;
+    }
+
     public boolean hasBalancedMonitors() {
         if (hasBalancedMonitors == null) {
             hasBalancedMonitors = graalRuntime().getCompilerToVM().hasBalancedMonitors(metaspaceMethod);
@@ -318,18 +365,23 @@
     }
 
     /**
-     * Returns the offset of this method into the v-table. If the holder is not initialized, returns
-     * -1
+     * Returns the offset of this method into the v-table. The method must have a v-table entry has
+     * indicated by {@link #isInVirtualMethodTable()}, otherwise an exception is thrown.
      * 
      * @return the offset of this method into the v-table
      */
     public int vtableEntryOffset() {
-        if (!holder.isInitialized()) {
-            return -1;
+        if (!isInVirtualMethodTable() || !holder.isInitialized()) {
+            throw new GraalInternalError("%s does not have a vtable entry", this);
         }
         return graalRuntime().getCompilerToVM().getVtableEntryOffset(metaspaceMethod);
     }
 
+    @Override
+    public boolean isInVirtualMethodTable() {
+        return graalRuntime().getCompilerToVM().hasVtableEntry(metaspaceMethod);
+    }
+
     public void setCurrentTask(CompilationTask task) {
         currentTask = task;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Mon May 13 17:11:31 2013 +0200
@@ -25,14 +25,42 @@
 import static com.oracle.graal.api.code.CallingConvention.Type.*;
 import static com.oracle.graal.api.code.DeoptimizationAction.*;
 import static com.oracle.graal.api.code.MemoryBarriers.*;
-import static com.oracle.graal.api.code.Register.RegisterFlag.*;
 import static com.oracle.graal.api.meta.DeoptimizationReason.*;
 import static com.oracle.graal.api.meta.Value.*;
 import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.hotspot.HotSpotBackend.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+import static com.oracle.graal.hotspot.nodes.MonitorEnterStubCall.*;
+import static com.oracle.graal.hotspot.nodes.MonitorExitStubCall.*;
 import static com.oracle.graal.hotspot.nodes.NewArrayStubCall.*;
 import static com.oracle.graal.hotspot.nodes.NewInstanceStubCall.*;
+import static com.oracle.graal.hotspot.nodes.NewMultiArrayStubCall.*;
+import static com.oracle.graal.hotspot.nodes.ThreadIsInterruptedStubCall.*;
+import static com.oracle.graal.hotspot.nodes.VMErrorNode.*;
+import static com.oracle.graal.hotspot.nodes.VerifyOopStubCall.*;
+import static com.oracle.graal.hotspot.nodes.WriteBarrierPostStubCall.*;
+import static com.oracle.graal.hotspot.nodes.WriteBarrierPreStubCall.*;
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.IDENTITY_HASHCODE;
 import static com.oracle.graal.hotspot.replacements.SystemSubstitutions.*;
+import static com.oracle.graal.hotspot.stubs.CreateNullPointerExceptionStub.*;
+import static com.oracle.graal.hotspot.stubs.CreateOutOfBoundsExceptionStub.*;
+import static com.oracle.graal.hotspot.stubs.ExceptionHandlerStub.*;
+import static com.oracle.graal.hotspot.stubs.LogObjectStub.*;
+import static com.oracle.graal.hotspot.stubs.LogPrimitiveStub.*;
+import static com.oracle.graal.hotspot.stubs.LogPrintfStub.*;
+import static com.oracle.graal.hotspot.stubs.MonitorEnterStub.*;
+import static com.oracle.graal.hotspot.stubs.MonitorExitStub.*;
+import static com.oracle.graal.hotspot.stubs.NewArrayStub.*;
+import static com.oracle.graal.hotspot.stubs.NewInstanceStub.*;
+import static com.oracle.graal.hotspot.stubs.NewMultiArrayStub.*;
+import static com.oracle.graal.hotspot.stubs.OSRMigrationEndStub.*;
+import static com.oracle.graal.hotspot.stubs.RegisterFinalizerStub.*;
+import static com.oracle.graal.hotspot.stubs.StubUtil.*;
+import static com.oracle.graal.hotspot.stubs.ThreadIsInterruptedStub.*;
+import static com.oracle.graal.hotspot.stubs.UnwindExceptionToCallerStub.*;
+import static com.oracle.graal.hotspot.stubs.VMErrorStub.*;
+import static com.oracle.graal.hotspot.stubs.WriteBarrierPostStub.*;
+import static com.oracle.graal.hotspot.stubs.WriteBarrierPreStub.*;
 import static com.oracle.graal.java.GraphBuilderPhase.RuntimeCalls.*;
 import static com.oracle.graal.nodes.java.RegisterFinalizerNode.*;
 import static com.oracle.graal.replacements.Log.*;
@@ -49,7 +77,6 @@
 import com.oracle.graal.api.code.CompilationResult.DataPatch;
 import com.oracle.graal.api.code.CompilationResult.Infopoint;
 import com.oracle.graal.api.code.CompilationResult.Mark;
-import com.oracle.graal.api.code.Register.RegisterFlag;
 import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
@@ -57,7 +84,6 @@
 import com.oracle.graal.hotspot.bridge.*;
 import com.oracle.graal.hotspot.bridge.CompilerToVM.CodeInstallResult;
 import com.oracle.graal.hotspot.nodes.*;
-import com.oracle.graal.hotspot.phases.*;
 import com.oracle.graal.hotspot.replacements.*;
 import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.java.*;
@@ -69,6 +95,7 @@
 import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.printer.*;
 import com.oracle.graal.replacements.*;
@@ -79,6 +106,8 @@
  */
 public abstract class HotSpotRuntime implements GraalCodeCacheProvider, DisassemblerProvider, BytecodeDisassemblerProvider {
 
+    public static final Descriptor OSR_MIGRATION_END = new Descriptor("OSR_migration_end", true, void.class, long.class);
+
     public final HotSpotVMConfig config;
 
     protected final RegisterConfig regConfig;
@@ -94,14 +123,6 @@
     private LoadExceptionObjectSnippets.Templates exceptionObjectSnippets;
 
     private final Map<Descriptor, HotSpotRuntimeCallTarget> runtimeCalls = new HashMap<>();
-    private final Map<ResolvedJavaMethod, Stub> stubs = new HashMap<>();
-
-    /**
-     * Holds onto objects that will be embedded in compiled code. HotSpot treats oops embedded in
-     * code as weak references so without an external strong root, such an embedded oop will quickly
-     * die. This in turn will cause the nmethod to be unloaded.
-     */
-    private final Map<Object, Object> gcRoots = new HashMap<>();
 
     /**
      * The offset from the origin of an array to the first element.
@@ -185,13 +206,12 @@
         int currentStackOffset = 0;
         for (int i = 0; i < arguments.length; i++) {
             Kind kind = arguments[i];
-            RegisterFlag flag = kind == Kind.Float || kind == Kind.Double ? FPU : CPU;
-            Register[] ccRegs = globalStubRegConfig.getCallingConventionRegisters(type, flag);
+            Register[] ccRegs = globalStubRegConfig.getCallingConventionRegisters(type, kind);
             if (i < ccRegs.length) {
                 result[i] = ccRegs[i].asValue(kind);
             } else {
                 result[i] = StackSlot.get(kind.getStackKind(), currentStackOffset, false);
-                currentStackOffset += Math.max(target.sizeInBytes(kind), target.wordSize);
+                currentStackOffset += Math.max(target.arch.getSizeInBytes(kind), target.wordSize);
             }
         }
         return result;
@@ -202,27 +222,80 @@
         this.graalRuntime = graalRuntime;
         regConfig = createRegisterConfig(false);
         globalStubRegConfig = createRegisterConfig(true);
+        Kind word = graalRuntime.getTarget().wordKind;
 
         // @formatter:off
 
-        addRuntimeCall(OnStackReplacementPhase.OSR_MIGRATION_END, config.osrMigrationEndStub,
-                        /*           temps */ null,
+        addStubCall(VERIFY_OOP,
+                        /*             ret */ ret(Kind.Object),
+                        /* arg0:    object */ javaCallingConvention(Kind.Object));
+
+        addStubCall(OSR_MIGRATION_END,
+                        /*             ret */ ret(Kind.Void),
+                        /* arg0:    buffer */ javaCallingConvention(word));
+
+        addCRuntimeCall(OSR_MIGRATION_END_C, config.osrMigrationEndAddress,
                         /*             ret */ ret(Kind.Void),
-                        /* arg0:      long */ javaCallingConvention(Kind.Long));
+                        /* arg0:    buffer */ nativeCallingConvention(word));
+
+        addRuntimeCall(UNCOMMON_TRAP, config.uncommonTrapStub,
+                        /*           temps */ null,
+                        /*             ret */ ret(Kind.Void));
+
+        addCRuntimeCall(EXCEPTION_HANDLER_FOR_PC, config.exceptionHandlerForPcAddress,
+                        /*             ret */ ret(word),
+                        /* arg0:    thread */ nativeCallingConvention(word));
 
-        addRuntimeCall(REGISTER_FINALIZER, config.registerFinalizerStub,
-                        /*           temps */ null,
+        addStubCall(UNWIND_EXCEPTION_TO_CALLER,
+                        /*             ret */ ret(Kind.Void),
+                        /* arg0: exception */ javaCallingConvention(Kind.Object,
+                    /* arg1: returnAddress */                       word));
+
+        addCRuntimeCall(EXCEPTION_HANDLER_FOR_RETURN_ADDRESS, config.exceptionHandlerForReturnAddressAddress,
+                        /*             ret */ ret(word),
+                        /* arg0:    thread */ nativeCallingConvention(word,
+                    /* arg1: returnAddress */                         word));
+        addStubCall(REGISTER_FINALIZER,
                         /*             ret */ ret(Kind.Void),
                         /* arg0:    object */ javaCallingConvention(Kind.Object));
 
-        addRuntimeCall(CREATE_NULL_POINTER_EXCEPTION, config.createNullPointerExceptionStub,
-                        /*           temps */ null,
-                        /*             ret */ ret(Kind.Object));
+        addCRuntimeCall(REGISTER_FINALIZER_C, config.registerFinalizerAddress,
+                        /*             ret */ ret(Kind.Void),
+                        /* arg0:    thread */ nativeCallingConvention(word,
+                        /* arg1:    object */                         Kind.Object));
+
+        addStubCall(NEW_ARRAY,
+                        /*             ret */ ret(Kind.Object),
+                        /* arg0:       hub */ javaCallingConvention(word,
+                        /* arg1:    length */ Kind.Int));
+
+        addCRuntimeCall(NEW_ARRAY_C, config.newArrayAddress,
+                        /*             ret */ ret(Kind.Void),
+                        /* arg0:    thread */ nativeCallingConvention(word,
+                        /* arg1:       hub */                         word,
+                        /* arg2:    length */                         Kind.Int));
 
-        addRuntimeCall(CREATE_OUT_OF_BOUNDS_EXCEPTION, config.createOutOfBoundsExceptionStub,
-                        /*           temps */ null,
+        addStubCall(NEW_INSTANCE,
+                        /*             ret */ ret(Kind.Object),
+                        /* arg0:       hub */ javaCallingConvention(word));
+
+        addCRuntimeCall(NEW_INSTANCE_C, config.newInstanceAddress,
+                        /*             ret */ ret(Kind.Void),
+                        /* arg0:    thread */ nativeCallingConvention(word,
+                        /* arg1:       hub */                         word));
+
+        addStubCall(NEW_MULTI_ARRAY,
                         /*             ret */ ret(Kind.Object),
-                        /* arg0:     index */ javaCallingConvention(Kind.Int));
+                        /* arg0:       hub */ javaCallingConvention(word,
+                        /* arg1:      rank */                       Kind.Int,
+                        /* arg2:      dims */                       word));
+
+        addCRuntimeCall(NEW_MULTI_ARRAY_C, config.newMultiArrayAddress,
+                        /*             ret */ ret(Kind.Void),
+                        /* arg0:    thread */ nativeCallingConvention(word,
+                        /* arg1:       hub */                         word,
+                        /* arg2:      rank */                         Kind.Int,
+                        /* arg3:      dims */                         word));
 
         addRuntimeCall(JAVA_TIME_MILLIS, config.javaTimeMillisStub,
                         /*           temps */ this.regConfig.getCallerSaveRegisters(),
@@ -247,34 +320,142 @@
                         /*             ret */ ret(Kind.Double),
                         /* arg0:     index */ javaCallingConvention(Kind.Double));
 
-        addRuntimeCall(LOG_PRIMITIVE, config.logPrimitiveStub,
-                        /*           temps */ null,
+        addStubCall(LOG_PRIMITIVE,
                         /*             ret */ ret(Kind.Void),
                         /* arg0:  typeChar */ javaCallingConvention(Kind.Int,
                         /* arg1:     value */                       Kind.Long,
                         /* arg2:   newline */                       Kind.Boolean));
 
-        addRuntimeCall(LOG_PRINTF, config.logPrintfStub,
-                        /*           temps */ null,
+        addCRuntimeCall(LOG_PRIMITIVE_C, config.logPrimitiveAddress,
+                        /*             ret */ ret(Kind.Void),
+                        /* arg0:    thread */ nativeCallingConvention(word,
+                        /* arg1:  typeChar */                         Kind.Char,
+                        /* arg2:     value */                         Kind.Long,
+                        /* arg3:   newline */                         Kind.Boolean));
+
+        addStubCall(LOG_PRINTF,
                         /*             ret */ ret(Kind.Void),
                         /* arg0:    format */ javaCallingConvention(Kind.Object,
                         /* arg1:     value */                       Kind.Long,
                         /* arg2:     value */                       Kind.Long,
                         /* arg3:     value */                       Kind.Long));
 
-        addRuntimeCall(Stub.STUB_PRINTF, config.stubPrintfStub,
-                        /*           temps */ null,
+        addCRuntimeCall(LOG_PRINTF_C, config.logObjectAddress,
                         /*             ret */ ret(Kind.Void),
-                        /* arg0:    format */ javaCallingConvention(Kind.Long,
-                        /* arg1:     value */                       Kind.Long,
-                        /* arg2:     value */                       Kind.Long,
-                        /* arg3:     value */                       Kind.Long));
+                        /* arg0:    thread */ nativeCallingConvention(word,
+                        /* arg1:    format */                         Kind.Object,
+                        /* arg2:        v1 */                         Kind.Long,
+                        /* arg3:        v2 */                         Kind.Long,
+                        /* arg4:        v3 */                         Kind.Long));
 
-        addRuntimeCall(LOG_OBJECT, config.logObjectStub,
-                        /*           temps */ null,
+        addCRuntimeCall(VM_MESSAGE_C, config.vmMessageAddress,
+                        /*             ret */ ret(Kind.Void),
+                        /* arg0:   vmError */ nativeCallingConvention(Kind.Boolean,
+                        /* arg1:    format */                         word,
+                        /* arg2:     value */                         Kind.Long,
+                        /* arg3:     value */                         Kind.Long,
+                        /* arg4:     value */                         Kind.Long));
+
+        addStubCall(LOG_OBJECT,
                         /*             ret */ ret(Kind.Void),
                         /* arg0:    object */ javaCallingConvention(Kind.Object,
                         /* arg1:     flags */                       Kind.Int));
+
+        addCRuntimeCall(LOG_OBJECT_C, config.logObjectAddress,
+                        /*             ret */ ret(Kind.Void),
+                        /* arg0:    thread */ nativeCallingConvention(word,
+                        /* arg1:    object */                         Kind.Object,
+                        /* arg2:     flags */                         Kind.Int));
+
+        addStubCall(THREAD_IS_INTERRUPTED,
+                        /*             ret */ ret(Kind.Boolean),
+                        /* arg0:    thread */ javaCallingConvention(Kind.Object,
+                 /* arg1: clearInterrupted */                       Kind.Boolean));
+
+        addCRuntimeCall(THREAD_IS_INTERRUPTED_C, config.threadIsInterruptedAddress,
+                        /*             ret */ ret(Kind.Boolean),
+                        /* arg0:    thread */ nativeCallingConvention(word,
+                   /* arg1: receiverThread */                         Kind.Object,
+              /* arg1: clearInterrupted */                            Kind.Boolean));
+
+        addRuntimeCall(DEOPT_HANDLER, config.handleDeoptStub,
+                        /*           temps */ null,
+                        /*             ret */ ret(Kind.Void));
+
+        addRuntimeCall(IC_MISS_HANDLER, config.inlineCacheMissStub,
+                        /*           temps */ null,
+                        /*             ret */ ret(Kind.Void));
+
+        addStubCall(MONITORENTER,
+                        /*          ret */ ret(Kind.Void),
+                        /* arg0: object */ javaCallingConvention(Kind.Object,
+                        /* arg1:   lock */                       word));
+
+        addCRuntimeCall(MONITORENTER_C, config.monitorenterAddress,
+                        /*          ret */ ret(Kind.Void),
+                        /* arg0: thread */ nativeCallingConvention(word,
+                        /* arg1: object */                         Kind.Object,
+                        /* arg1:   lock */                         word));
+
+        addStubCall(MONITOREXIT,
+                        /*          ret */ ret(Kind.Void),
+                        /* arg0: object */ javaCallingConvention(Kind.Object,
+                        /* arg1:   lock */                       word));
+
+        addCRuntimeCall(MONITOREXIT_C, config.monitorexitAddress,
+                        /*          ret */ ret(Kind.Void),
+                        /* arg0: thread */ nativeCallingConvention(word,
+                        /* arg1: object */                         Kind.Object,
+                        /* arg1:   lock */                         word));
+
+        addStubCall(CREATE_NULL_POINTER_EXCEPTION,
+                        /*             ret */ ret(Kind.Object));
+
+        addCRuntimeCall(CREATE_NULL_POINTER_EXCEPTION_C, config.createNullPointerExceptionAddress,
+                        /*          ret */ ret(Kind.Void),
+                        /* arg0: thread */ nativeCallingConvention(word));
+
+        addStubCall(CREATE_OUT_OF_BOUNDS_EXCEPTION,
+                        /*             ret */ ret(Kind.Object),
+                        /* arg0:     index */ javaCallingConvention(Kind.Int));
+
+        addCRuntimeCall(CREATE_OUT_OF_BOUNDS_C, config.createOutOfBoundsExceptionAddress,
+                        /*          ret */ ret(Kind.Void),
+                        /* arg0: thread */ nativeCallingConvention(word,
+                        /* arg1:  index */                         Kind.Int));
+
+        addStubCall(VM_ERROR,
+                        /*          ret */ ret(Kind.Void),
+                        /* arg0:  where */ javaCallingConvention(Kind.Object,
+                        /* arg1: format */                       Kind.Object,
+                        /* arg2:  value */                       Kind.Long));
+
+        addCRuntimeCall(VM_ERROR_C, config.vmErrorAddress,
+                        /*          ret */ ret(Kind.Void),
+                        /* arg0: thread */ nativeCallingConvention(word,
+                        /* arg0:  where */                         Kind.Object,
+                        /* arg1: format */                         Kind.Object,
+                        /* arg2:  value */                         Kind.Long));
+
+        addStubCall(WRITE_BARRIER_PRE,
+                        /*          ret */ ret(Kind.Void),
+                        /* arg0: object */ javaCallingConvention(Kind.Object));
+
+        addCRuntimeCall(WRITE_BARRIER_PRE_C, config.writeBarrierPreAddress,
+                        /*          ret */ ret(Kind.Void),
+                        /* arg0: thread */ nativeCallingConvention(word,
+                        /* arg1: object */                         Kind.Object));
+
+        addStubCall(WRITE_BARRIER_POST,
+                        /*          ret */ ret(Kind.Void),
+                        /* arg0: object */ javaCallingConvention(Kind.Object,
+                        /* arg1:   card */                       word));
+
+        addCRuntimeCall(WRITE_BARRIER_POST_C, config.writeBarrierPostAddress,
+                        /*          ret */ ret(Kind.Void),
+                        /* arg0: thread */ nativeCallingConvention(word,
+                        /* arg1: object */                         Kind.Object,
+                        /* arg2:   card */                         word));
         // @formatter:on
     }
 
@@ -290,6 +471,33 @@
     }
 
     /**
+     * Registers the details for a jump to a target that has a signature (i.e. expects arguments in
+     * specified locations).
+     * 
+     * @param descriptor name and signature of the jump target
+     * @param args where arguments are passed to the call
+     */
+    protected RuntimeCallTarget addJump(Descriptor descriptor, AllocatableValue... args) {
+        return addRuntimeCall(descriptor, HotSpotRuntimeCallTarget.JUMP_ADDRESS, null, ret(Kind.Void), args);
+    }
+
+    /**
+     * Registers the details for a call to a runtime C/C++ function.
+     * 
+     * @param descriptor name and signature of the call
+     * @param args where arguments are passed to the call
+     */
+    protected RuntimeCallTarget addCRuntimeCall(Descriptor descriptor, long address, AllocatableValue ret, AllocatableValue... args) {
+        assert descriptor.getResultType().isPrimitive() || Word.class.isAssignableFrom(descriptor.getResultType()) : "C runtime call cannot have Object return type - objects must be returned via thread local storage: " +
+                        descriptor;
+        return addRuntimeCall(descriptor, address, true, null, ret, args);
+    }
+
+    protected RuntimeCallTarget addRuntimeCall(Descriptor descriptor, long address, Register[] tempRegs, AllocatableValue ret, AllocatableValue... args) {
+        return addRuntimeCall(descriptor, address, false, tempRegs, ret, args);
+    }
+
+    /**
      * Registers the details for linking a runtime call.
      * 
      * @param descriptor name and signature of the call
@@ -298,7 +506,7 @@
      * @param ret where the call returns its result
      * @param args where arguments are passed to the call
      */
-    protected RuntimeCallTarget addRuntimeCall(Descriptor descriptor, long address, Register[] tempRegs, AllocatableValue ret, AllocatableValue... args) {
+    protected RuntimeCallTarget addRuntimeCall(Descriptor descriptor, long address, boolean isCRuntimeCall, Register[] tempRegs, AllocatableValue ret, AllocatableValue... args) {
         AllocatableValue[] temps = tempRegs == null || tempRegs.length == 0 ? AllocatableValue.NONE : new AllocatableValue[tempRegs.length];
         for (int i = 0; i < temps.length; i++) {
             temps[i] = tempRegs[i].asValue();
@@ -309,7 +517,7 @@
         for (int i = 0; i < argTypes.length; i++) {
             assert checkAssignable(argTypes[i], args[i]) : descriptor + " incompatible with argument location " + i + ": " + args[i];
         }
-        HotSpotRuntimeCallTarget runtimeCall = new HotSpotRuntimeCallTarget(descriptor, address, new CallingConvention(temps, 0, ret, args), graalRuntime.getCompilerToVM());
+        HotSpotRuntimeCallTarget runtimeCall = new HotSpotRuntimeCallTarget(descriptor, address, isCRuntimeCall, new CallingConvention(temps, 0, ret, args), graalRuntime.getCompilerToVM());
         runtimeCalls.put(descriptor, runtimeCall);
         return runtimeCall;
     }
@@ -347,6 +555,9 @@
             replacements.registerSubstitutions(AESCryptSubstitutions.class);
             replacements.registerSubstitutions(CipherBlockChainingSubstitutions.class);
         }
+        if (GraalOptions.IntrinsifyReflectionMethods) {
+            replacements.registerSubstitutions(ReflectionSubstitutions.class);
+        }
 
         checkcastSnippets = new CheckCastSnippets.Templates(this, replacements, graalRuntime.getTarget());
         instanceofSnippets = new InstanceOfSnippets.Templates(this, replacements, graalRuntime.getTarget());
@@ -356,13 +567,40 @@
         boxingSnippets = new BoxingSnippets.Templates(this, replacements, graalRuntime.getTarget());
         exceptionObjectSnippets = new LoadExceptionObjectSnippets.Templates(this, replacements, graalRuntime.getTarget());
 
-        registerStub(new NewInstanceStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(NEW_INSTANCE)));
-        registerStub(new NewArrayStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(NEW_ARRAY)));
+        link(new NewInstanceStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(NEW_INSTANCE)));
+        link(new NewArrayStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(NEW_ARRAY)));
+        link(new NewMultiArrayStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(NEW_MULTI_ARRAY)));
+        link(new RegisterFinalizerStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(REGISTER_FINALIZER)));
+        link(new ThreadIsInterruptedStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(THREAD_IS_INTERRUPTED)));
+        link(new ExceptionHandlerStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(EXCEPTION_HANDLER)));
+        link(new UnwindExceptionToCallerStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(UNWIND_EXCEPTION_TO_CALLER)));
+        link(new VerifyOopStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(VERIFY_OOP)));
+        link(new OSRMigrationEndStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(OSR_MIGRATION_END)));
+        link(new MonitorEnterStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(MONITORENTER)));
+        link(new MonitorExitStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(MONITOREXIT)));
+        link(new CreateNullPointerExceptionStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(CREATE_NULL_POINTER_EXCEPTION)));
+        link(new CreateOutOfBoundsExceptionStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(CREATE_OUT_OF_BOUNDS_EXCEPTION)));
+        link(new LogPrimitiveStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(LOG_PRIMITIVE)));
+        link(new LogObjectStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(LOG_OBJECT)));
+        link(new LogPrintfStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(LOG_PRINTF)));
+        link(new VMErrorStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(VM_ERROR)));
+        link(new WriteBarrierPreStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(WRITE_BARRIER_PRE)));
+        link(new WriteBarrierPostStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(WRITE_BARRIER_POST)));
+
+        CompilerToVM c2vm = graalRuntime.getCompilerToVM();
+        link(new RuntimeCallStub(config.identityHashCodeAddress, IDENTITY_HASHCODE, true, this, replacements, globalStubRegConfig, c2vm));
     }
 
-    private void registerStub(Stub stub) {
+    private static void link(Stub stub) {
         stub.getLinkage().setStub(stub);
-        stubs.put(stub.getMethod(), stub);
+    }
+
+    private void link(RuntimeCallStub stub) {
+        HotSpotRuntimeCallTarget linkage = stub.getLinkage();
+        HotSpotRuntimeCallTarget targetLinkage = stub.getTargetLinkage();
+        linkage.setStub(stub);
+        runtimeCalls.put(linkage.getDescriptor(), linkage);
+        runtimeCalls.put(targetLinkage.getDescriptor(), targetLinkage);
     }
 
     public HotSpotGraalRuntime getGraalRuntime() {
@@ -516,7 +754,7 @@
             ArrayLengthNode arrayLengthNode = (ArrayLengthNode) n;
             ValueNode array = arrayLengthNode.array();
             ReadNode arrayLengthRead = graph.add(new ReadNode(array, ConstantLocationNode.create(LocationNode.FINAL_LOCATION, Kind.Int, config.arrayLengthOffset, graph), StampFactory.positiveInt()));
-            arrayLengthRead.dependencies().add(tool.createNullCheckGuard(array));
+            tool.createNullCheckGuard(arrayLengthRead, array);
             graph.replaceFixedWithFixed(arrayLengthNode, arrayLengthRead);
         } else if (n instanceof Invoke) {
             Invoke invoke = (Invoke) n;
@@ -525,7 +763,7 @@
                 NodeInputList<ValueNode> parameters = callTarget.arguments();
                 ValueNode receiver = parameters.size() <= 0 ? null : parameters.get(0);
                 if (!callTarget.isStatic() && receiver.kind() == Kind.Object && !receiver.objectStamp().nonNull()) {
-                    invoke.asNode().dependencies().add(tool.createNullCheckGuard(receiver));
+                    tool.createNullCheckGuard(invoke, receiver);
                 }
                 JavaType[] signature = MetaUtil.signatureToTypes(callTarget.targetMethod().getSignature(), callTarget.isStatic() ? null : callTarget.targetMethod().getDeclaringClass());
 
@@ -534,15 +772,14 @@
 
                     HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod();
                     if (!hsMethod.getDeclaringClass().isInterface()) {
-                        int vtableEntryOffset = hsMethod.vtableEntryOffset();
-                        if (vtableEntryOffset > 0) {
-                            // We use LocationNode.ANY_LOCATION for the reads that access the vtable
-                            // entry and the compiled code entry
-                            // as HotSpot does not guarantee they are final values.
+                        if (hsMethod.isInVirtualMethodTable()) {
+                            int vtableEntryOffset = hsMethod.vtableEntryOffset();
                             assert vtableEntryOffset > 0;
-                            LoadHubNode hub = graph.add(new LoadHubNode(receiver, wordKind));
-                            ReadNode metaspaceMethod = graph.add(new ReadNode(hub, ConstantLocationNode.create(LocationNode.ANY_LOCATION, wordKind, vtableEntryOffset, graph),
-                                            StampFactory.forKind(wordKind())));
+                            ReadNode hub = this.createReadHub(tool, graph, wordKind, receiver);
+                            ReadNode metaspaceMethod = createReadVirtualMethod(graph, wordKind, hub, hsMethod);
+                            // We use LocationNode.ANY_LOCATION for the reads that access the
+                            // compiled code entry as HotSpot does not guarantee they are final
+                            // values.
                             ReadNode compiledEntry = graph.add(new ReadNode(metaspaceMethod, ConstantLocationNode.create(LocationNode.ANY_LOCATION, wordKind, config.methodCompiledEntryOffset, graph),
                                             StampFactory.forKind(wordKind())));
 
@@ -567,8 +804,8 @@
             HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) loadField.field();
             ValueNode object = loadField.isStatic() ? ConstantNode.forObject(field.getDeclaringClass().mirror(), this, graph) : loadField.object();
             assert loadField.kind() != Kind.Illegal;
-            ReadNode memoryRead = graph.add(new ReadNode(object, ConstantLocationNode.create(field, field.getKind(), field.offset(), graph), loadField.stamp()));
-            memoryRead.dependencies().add(tool.createNullCheckGuard(object));
+            ReadNode memoryRead = graph.add(new ReadNode(object, createFieldLocation(graph, field), loadField.stamp()));
+            tool.createNullCheckGuard(memoryRead, object);
 
             graph.replaceFixedWithFixed(loadField, memoryRead);
 
@@ -582,10 +819,9 @@
             StoreFieldNode storeField = (StoreFieldNode) n;
             HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) storeField.field();
             ValueNode object = storeField.isStatic() ? ConstantNode.forObject(field.getDeclaringClass().mirror(), this, graph) : storeField.object();
-            LocationNode location = ConstantLocationNode.create(field, field.getKind(), field.offset(), graph);
             WriteBarrierType barrierType = getFieldStoreBarrierType(storeField);
-            WriteNode memoryWrite = graph.add(new WriteNode(object, storeField.value(), location, barrierType));
-            memoryWrite.dependencies().add(tool.createNullCheckGuard(object));
+            WriteNode memoryWrite = graph.add(new WriteNode(object, storeField.value(), createFieldLocation(graph, field), barrierType));
+            tool.createNullCheckGuard(memoryWrite, object);
             memoryWrite.setStateAfter(storeField.stateAfter());
             graph.replaceFixedWithFixed(storeField, memoryWrite);
             FixedWithNextNode last = memoryWrite;
@@ -605,15 +841,15 @@
             cas.setWriteBarrierType(getCompareAndSwapBarrier(cas));
         } else if (n instanceof LoadIndexedNode) {
             LoadIndexedNode loadIndexed = (LoadIndexedNode) n;
-            ValueNode boundsCheck = createBoundsCheck(loadIndexed, tool);
+            GuardingNode boundsCheck = createBoundsCheck(loadIndexed, tool);
             Kind elementKind = loadIndexed.elementKind();
             LocationNode arrayLocation = createArrayLocation(graph, elementKind, loadIndexed.index());
             ReadNode memoryRead = graph.add(new ReadNode(loadIndexed.array(), arrayLocation, loadIndexed.stamp()));
-            memoryRead.dependencies().add(boundsCheck);
+            memoryRead.setGuard(boundsCheck);
             graph.replaceFixedWithFixed(loadIndexed, memoryRead);
         } else if (n instanceof StoreIndexedNode) {
             StoreIndexedNode storeIndexed = (StoreIndexedNode) n;
-            ValueNode boundsCheck = createBoundsCheck(storeIndexed, tool);
+            GuardingNode boundsCheck = createBoundsCheck(storeIndexed, tool);
             Kind elementKind = storeIndexed.elementKind();
             LocationNode arrayLocation = createArrayLocation(graph, elementKind, storeIndexed.index());
             ValueNode value = storeIndexed.value();
@@ -624,7 +860,7 @@
                 if (arrayType != null && array.objectStamp().isExactType()) {
                     ResolvedJavaType elementType = arrayType.getComponentType();
                     if (!MetaUtil.isJavaLangObject(elementType)) {
-                        CheckCastNode checkcast = graph.add(new CheckCastNode(elementType, value, null));
+                        CheckCastNode checkcast = graph.add(new CheckCastNode(elementType, value, null, true));
                         graph.addBeforeFixed(storeIndexed, checkcast);
                         value = checkcast;
                     }
@@ -632,7 +868,7 @@
                     LoadHubNode arrayClass = graph.add(new LoadHubNode(array, wordKind));
                     LocationNode location = ConstantLocationNode.create(LocationNode.FINAL_LOCATION, wordKind, config.arrayClassElementOffset, graph);
                     FloatingReadNode arrayElementKlass = graph.unique(new FloatingReadNode(arrayClass, location, null, StampFactory.forKind(wordKind())));
-                    CheckCastDynamicNode checkcast = graph.add(new CheckCastDynamicNode(arrayElementKlass, value));
+                    CheckCastDynamicNode checkcast = graph.add(new CheckCastDynamicNode(arrayElementKlass, value, true));
                     graph.addBeforeFixed(storeIndexed, checkcast);
                     graph.addBeforeFixed(checkcast, arrayClass);
                     value = checkcast;
@@ -640,7 +876,7 @@
             }
             WriteBarrierType barrierType = getArrayStoreBarrierType(storeIndexed);
             WriteNode memoryWrite = graph.add(new WriteNode(array, value, arrayLocation, barrierType));
-            memoryWrite.dependencies().add(boundsCheck);
+            memoryWrite.setGuard(boundsCheck);
             memoryWrite.setStateAfter(storeIndexed.stateAfter());
             graph.replaceFixedWithFixed(storeIndexed, memoryWrite);
 
@@ -651,7 +887,7 @@
             ReadNode memoryRead = graph.add(new ReadNode(load.object(), location, load.stamp()));
             // An unsafe read must not floating outside its block as may float above an explicit
             // null check on its object.
-            memoryRead.dependencies().add(BeginNode.prevBegin(load));
+            memoryRead.setGuard(AbstractBeginNode.prevBegin(load));
             graph.replaceFixedWithFixed(load, memoryRead);
         } else if (n instanceof UnsafeStoreNode) {
             UnsafeStoreNode store = (UnsafeStoreNode) n;
@@ -661,23 +897,111 @@
             WriteNode write = graph.add(new WriteNode(object, store.value(), location, barrierType));
             write.setStateAfter(store.stateAfter());
             graph.replaceFixedWithFixed(store, write);
-
         } else if (n instanceof LoadHubNode) {
             LoadHubNode loadHub = (LoadHubNode) n;
             assert loadHub.kind() == wordKind;
-            LocationNode location = ConstantLocationNode.create(LocationNode.FINAL_LOCATION, wordKind, config.hubOffset, graph);
             ValueNode object = loadHub.object();
-            assert !object.isConstant() || object.asConstant().isNull();
-            ValueNode guard = tool.createNullCheckGuard(object);
-            ReadNode hub = graph.add(new ReadNode(object, location, StampFactory.forKind(wordKind())));
-            hub.dependencies().add(guard);
+            ReadNode hub = createReadHub(tool, graph, wordKind, object);
             graph.replaceFixed(loadHub, hub);
+        } else if (n instanceof LoadMethodNode) {
+            LoadMethodNode loadMethodNode = (LoadMethodNode) n;
+            ResolvedJavaMethod method = loadMethodNode.getMethod();
+            ReadNode metaspaceMethod = createReadVirtualMethod(graph, wordKind, loadMethodNode.getHub(), method);
+            graph.replaceFixed(loadMethodNode, metaspaceMethod);
         } else if (n instanceof FixedGuardNode) {
             FixedGuardNode node = (FixedGuardNode) n;
-            ValueAnchorNode newAnchor = graph.add(new ValueAnchorNode(tool.createGuard(node.condition(), node.getReason(), node.getAction(), node.isNegated())));
+            ValueAnchorNode newAnchor = graph.add(new ValueAnchorNode(tool.createGuard(node.condition(), node.getReason(), node.getAction(), node.isNegated()).asNode()));
             graph.replaceFixedWithFixed(node, newAnchor);
+        } else if (n instanceof CommitAllocationNode) {
+            CommitAllocationNode commit = (CommitAllocationNode) n;
+
+            ValueNode[] allocations = new ValueNode[commit.getVirtualObjects().size()];
+            for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
+                VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex);
+                int entryCount = virtual.entryCount();
+
+                FixedWithNextNode newObject;
+                if (virtual instanceof VirtualInstanceNode) {
+                    newObject = graph.add(new NewInstanceNode(virtual.type(), true));
+                } else {
+                    ResolvedJavaType element = ((VirtualArrayNode) virtual).componentType();
+                    newObject = graph.add(new NewArrayNode(element, ConstantNode.forInt(entryCount, graph), true));
+                }
+                graph.addBeforeFixed(commit, newObject);
+                allocations[objIndex] = newObject;
+            }
+            int valuePos = 0;
+            for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
+                VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex);
+                int entryCount = virtual.entryCount();
+
+                ValueNode newObject = allocations[objIndex];
+                if (virtual instanceof VirtualInstanceNode) {
+                    VirtualInstanceNode instance = (VirtualInstanceNode) virtual;
+                    for (int i = 0; i < entryCount; i++) {
+                        ValueNode value = commit.getValues().get(valuePos++);
+                        if (value instanceof VirtualObjectNode) {
+                            value = allocations[commit.getVirtualObjects().indexOf(value)];
+                        }
+                        graph.addBeforeFixed(commit, graph.add(new WriteNode(newObject, value, createFieldLocation(graph, (HotSpotResolvedJavaField) instance.field(i)), WriteBarrierType.NONE)));
+                    }
+                } else {
+                    VirtualArrayNode array = (VirtualArrayNode) virtual;
+                    ResolvedJavaType element = array.componentType();
+                    for (int i = 0; i < entryCount; i++) {
+                        ValueNode value = commit.getValues().get(valuePos++);
+                        if (value instanceof VirtualObjectNode) {
+                            int indexOf = commit.getVirtualObjects().indexOf(value);
+                            assert indexOf != -1 : commit + " " + value;
+                            value = allocations[indexOf];
+                        }
+                        graph.addBeforeFixed(commit, graph.add(new WriteNode(newObject, value, createArrayLocation(graph, element.getKind(), ConstantNode.forInt(i, graph)), WriteBarrierType.NONE)));
+                    }
+                }
+            }
+            for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
+                FixedValueAnchorNode anchor = graph.add(new FixedValueAnchorNode(allocations[objIndex]));
+                allocations[objIndex] = anchor;
+                graph.addBeforeFixed(commit, anchor);
+            }
+            for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
+                for (int lockDepth : commit.getLocks().get(objIndex)) {
+                    MonitorEnterNode enter = graph.add(new MonitorEnterNode(allocations[objIndex], lockDepth));
+                    graph.addBeforeFixed(commit, enter);
+                }
+            }
+            for (Node usage : commit.usages().snapshot()) {
+                AllocatedObjectNode addObject = (AllocatedObjectNode) usage;
+                int index = commit.getVirtualObjects().indexOf(addObject.getVirtualObject());
+                graph.replaceFloating(addObject, allocations[index]);
+            }
+            graph.removeFixed(commit);
         } else if (n instanceof CheckCastNode) {
             checkcastSnippets.lower((CheckCastNode) n, tool);
+        } else if (n instanceof OSRStartNode) {
+            OSRStartNode osrStart = (OSRStartNode) n;
+            StartNode newStart = graph.add(new StartNode());
+            LocalNode buffer = graph.unique(new LocalNode(0, StampFactory.forKind(wordKind())));
+            RuntimeCallNode migrationEnd = graph.add(new RuntimeCallNode(OSR_MIGRATION_END, buffer));
+            migrationEnd.setStateAfter(osrStart.stateAfter());
+
+            newStart.setNext(migrationEnd);
+            FixedNode next = osrStart.next();
+            osrStart.setNext(null);
+            migrationEnd.setNext(next);
+            graph.setStart(newStart);
+
+            // mirroring the calculations in c1_GraphBuilder.cpp (setup_osr_entry_block)
+            int localsOffset = (graph.method().getMaxLocals() - 1) * 8;
+            for (OSRLocalNode osrLocal : graph.getNodes(OSRLocalNode.class)) {
+                int size = FrameStateBuilder.stackSlots(osrLocal.kind());
+                int offset = localsOffset - (osrLocal.index() + size - 1) * 8;
+                UnsafeLoadNode load = graph.add(new UnsafeLoadNode(buffer, offset, ConstantNode.forInt(0, graph), osrLocal.kind()));
+                osrLocal.replaceAndDelete(load);
+                graph.addBeforeFixed(migrationEnd, load);
+            }
+            osrStart.replaceAtUsages(newStart);
+            osrStart.safeDelete();
         } else if (n instanceof CheckCastDynamicNode) {
             checkcastSnippets.lower((CheckCastDynamicNode) n);
         } else if (n instanceof InstanceOfNode) {
@@ -721,6 +1045,27 @@
         }
     }
 
+    private static ReadNode createReadVirtualMethod(StructuredGraph graph, Kind wordKind, ValueNode hub, ResolvedJavaMethod method) {
+        HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) method;
+        assert !hsMethod.getDeclaringClass().isInterface();
+        assert hsMethod.isInVirtualMethodTable();
+
+        int vtableEntryOffset = hsMethod.vtableEntryOffset();
+        assert vtableEntryOffset > 0;
+        // We use LocationNode.ANY_LOCATION for the reads that access the vtable
+        // entry as HotSpot does not guarantee that this is a final value.
+        ReadNode metaspaceMethod = graph.add(new ReadNode(hub, ConstantLocationNode.create(LocationNode.ANY_LOCATION, wordKind, vtableEntryOffset, graph), StampFactory.forKind(wordKind())));
+        return metaspaceMethod;
+    }
+
+    private ReadNode createReadHub(LoweringTool tool, StructuredGraph graph, Kind wordKind, ValueNode object) {
+        LocationNode location = ConstantLocationNode.create(LocationNode.FINAL_LOCATION, wordKind, config.hubOffset, graph);
+        assert !object.isConstant() || object.asConstant().isNull();
+        ReadNode hub = graph.add(new ReadNode(object, location, StampFactory.forKind(wordKind())));
+        tool.createNullCheckGuard(hub, object);
+        return hub;
+    }
+
     private static WriteBarrierType getFieldStoreBarrierType(StoreFieldNode storeField) {
         WriteBarrierType barrierType = WriteBarrierType.NONE;
         if (storeField.field().getKind() == Kind.Object && !storeField.value().objectStamp().alwaysNull()) {
@@ -763,15 +1108,19 @@
         return barrierType;
     }
 
-    private IndexedLocationNode createArrayLocation(Graph graph, Kind elementKind, ValueNode index) {
-        int scale = this.graalRuntime.getTarget().sizeInBytes(elementKind);
+    protected static ConstantLocationNode createFieldLocation(StructuredGraph graph, HotSpotResolvedJavaField field) {
+        return ConstantLocationNode.create(field, field.getKind(), field.offset(), graph);
+    }
+
+    protected IndexedLocationNode createArrayLocation(Graph graph, Kind elementKind, ValueNode index) {
+        int scale = this.graalRuntime.getTarget().arch.getSizeInBytes(elementKind);
         return IndexedLocationNode.create(LocationNode.getArrayLocation(elementKind), elementKind, getArrayBaseOffset(elementKind), index, graph, scale);
     }
 
-    private static ValueNode createBoundsCheck(AccessIndexedNode n, LoweringTool tool) {
-        StructuredGraph graph = (StructuredGraph) n.graph();
+    private static GuardingNode createBoundsCheck(AccessIndexedNode n, LoweringTool tool) {
+        StructuredGraph graph = n.graph();
         ArrayLengthNode arrayLength = graph.add(new ArrayLengthNode(n.array()));
-        ValueNode guard = tool.createGuard(graph.unique(new IntegerBelowThanNode(n.index(), arrayLength)), BoundsCheckException, InvalidateReprofile);
+        GuardingNode guard = tool.createGuard(graph.unique(new IntegerBelowThanNode(n.index(), arrayLength)), BoundsCheckException, InvalidateReprofile);
 
         graph.addBeforeFixed(n, arrayLength);
         return guard;
@@ -781,16 +1130,6 @@
         return HotSpotResolvedObjectType.fromClass(clazz);
     }
 
-    /**
-     * Gets the stub corresponding to a given method.
-     * 
-     * @return the stub {@linkplain Stub#getMethod() implemented} by {@code method} or null if
-     *         {@code method} does not implement a stub
-     */
-    public Stub asStub(ResolvedJavaMethod method) {
-        return stubs.get(method);
-    }
-
     public HotSpotRuntimeCallTarget lookupRuntimeCall(Descriptor descriptor) {
         HotSpotRuntimeCallTarget callTarget = runtimeCalls.get(descriptor);
         assert runtimeCalls != null : descriptor;
@@ -895,6 +1234,8 @@
                 return config.deoptReasonDiv0Check;
             case RuntimeConstraint:
                 return config.deoptReasonConstraint;
+            case LoopLimitCheck:
+                return config.deoptReasonLoopLimitCheck;
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
@@ -904,20 +1245,6 @@
         return constant.getPrimitiveAnnotation() != null;
     }
 
-    /**
-     * Registers an object created by the compiler and referenced by some generated code. HotSpot
-     * treats oops embedded in code as weak references so without an external strong root, such an
-     * embedded oop will quickly die. This in turn will cause the nmethod to be unloaded.
-     */
-    public synchronized Object registerGCRoot(Object object) {
-        Object existing = gcRoots.get(object);
-        if (existing != null) {
-            return existing;
-        }
-        gcRoots.put(object, object);
-        return object;
-    }
-
     @Override
     public Constant readUnsafeConstant(Kind kind, Object base, long displacement) {
         switch (kind) {
@@ -951,8 +1278,8 @@
 
     public String disassemble(InstalledCode code) {
         if (code.isValid()) {
-            long nmethod = ((HotSpotInstalledCode) code).getMethodAddress();
-            return graalRuntime.getCompilerToVM().disassembleNMethod(nmethod);
+            long codeBlob = ((HotSpotInstalledCode) code).getCodeBlob();
+            return graalRuntime.getCompilerToVM().disassembleCodeBlob(codeBlob);
         }
         return null;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSignature.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSignature.java	Mon May 13 17:11:31 2013 +0200
@@ -37,10 +37,10 @@
 public class HotSpotSignature extends CompilerObject implements Signature {
 
     private static final long serialVersionUID = -2890917956072366116L;
-    private final List<String> arguments = new ArrayList<>();
+    private final List<String> parameters = new ArrayList<>();
     private final String returnType;
     private final String originalString;
-    private JavaType[] argumentTypes;
+    private JavaType[] parameterTypes;
     private JavaType returnTypeCache;
 
     public HotSpotSignature(String signature) {
@@ -51,7 +51,7 @@
             int cur = 1;
             while (cur < signature.length() && signature.charAt(cur) != ')') {
                 int nextCur = parseSignature(signature, cur);
-                arguments.add(signature.substring(cur, nextCur));
+                parameters.add(signature.substring(cur, nextCur));
                 cur = nextCur;
             }
 
@@ -64,6 +64,20 @@
         }
     }
 
+    public HotSpotSignature(JavaType returnType, JavaType... parameterTypes) {
+        this.parameterTypes = parameterTypes.clone();
+        this.returnTypeCache = returnType;
+        this.returnType = returnType.getName();
+        StringBuilder sb = new StringBuilder("(");
+        for (JavaType type : parameterTypes) {
+            parameters.add(type.getName());
+            sb.append(type.getName());
+        }
+        sb.append(")").append(returnType.getName());
+        this.originalString = sb.toString();
+        assert new HotSpotSignature(originalString).equals(this);
+    }
+
     private static int parseSignature(String signature, int start) {
         int cur = start;
         char first;
@@ -96,12 +110,12 @@
 
     @Override
     public int getParameterCount(boolean withReceiver) {
-        return arguments.size() + (withReceiver ? 1 : 0);
+        return parameters.size() + (withReceiver ? 1 : 0);
     }
 
     @Override
     public Kind getParameterKind(int index) {
-        return Kind.fromTypeString(arguments.get(index));
+        return Kind.fromTypeString(parameters.get(index));
     }
 
     @Override
@@ -115,13 +129,13 @@
 
     @Override
     public JavaType getParameterType(int index, ResolvedJavaType accessingClass) {
-        if (argumentTypes == null) {
-            argumentTypes = new JavaType[arguments.size()];
+        if (parameterTypes == null) {
+            parameterTypes = new JavaType[parameters.size()];
         }
-        JavaType type = argumentTypes[index];
+        JavaType type = parameterTypes[index];
         if (type == null || !(type instanceof ResolvedJavaType)) {
-            type = graalRuntime().lookupType(arguments.get(index), (HotSpotResolvedObjectType) accessingClass, false);
-            argumentTypes[index] = type;
+            type = graalRuntime().lookupType(parameters.get(index), (HotSpotResolvedObjectType) accessingClass, false);
+            parameterTypes[index] = type;
         }
         return type;
     }
@@ -149,4 +163,21 @@
         return "HotSpotSignature<" + originalString + ">";
     }
 
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof HotSpotSignature) {
+            HotSpotSignature other = (HotSpotSignature) obj;
+            if (other.originalString.equals(originalString)) {
+                assert other.parameters.equals(parameters);
+                assert other.returnType.equals(returnType);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return originalString.hashCode();
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java	Mon May 13 17:11:31 2013 +0200
@@ -29,6 +29,7 @@
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.word.*;
 
@@ -38,22 +39,12 @@
  * 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, MonitorReference {
-
-    private final boolean eliminated;
+public final class BeginLockScopeNode extends AbstractStateSplit implements LIRGenLowerable, MonitorEnter {
 
-    private int lockDepth = -1;
+    private int lockDepth;
 
-    public BeginLockScopeNode(boolean eliminated) {
+    public BeginLockScopeNode(int lockDepth) {
         super(StampFactory.forWord());
-        this.eliminated = eliminated;
-    }
-
-    public int getLockDepth() {
-        return lockDepth;
-    }
-
-    public void setLockDepth(int lockDepth) {
         this.lockDepth = lockDepth;
     }
 
@@ -63,8 +54,8 @@
     }
 
     @Override
-    public Object[] getLocationIdentities() {
-        return new Object[]{LocationNode.ANY_LOCATION};
+    public LocationIdentity[] getLocationIdentities() {
+        return new LocationIdentity[]{LocationNode.ANY_LOCATION};
     }
 
     @Override
@@ -72,12 +63,10 @@
         assert lockDepth != -1;
         HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen;
         StackSlot slot = hsGen.getLockSlot(lockDepth);
-        if (!eliminated) {
-            Value result = gen.emitAddress(slot);
-            gen.setResult(this, result);
-        }
+        Value result = gen.emitAddress(slot);
+        gen.setResult(this, result);
     }
 
     @NodeIntrinsic
-    public static native Word beginLockScope(@ConstantNodeParameter boolean eliminated);
+    public static native Word beginLockScope(@ConstantNodeParameter int lockDepth);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CRuntimeCall.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,72 @@
+/*
+ * 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.hotspot.nodes;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.compiler.target.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.type.*;
+
+/**
+ * Implements a direct call to a C/C++ HotSpot function.
+ */
+public class CRuntimeCall extends DeoptimizingFixedWithNextNode implements LIRGenLowerable {
+
+    @Input protected final NodeInputList<ValueNode> arguments;
+
+    private final Descriptor descriptor;
+
+    public CRuntimeCall(Descriptor descriptor, ValueNode... arguments) {
+        super(StampFactory.forKind(Kind.fromJavaClass(descriptor.getResultType())));
+        this.arguments = new NodeInputList<>(this, arguments);
+        this.descriptor = descriptor;
+    }
+
+    @Override
+    public void generate(LIRGenerator gen) {
+        RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(descriptor);
+        Value[] args = new Value[arguments.size()];
+        for (int i = 0; i < args.length; i++) {
+            args[i] = gen.operand(arguments.get(i));
+        }
+        Variable result = gen.emitCall(stub, stub.getCallingConvention(), this, args);
+        if (result != null) {
+            gen.setResult(this, result);
+        }
+    }
+
+    @Override
+    public boolean canDeoptimize() {
+        return true;
+    }
+
+    @Override
+    public DeoptimizationReason getDeoptimizationReason() {
+        return null;
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CStringNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CStringNode.java	Mon May 13 17:11:31 2013 +0200
@@ -51,9 +51,8 @@
             unsafe.putByte(cstring + i, formatBytes[i]);
         }
         unsafe.putByte(cstring + formatBytes.length, (byte) 0);
-        StructuredGraph graph = (StructuredGraph) graph();
-        ConstantNode replacement = ConstantNode.forLong(cstring, graph);
-        graph.replaceFloating(this, replacement);
+        ConstantNode replacement = ConstantNode.forLong(cstring, graph());
+        graph().replaceFloating(this, replacement);
     }
 
     @NodeIntrinsic
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentLockNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentLockNode.java	Mon May 13 17:11:31 2013 +0200
@@ -28,26 +28,18 @@
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.word.*;
 
 /**
  * Intrinsic for getting the lock in the current {@linkplain BeginLockScopeNode lock scope}.
  */
-public final class CurrentLockNode extends FixedWithNextNode implements LIRGenLowerable, MonitorReference {
+public final class CurrentLockNode extends FixedWithNextNode implements LIRGenLowerable {
 
-    private int lockDepth = -1;
+    private int lockDepth;
 
-    public CurrentLockNode() {
+    public CurrentLockNode(int lockDepth) {
         super(StampFactory.forWord());
-    }
-
-    public int getLockDepth() {
-        return lockDepth;
-    }
-
-    public void setLockDepth(int lockDepth) {
         this.lockDepth = lockDepth;
     }
 
@@ -62,5 +54,5 @@
     }
 
     @NodeIntrinsic
-    public static native Word currentLock();
+    public static native Word currentLock(@ConstantNodeParameter int lockDepth);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizeCallerNode.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,55 @@
+/*
+ * 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.hotspot.nodes;
+
+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.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+
+/**
+ * Removes the current frame and tail calls the uncommon trap routine.
+ */
+@NodeInfo(shortName = "DeoptCaller", nameTemplate = "DeoptCaller {p#reason/s}")
+public class DeoptimizeCallerNode extends ControlSinkNode implements LIRLowerable {
+
+    private final DeoptimizationAction action;
+    private final DeoptimizationReason reason;
+
+    public DeoptimizeCallerNode(DeoptimizationAction action, DeoptimizationReason reason) {
+        super(StampFactory.forVoid());
+        this.action = action;
+        this.reason = reason;
+    }
+
+    @Override
+    public void generate(LIRGeneratorTool gen) {
+        ((HotSpotLIRGenerator) gen).emitDeoptimizeCaller(action, reason);
+    }
+
+    @NodeIntrinsic
+    public static native void deopt(@ConstantNodeParameter DeoptimizationAction action, @ConstantNodeParameter DeoptimizationReason reason);
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DirectCompareAndSwapNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DirectCompareAndSwapNode.java	Mon May 13 17:11:31 2013 +0200
@@ -26,14 +26,16 @@
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.word.*;
 
 /**
  * A special purpose store node that differs from {@link CompareAndSwapNode} in that it is not a
- * {@link StateSplit} and it {@linkplain #compareAndSwap(Object, long, Word, Word, Object)} returns
- * either the expected value or the compared against value instead of a boolean.
+ * {@link StateSplit} and it
+ * {@linkplain #compareAndSwap(Object, long, Word, Word, LocationIdentity)} returns either the
+ * expected value or the compared against value instead of a boolean.
  */
 public class DirectCompareAndSwapNode extends FixedWithNextNode implements LIRGenLowerable, MemoryCheckpoint {
 
@@ -42,9 +44,9 @@
     @Input private ValueNode expectedValue;
     @Input private ValueNode newValue;
 
-    private final Object locationIdentity;
+    private final LocationIdentity locationIdentity;
 
-    public DirectCompareAndSwapNode(ValueNode object, ValueNode offset, ValueNode expected, ValueNode newValue, Object locationIdentity) {
+    public DirectCompareAndSwapNode(ValueNode object, ValueNode offset, ValueNode expected, ValueNode newValue, LocationIdentity locationIdentity) {
         super(expected.stamp());
         this.object = object;
         this.offset = offset;
@@ -70,8 +72,8 @@
     }
 
     @Override
-    public Object[] getLocationIdentities() {
-        return new Object[]{locationIdentity};
+    public LocationIdentity[] getLocationIdentities() {
+        return new LocationIdentity[]{locationIdentity};
     }
 
     @Override
@@ -92,5 +94,5 @@
      * @return either {@code expectedValue} or the actual value
      */
     @NodeIntrinsic
-    public static native Word compareAndSwap(Object object, long offset, Word expectedValue, Word newValue, @ConstantNodeParameter Object locationIdentity);
+    public static native Word compareAndSwap(Object object, long offset, Word expectedValue, Word newValue, @ConstantNodeParameter LocationIdentity locationIdentity);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EndLockScopeNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EndLockScopeNode.java	Mon May 13 17:11:31 2013 +0200
@@ -26,6 +26,7 @@
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity;
 import com.oracle.graal.nodes.type.*;
 
 /**
@@ -44,8 +45,8 @@
     }
 
     @Override
-    public Object[] getLocationIdentities() {
-        return new Object[]{LocationNode.ANY_LOCATION};
+    public LocationIdentity[] getLocationIdentities() {
+        return new LocationIdentity[]{LocationNode.ANY_LOCATION};
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotInstalledCodeExecuteNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotInstalledCodeExecuteNode.java	Mon May 13 17:11:31 2013 +0200
@@ -30,6 +30,7 @@
 import com.oracle.graal.hotspot.replacements.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
@@ -47,8 +48,8 @@
     }
 
     @Override
-    public Object[] getLocationIdentities() {
-        return new Object[]{LocationNode.ANY_LOCATION};
+    public LocationIdentity[] getLocationIdentities() {
+        return new LocationIdentity[]{LocationNode.ANY_LOCATION};
     }
 
     @Override
@@ -69,11 +70,11 @@
         ResolvedJavaMethod method = null;
         ResolvedJavaField methodField = null;
         ResolvedJavaField metaspaceMethodField = null;
-        ResolvedJavaField nmethodField = null;
+        ResolvedJavaField codeBlobField = null;
         try {
             method = tool.lookupJavaMethod(HotSpotInstalledCodeExecuteNode.class.getMethod("placeholder", Object.class, Object.class, Object.class));
             methodField = tool.lookupJavaField(HotSpotInstalledCode.class.getDeclaredField("method"));
-            nmethodField = tool.lookupJavaField(HotSpotInstalledCode.class.getDeclaredField("nmethod"));
+            codeBlobField = tool.lookupJavaField(HotSpotInstalledCode.class.getDeclaredField("codeBlob"));
             metaspaceMethodField = tool.lookupJavaField(HotSpotResolvedJavaMethod.class.getDeclaredField("metaspaceMethod"));
         } catch (NoSuchMethodException | SecurityException | NoSuchFieldException e) {
             throw new IllegalStateException(e);
@@ -82,27 +83,26 @@
         for (int i = 0; i < signature.length; i++) {
             signatureTypes[i] = tool.lookupJavaType(signature[i]);
         }
-        final int verifiedEntryPointOffset = HotSpotSnippetUtils.verifiedEntryPointOffset();
+        final int verifiedEntryPointOffset = HotSpotReplacementsUtil.verifiedEntryPointOffset();
 
-        StructuredGraph g = (StructuredGraph) graph();
-
-        LoadFieldNode loadnmethod = g.add(new LoadFieldNode(code, nmethodField));
-        UnsafeLoadNode load = g.add(new UnsafeLoadNode(loadnmethod, verifiedEntryPointOffset, ConstantNode.forLong(0, graph()), graalRuntime().getTarget().wordKind));
+        LoadFieldNode loadCodeBlob = graph().add(new LoadFieldNode(code, codeBlobField));
+        UnsafeLoadNode load = graph().add(new UnsafeLoadNode(loadCodeBlob, verifiedEntryPointOffset, ConstantNode.forLong(0, graph()), graalRuntime().getTarget().wordKind));
 
-        LoadFieldNode loadMethod = g.add(new LoadFieldNode(code, methodField));
-        LoadFieldNode loadmetaspaceMethod = g.add(new LoadFieldNode(loadMethod, metaspaceMethodField));
+        LoadFieldNode loadMethod = graph().add(new LoadFieldNode(code, methodField));
+        LoadFieldNode loadmetaspaceMethod = graph().add(new LoadFieldNode(loadMethod, metaspaceMethodField));
 
-        HotSpotIndirectCallTargetNode callTarget = g.add(new HotSpotIndirectCallTargetNode(loadmetaspaceMethod, load, arguments, stamp(), signatureTypes, method, CallingConvention.Type.JavaCall));
+        HotSpotIndirectCallTargetNode callTarget = graph().add(
+                        new HotSpotIndirectCallTargetNode(loadmetaspaceMethod, load, arguments, stamp(), signatureTypes, method, CallingConvention.Type.JavaCall));
 
-        InvokeNode invoke = g.add(new InvokeNode(callTarget, 0));
+        InvokeNode invoke = graph().add(new InvokeNode(callTarget, 0));
 
         invoke.setStateAfter(stateAfter());
-        g.replaceFixedWithFixed(this, invoke);
+        graph().replaceFixedWithFixed(this, invoke);
 
-        g.addBeforeFixed(invoke, loadmetaspaceMethod);
-        g.addBeforeFixed(loadmetaspaceMethod, loadMethod);
-        g.addBeforeFixed(invoke, load);
-        g.addBeforeFixed(load, loadnmethod);
+        graph().addBeforeFixed(invoke, loadmetaspaceMethod);
+        graph().addBeforeFixed(loadmetaspaceMethod, loadMethod);
+        graph().addBeforeFixed(invoke, load);
+        graph().addBeforeFixed(load, loadCodeBlob);
 
         return invoke;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/IdentityHashCodeStubCall.java	Mon May 13 16:46:39 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-/*
- * 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.hotspot.nodes;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.type.*;
-
-/**
- * Node implementing a call to HotSpot's {@code graal_identityhashcode} stub.
- */
-public class IdentityHashCodeStubCall extends DeoptimizingStubCall implements LIRGenLowerable {
-
-    @Input private final ValueNode object;
-    public static final Descriptor IDENTITY_HASHCODE = new Descriptor("identity_hashcode", false, int.class, Object.class);
-
-    public IdentityHashCodeStubCall(ValueNode object) {
-        super(StampFactory.forKind(Kind.Int));
-        this.object = object;
-    }
-
-    @Override
-    public void generate(LIRGenerator gen) {
-        RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(IdentityHashCodeStubCall.IDENTITY_HASHCODE);
-        Variable result = gen.emitCall(stub, stub.getCallingConvention(), this, gen.operand(object));
-        gen.setResult(this, result);
-    }
-
-    @NodeIntrinsic
-    public static int call(Object object) {
-        return System.identityHashCode(object);
-    }
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/InitializeArrayNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/InitializeArrayNode.java	Mon May 13 17:11:31 2013 +0200
@@ -39,16 +39,14 @@
     @Input private final ValueNode allocationSize;
     private final ResolvedJavaType type;
     private final boolean fillContents;
-    private final boolean locked;
 
-    public InitializeArrayNode(ValueNode memory, ValueNode length, ValueNode allocationSize, ResolvedJavaType type, boolean fillContents, boolean locked) {
+    public InitializeArrayNode(ValueNode memory, ValueNode length, ValueNode allocationSize, ResolvedJavaType type, boolean fillContents) {
         super(StampFactory.exactNonNull(type));
         this.memory = memory;
         this.type = type;
         this.length = length;
         this.allocationSize = allocationSize;
         this.fillContents = fillContents;
-        this.locked = locked;
     }
 
     public ValueNode memory() {
@@ -77,16 +75,11 @@
         return fillContents;
     }
 
-    public boolean locked() {
-        return locked;
-    }
-
     @Override
     public void lower(LoweringTool tool, LoweringType loweringType) {
         tool.getRuntime().lower(this, tool);
     }
 
     @NodeIntrinsic
-    public static native Object initialize(Object memory, int length, int allocationSize, @ConstantNodeParameter ResolvedJavaType type, @ConstantNodeParameter boolean fillContents,
-                    @ConstantNodeParameter boolean locked);
+    public static native Object initialize(Object memory, int length, int allocationSize, @ConstantNodeParameter ResolvedJavaType type, @ConstantNodeParameter boolean fillContents);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/InitializeObjectNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/InitializeObjectNode.java	Mon May 13 17:11:31 2013 +0200
@@ -37,14 +37,12 @@
     @Input private final ValueNode memory;
     private final ResolvedJavaType type;
     private final boolean fillContents;
-    private final boolean locked;
 
-    public InitializeObjectNode(ValueNode memory, ResolvedJavaType type, boolean fillContents, boolean locked) {
+    public InitializeObjectNode(ValueNode memory, ResolvedJavaType type, boolean fillContents) {
         super(StampFactory.exactNonNull(type));
         this.memory = memory;
         this.type = type;
         this.fillContents = fillContents;
-        this.locked = locked;
     }
 
     public ValueNode memory() {
@@ -59,10 +57,6 @@
         return fillContents;
     }
 
-    public boolean locked() {
-        return locked;
-    }
-
     @Override
     public void lower(LoweringTool tool, LoweringType loweringType) {
         tool.getRuntime().lower(this, tool);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/JumpToExceptionHandlerInCallerNode.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,55 @@
+/*
+ * 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.hotspot.nodes;
+
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.word.*;
+
+/**
+ * Sets up the {@linkplain HotSpotBackend#EXCEPTION_HANDLER_IN_CALLER arguments} expected by an
+ * exception handler in the caller's frame, removes the current frame and jumps to said handler.
+ */
+public class JumpToExceptionHandlerInCallerNode extends ControlSinkNode implements LIRLowerable {
+
+    @Input private ValueNode handlerInCallerPc;
+    @Input private ValueNode exception;
+    @Input private ValueNode exceptionPc;
+
+    public JumpToExceptionHandlerInCallerNode(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc) {
+        super(StampFactory.forVoid());
+        this.handlerInCallerPc = handlerInCallerPc;
+        this.exception = exception;
+        this.exceptionPc = exceptionPc;
+    }
+
+    @Override
+    public void generate(LIRGeneratorTool gen) {
+        ((HotSpotLIRGenerator) gen).emitJumpToExceptionHandlerInCaller(handlerInCallerPc, exception, exceptionPc);
+    }
+
+    @NodeIntrinsic
+    public static native void jumpToExceptionHandlerInCaller(Word handlerInCallerPc, Object exception, Word exceptionPc);
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorExitStubCall.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorExitStubCall.java	Mon May 13 17:11:31 2013 +0200
@@ -28,29 +28,21 @@
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.word.*;
 
 /**
  * Node implementing a call to HotSpot's {@code graal_monitorexit} stub.
  */
-public class MonitorExitStubCall extends DeoptimizingStubCall implements LIRGenLowerable, MonitorReference {
+public class MonitorExitStubCall extends DeoptimizingStubCall implements LIRGenLowerable {
 
     @Input private final ValueNode object;
     private int lockDepth;
     public static final Descriptor MONITOREXIT = new Descriptor("monitorexit", true, void.class, Object.class, Word.class);
 
-    public MonitorExitStubCall(ValueNode object) {
+    public MonitorExitStubCall(ValueNode object, int lockDepth) {
         super(StampFactory.forVoid());
         this.object = object;
-    }
-
-    public int getLockDepth() {
-        return lockDepth;
-    }
-
-    public void setLockDepth(int lockDepth) {
         this.lockDepth = lockDepth;
     }
 
@@ -64,5 +56,5 @@
     }
 
     @NodeIntrinsic
-    public static native void call(Object hub);
+    public static native void call(Object hub, @ConstantNodeParameter int lockDepth);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArraySlowStubCall.java	Mon May 13 16:46:39 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-/*
- * 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.hotspot.nodes;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
-import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.word.*;
-
-/**
- * Node implementing a call to the {@code new_array} stub.
- */
-public class NewArraySlowStubCall extends DeoptimizingStubCall implements LIRGenLowerable {
-
-    private static final Stamp defaultStamp = StampFactory.objectNonNull();
-
-    @Input private final ValueNode hub;
-    @Input private final ValueNode length;
-
-    public static final Descriptor NEW_ARRAY_SLOW = new Descriptor("new_array_slow", false, Object.class, Word.class, int.class);
-
-    public NewArraySlowStubCall(ValueNode hub, ValueNode length) {
-        super(defaultStamp);
-        this.hub = hub;
-        this.length = length;
-    }
-
-    @Override
-    public boolean inferStamp() {
-        if (stamp() == defaultStamp && hub.isConstant()) {
-            updateStamp(StampFactory.exactNonNull(HotSpotResolvedObjectType.fromMetaspaceKlass(hub.asConstant())));
-            return true;
-        }
-        return false;
-    }
-
-    @Override
-    public void generate(LIRGenerator gen) {
-        RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(NEW_ARRAY_SLOW);
-        Variable result = gen.emitCall(stub, stub.getCallingConvention(), this, gen.operand(hub), gen.operand(length));
-        gen.setResult(this, result);
-    }
-
-    @NodeIntrinsic
-    public static native Object call(Word hub, int length);
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceSlowStubCall.java	Mon May 13 16:46:39 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,69 +0,0 @@
-/*
- * 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.hotspot.nodes;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
-import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.word.*;
-
-/**
- * Node implementing a call to HotSpot's {@code new_instance} stub.
- */
-public class NewInstanceSlowStubCall extends DeoptimizingStubCall implements LIRGenLowerable {
-
-    private static final Stamp defaultStamp = StampFactory.objectNonNull();
-
-    @Input private final ValueNode hub;
-
-    public static final Descriptor NEW_INSTANCE_SLOW = new Descriptor("new_instance_slow", false, Object.class, Word.class);
-
-    public NewInstanceSlowStubCall(ValueNode hub) {
-        super(defaultStamp);
-        this.hub = hub;
-    }
-
-    @Override
-    public boolean inferStamp() {
-        if (stamp() == defaultStamp && hub.isConstant()) {
-            updateStamp(StampFactory.exactNonNull(HotSpotResolvedObjectType.fromMetaspaceKlass(hub.asConstant())));
-            return true;
-        }
-        return false;
-    }
-
-    @Override
-    public void generate(LIRGenerator gen) {
-        RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(NEW_INSTANCE_SLOW);
-        Variable result = gen.emitCall(stub, stub.getCallingConvention(), this, gen.operand(hub));
-        gen.setResult(this, result);
-    }
-
-    @NodeIntrinsic
-    public static native Object call(Word hub);
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewMultiArrayStubCall.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewMultiArrayStubCall.java	Mon May 13 17:11:31 2013 +0200
@@ -28,13 +28,14 @@
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.word.*;
 
 /**
- * Node implementing a call to HotSpot's {@code new_multi_array} stub.
+ * Node implementing a call to {@link NewMultiArrayStub}.
  */
 public class NewMultiArrayStubCall extends DeoptimizingStubCall implements LIRGenLowerable {
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/PatchReturnAddressNode.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,50 @@
+/*
+ * 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.hotspot.nodes;
+
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.word.*;
+
+/**
+ * Modifies the return address of the current frame.
+ */
+public class PatchReturnAddressNode extends FixedWithNextNode implements LIRLowerable {
+
+    @Input private ValueNode address;
+
+    public PatchReturnAddressNode(ValueNode address) {
+        super(StampFactory.forVoid());
+        this.address = address;
+    }
+
+    @Override
+    public void generate(LIRGeneratorTool gen) {
+        ((HotSpotLIRGenerator) gen).emitPatchReturnAddress(address);
+    }
+
+    @NodeIntrinsic
+    public static native void patchReturnAddress(Word address);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/StubStartNode.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,42 @@
+/*
+ * 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.hotspot.nodes;
+
+import com.oracle.graal.hotspot.stubs.*;
+import com.oracle.graal.nodes.*;
+
+/**
+ * Start node for a {@link Stub}'s graph.
+ */
+public class StubStartNode extends StartNode {
+
+    private final Stub stub;
+
+    public StubStartNode(Stub stub) {
+        this.stub = stub;
+    }
+
+    public Stub getStub() {
+        return stub;
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ThreadIsInterruptedStubCall.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ThreadIsInterruptedStubCall.java	Mon May 13 17:11:31 2013 +0200
@@ -30,12 +30,13 @@
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.graph.*;
+import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.type.*;
 
 /**
- * Node implementing a call to HotSpot's ThreadIsInterrupted stub.
+ * Node implementing a call to {@link ThreadIsInterruptedStub}.
  */
 public class ThreadIsInterruptedStubCall extends DeoptimizingStubCall implements LIRGenLowerable {
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VMErrorNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VMErrorNode.java	Mon May 13 17:11:31 2013 +0200
@@ -27,7 +27,6 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.target.*;
-import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.replacements.*;
@@ -38,11 +37,11 @@
  */
 public final class VMErrorNode extends DeoptimizingStubCall implements LIRGenLowerable {
 
-    @Input private ValueNode format;
+    private final String format;
     @Input private ValueNode value;
     public static final Descriptor VM_ERROR = new Descriptor("vm_error", false, void.class, Object.class, Object.class, long.class);
 
-    public VMErrorNode(ValueNode format, ValueNode value) {
+    private VMErrorNode(String format, ValueNode value) {
         super(StampFactory.forVoid());
         this.format = format;
         this.value = value;
@@ -50,21 +49,19 @@
 
     @Override
     public void generate(LIRGenerator gen) {
-        String where = "in compiled code for " + MetaUtil.format("%H.%n(%p)", gen.method());
+        String whereString = "in compiled code for " + graph();
 
-        HotSpotRuntime runtime = (HotSpotRuntime) gen.getRuntime();
-        Constant whereArg = Constant.forObject(runtime.registerGCRoot(where));
-        Value formatArg;
-        if (format.isConstant() && format.kind() == Kind.Object) {
-            formatArg = Constant.forObject(runtime.registerGCRoot(format.asConstant().asObject()));
-        } else {
-            formatArg = gen.operand(format);
-        }
+        // As these strings will end up embedded as oops in the code, they
+        // must be interned or else they will cause the nmethod to be unloaded
+        // (nmethods are a) weak GC roots and b) unloaded if any of their
+        // embedded oops become unreachable).
+        Constant whereArg = Constant.forObject(whereString.intern());
+        Constant formatArg = Constant.forObject(format.intern());
 
         RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(VMErrorNode.VM_ERROR);
         gen.emitCall(stub, stub.getCallingConvention(), null, whereArg, formatArg, gen.operand(value));
     }
 
     @NodeIntrinsic
-    public static native void vmError(String format, long value);
+    public static native void vmError(@ConstantNodeParameter String format, long value);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VerifyOopStubCall.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VerifyOopStubCall.java	Mon May 13 17:11:31 2013 +0200
@@ -26,16 +26,17 @@
 import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.target.*;
+import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.type.*;
 
 /**
- * Node implementing a call to HotSpot's object pointer verification stub.
+ * Call to {@link VerifyOopStub}.
  */
 public class VerifyOopStubCall extends DeoptimizingStubCall implements LIRGenLowerable {
 
     @Input private final ValueNode object;
-    public static final Descriptor VERIFY_OOP = new Descriptor("verify_oop", false, void.class, Object.class);
+    public static final Descriptor VERIFY_OOP = new Descriptor("verify_oop", false, Object.class, Object.class);
 
     public VerifyOopStubCall(ValueNode object) {
         super(StampFactory.objectNonNull());
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrierPostStubCall.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrierPostStubCall.java	Mon May 13 17:11:31 2013 +0200
@@ -26,18 +26,19 @@
 import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.target.*;
+import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.word.*;
 
 /**
- * Node implementing a call to HotSpot's {@code graal_monitorenter} stub.
+ * Node implementing a call to {@link WriteBarrierPostStub}.
  */
 public class WriteBarrierPostStubCall extends FixedWithNextNode implements LIRGenLowerable {
 
     @Input private ValueNode object;
     @Input private ValueNode card;
-    public static final Descriptor WBPOSTCALL = new Descriptor("wbpostcall", true, void.class, Object.class, Word.class);
+    public static final Descriptor WRITE_BARRIER_POST = new Descriptor("writeBarrierPost", true, void.class, Object.class, Word.class);
 
     public WriteBarrierPostStubCall(ValueNode object, ValueNode card) {
         super(StampFactory.forVoid());
@@ -47,7 +48,7 @@
 
     @Override
     public void generate(LIRGenerator gen) {
-        RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(WriteBarrierPostStubCall.WBPOSTCALL);
+        RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(WriteBarrierPostStubCall.WRITE_BARRIER_POST);
         gen.emitCall(stub, stub.getCallingConvention(), null, gen.operand(object), gen.operand(card));
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrierPreStubCall.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrierPreStubCall.java	Mon May 13 17:11:31 2013 +0200
@@ -26,16 +26,17 @@
 import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.target.*;
+import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.type.*;
 
 /**
- * Node implementing a call to HotSpot's {@code graal_monitorenter} stub.
+ * Node implementing a call to {@link WriteBarrierPreStub}.
  */
 public class WriteBarrierPreStubCall extends FixedWithNextNode implements LIRGenLowerable {
 
     @Input private ValueNode object;
-    public static final Descriptor WBPRECALL = new Descriptor("wbprecall", true, void.class, Object.class);
+    public static final Descriptor WRITE_BARRIER_PRE = new Descriptor("writeBarrierPre", true, void.class, Object.class);
 
     public WriteBarrierPreStubCall(ValueNode object) {
         super(StampFactory.forVoid());
@@ -44,7 +45,7 @@
 
     @Override
     public void generate(LIRGenerator gen) {
-        RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(WriteBarrierPreStubCall.WBPRECALL);
+        RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(WriteBarrierPreStubCall.WRITE_BARRIER_PRE);
         gen.emitCall(stub, stub.getCallingConvention(), null, gen.operand(object));
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/OnStackReplacementPhase.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/OnStackReplacementPhase.java	Mon May 13 17:11:31 2013 +0200
@@ -22,20 +22,14 @@
  */
 package com.oracle.graal.hotspot.phases;
 
-import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
-
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.RuntimeCallTarget.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.Node.*;
+import com.oracle.graal.graph.Node.Verbosity;
 import com.oracle.graal.graph.iterators.*;
-import com.oracle.graal.java.*;
 import com.oracle.graal.loop.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.*;
@@ -43,29 +37,6 @@
 
 public class OnStackReplacementPhase extends Phase {
 
-    public static final Descriptor OSR_MIGRATION_END = new Descriptor("OSR_migration_end", true, void.class, long.class);
-
-    public class OSREntryProxyNode extends FloatingNode implements LIRLowerable {
-
-        @Input private ValueNode object;
-        @Input(notDataflow = true) private final RuntimeCallNode anchor;
-
-        public OSREntryProxyNode(ValueNode object, RuntimeCallNode anchor) {
-            super(object.stamp());
-            this.object = object;
-            this.anchor = anchor;
-        }
-
-        public RuntimeCallNode getAnchor() {
-            return anchor;
-        }
-
-        @Override
-        public void generate(LIRGeneratorTool generator) {
-            generator.setResult(this, generator.operand(object));
-        }
-    }
-
     @Override
     protected void run(StructuredGraph graph) {
         if (graph.getEntryBCI() == StructuredGraph.INVOCATION_ENTRY_BCI) {
@@ -114,39 +85,29 @@
             Debug.dump(graph, "OnStackReplacement loop peeling result");
         } while (true);
 
-        LocalNode buffer = graph.unique(new LocalNode(0, StampFactory.forKind(wordKind())));
-        RuntimeCallNode migrationEnd = graph.add(new RuntimeCallNode(OSR_MIGRATION_END, buffer));
         FrameState osrState = osr.stateAfter();
-        migrationEnd.setStateAfter(osrState);
         osr.setStateAfter(null);
-
+        OSRStartNode osrStart = graph.add(new OSRStartNode());
         StartNode start = graph.start();
-        FixedNode rest = start.next();
-        start.setNext(migrationEnd);
         FixedNode next = osr.next();
         osr.setNext(null);
-        migrationEnd.setNext(next);
+        osrStart.setNext(next);
+        graph.setStart(osrStart);
+        osrStart.setStateAfter(osrState);
 
-        FrameState oldStartState = start.stateAfter();
-        start.setStateAfter(null);
-        GraphUtil.killWithUnusedFloatingInputs(oldStartState);
-
-        // mirroring the calculations in c1_GraphBuilder.cpp (setup_osr_entry_block)
-        int localsOffset = (graph.method().getMaxLocals() - 1) * 8;
         for (int i = 0; i < osrState.localsSize(); i++) {
             ValueNode value = osrState.localAt(i);
             if (value != null) {
                 ProxyNode proxy = (ProxyNode) value;
-                int size = FrameStateBuilder.stackSlots(value.kind());
-                int offset = localsOffset - (i + size - 1) * 8;
-                UnsafeLoadNode load = graph.add(new UnsafeLoadNode(buffer, offset, ConstantNode.forInt(0, graph), value.kind()));
-                OSREntryProxyNode newProxy = graph.add(new OSREntryProxyNode(load, migrationEnd));
-                proxy.replaceAndDelete(newProxy);
-                graph.addBeforeFixed(migrationEnd, load);
+                /*
+                 * we need to drop the stamp and go back to the kind since the types we see during
+                 * OSR may be too precise (if a branch was not parsed for example).
+                 */
+                proxy.replaceAndDelete(graph.unique(new OSRLocalNode(i, StampFactory.forKind(proxy.kind()))));
             }
         }
 
-        GraphUtil.killCFG(rest);
+        GraphUtil.killCFG(start);
 
         Debug.dump(graph, "OnStackReplacement result");
         new DeadCodeEliminationPhase().apply(graph);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierVerificationPhase.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierVerificationPhase.java	Mon May 13 17:11:31 2013 +0200
@@ -31,193 +31,94 @@
 import com.oracle.graal.nodes.extended.WriteNode.WriteBarrierType;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.graph.*;
 
+/**
+ * Verification phase that checks if, for every write, at least one write barrier is present at all
+ * paths leading to the previous safepoint. For every write, necessitating a write barrier, a
+ * bottom-up traversal of the graph is performed up to the previous safepoints via all possible
+ * paths. If, for a certain path, no write barrier satisfying the processed write is found, an
+ * assertion is generated.
+ */
 public class WriteBarrierVerificationPhase extends Phase {
 
-    private class MemoryMap implements MergeableState<MemoryMap> {
-
-        private IdentityHashMap<Object, LinkedList<LocationNode>> lastMemorySnapshot;
-        private IdentityHashMap<Object, LinkedList<SerialWriteBarrier>> lastWriteBarrierSnapshot;
-
-        public MemoryMap(MemoryMap memoryMap) {
-            lastMemorySnapshot = new IdentityHashMap<>(memoryMap.lastMemorySnapshot);
-            lastWriteBarrierSnapshot = new IdentityHashMap<>(memoryMap.lastWriteBarrierSnapshot);
-        }
-
-        public MemoryMap() {
-            lastMemorySnapshot = new IdentityHashMap<>();
-            lastWriteBarrierSnapshot = new IdentityHashMap<>();
-        }
-
-        @Override
-        public String toString() {
-            return "Map=" + lastMemorySnapshot.toString();
-        }
-
-        @Override
-        public boolean merge(MergeNode merge, List<MemoryMap> withStates) {
-            if (withStates.size() == 0) {
-                return true;
-            }
+    @Override
+    protected void run(StructuredGraph graph) {
+        processWrites(graph);
+    }
 
-            for (MemoryMap other : withStates) {
-                for (Object otherObject : other.lastMemorySnapshot.keySet()) {
-                    LinkedList<LocationNode> currentLocations = lastMemorySnapshot.get(otherObject);
-                    LinkedList<LocationNode> otherLocations = other.lastMemorySnapshot.get(otherObject);
-                    if (otherLocations != null) {
-                        if (currentLocations == null) {
-                            currentLocations = new LinkedList<>();
-                        }
-                        for (LocationNode location : otherLocations) {
-                            if (!currentLocations.contains(location)) {
-                                currentLocations.add(location);
-                            }
-                        }
-                    }
-                }
-                for (Object otherObject : other.lastWriteBarrierSnapshot.keySet()) {
-                    LinkedList<SerialWriteBarrier> currentWriteBarriers = lastWriteBarrierSnapshot.get(otherObject);
-                    LinkedList<SerialWriteBarrier> otherWriteBarriers = other.lastWriteBarrierSnapshot.get(otherObject);
-                    if (otherWriteBarriers != null) {
-                        if (currentWriteBarriers == null) {
-                            currentWriteBarriers = new LinkedList<>();
-                        }
-                        for (SerialWriteBarrier barrier : otherWriteBarriers) {
-                            if (!currentWriteBarriers.contains(barrier)) {
-                                currentWriteBarriers.add(barrier);
-                            }
-                        }
-                    }
-                }
+    private static void processWrites(StructuredGraph graph) {
+        for (Node node : graph.getNodes()) {
+            if (isObjectWrite(node)) {
+                validateWrite(node);
             }
-            return true;
-        }
-
-        @Override
-        public void loopBegin(LoopBeginNode loopBegin) {
-        }
-
-        @Override
-        public void loopEnds(LoopBeginNode loopBegin, List<MemoryMap> loopEndStates) {
-        }
-
-        @Override
-        public void afterSplit(BeginNode node) {
-        }
-
-        @Override
-        public MemoryMap clone() {
-            return new MemoryMap(this);
         }
     }
 
-    @Override
-    protected void run(StructuredGraph graph) {
-        new PostOrderNodeIterator<MemoryMap>(graph.start(), new MemoryMap()) {
-
-            @Override
-            protected void node(FixedNode node) {
-                processNode(node, state);
-            }
-        }.apply();
-    }
-
-    private static void processNode(FixedNode node, MemoryMap state) {
-        if (node instanceof WriteNode) {
-            processWriteNode((WriteNode) node, state);
-        } else if (node instanceof CompareAndSwapNode) {
-            processCASNode((CompareAndSwapNode) node, state);
-        } else if (node instanceof SerialWriteBarrier) {
-            processWriteBarrier((SerialWriteBarrier) node, state);
-        } else if ((node instanceof DeoptimizingNode)) {
-            if (((DeoptimizingNode) node).canDeoptimize()) {
-                validateWriteBarriers(state);
-                processSafepoint(state);
+    private static void validateWrite(Node write) {
+        /*
+         * The currently validated write is checked in order to discover if it has an appropriate
+         * attached write barrier.
+         */
+        if (hasAttachedBarrier(write)) {
+            return;
+        }
+        NodeFlood frontier = write.graph().createNodeFlood();
+        expandFrontier(frontier, write);
+        Iterator<Node> iterator = frontier.iterator();
+        while (iterator.hasNext()) {
+            Node currentNode = iterator.next();
+            assert !isSafepoint(currentNode) : "Write barrier must be present";
+            if (!(currentNode instanceof SerialWriteBarrier) || ((currentNode instanceof SerialWriteBarrier) && !validateBarrier(write, (SerialWriteBarrier) currentNode))) {
+                expandFrontier(frontier, currentNode);
             }
         }
     }
 
-    private static void processWriteNode(WriteNode node, MemoryMap state) {
-        if (node.getWriteBarrierType() != WriteBarrierType.NONE) {
-            LinkedList<LocationNode> locations = state.lastMemorySnapshot.get(node.object());
-            if (locations == null) {
-                locations = new LinkedList<>();
-                locations.add(node.location());
-                state.lastMemorySnapshot.put(node.object(), locations);
-            } else if ((node.getWriteBarrierType() == WriteBarrierType.PRECISE) && !locations.contains(node.location())) {
-                locations.add(node.location());
-            }
-        }
+    private static boolean hasAttachedBarrier(Node node) {
+        return (((FixedWithNextNode) node).next() instanceof SerialWriteBarrier) && validateBarrier(node, (SerialWriteBarrier) ((FixedWithNextNode) node).next());
     }
 
-    private static void processCASNode(CompareAndSwapNode node, MemoryMap state) {
-        if (node.getWriteBarrierType() != WriteBarrierType.NONE) {
-            LinkedList<LocationNode> locations = state.lastMemorySnapshot.get(node.object());
-            if (locations == null) {
-                locations = new LinkedList<>();
-                locations.add(node.getLocation());
-                state.lastMemorySnapshot.put(node.object(), locations);
-            } else if ((node.getWriteBarrierType() == WriteBarrierType.PRECISE) && !locations.contains(node.getLocation())) {
-                locations.add(node.getLocation());
+    private static boolean isObjectWrite(Node node) {
+        if ((node instanceof WriteNode && (((WriteNode) node).getWriteBarrierType() != WriteBarrierType.NONE)) ||
+                        (node instanceof CompareAndSwapNode && (((CompareAndSwapNode) node).getWriteBarrierType() != WriteBarrierType.NONE))) {
+            return true;
+        }
+        return false;
+    }
+
+    private static void expandFrontier(NodeFlood frontier, Node node) {
+        for (Node previousNode : node.cfgPredecessors()) {
+            if (previousNode != null) {
+                frontier.add(previousNode);
             }
         }
     }
 
-    private static void processWriteBarrier(SerialWriteBarrier currentBarrier, MemoryMap state) {
-        LinkedList<SerialWriteBarrier> writeBarriers = state.lastWriteBarrierSnapshot.get(currentBarrier.getObject());
-        if (writeBarriers == null) {
-            writeBarriers = new LinkedList<>();
-            writeBarriers.add(currentBarrier);
-            state.lastWriteBarrierSnapshot.put(currentBarrier.getObject(), writeBarriers);
-        } else if (currentBarrier.usePrecise()) {
-            boolean found = false;
-            for (SerialWriteBarrier barrier : writeBarriers) {
-                if (barrier.getLocation() == currentBarrier.getLocation()) {
-                    found = true;
-                    break;
-                }
-            }
-            if (!found) {
-                writeBarriers.add(currentBarrier);
-            }
-        }
+    private static boolean isSafepoint(Node node) {
+        /*
+         * LoopBegin nodes are also treated as safepoints since a bottom-up analysis is performed
+         * and loop safepoints are placed before LoopEnd nodes. Possible elimination of write
+         * barriers inside loops, derived from writes outside loops, can not be permitted.
+         */
+        return ((node instanceof DeoptimizingNode) && ((DeoptimizingNode) node).canDeoptimize()) || (node instanceof LoopBeginNode);
     }
 
-    private static void validateWriteBarriers(MemoryMap state) {
-        Set<Object> objects = state.lastMemorySnapshot.keySet();
-        for (Object write : objects) {
-            LinkedList<SerialWriteBarrier> writeBarriers = state.lastWriteBarrierSnapshot.get(write);
-            if (writeBarriers == null) {
-                throw new GraalInternalError("Failed to find any write barrier at safepoint for written object");
-            }
-            /*
-             * Check the first write barrier of the object to determine if it is precise or not. If
-             * it is not, the validation for this object has passed (since we had a hit in the write
-             * barrier hashmap), otherwise we have to ensure the presence of write barriers for
-             * every written location.
-             */
-            final boolean precise = writeBarriers.getFirst().usePrecise();
-            if (precise) {
-                LinkedList<LocationNode> locations = state.lastMemorySnapshot.get(write);
-                for (LocationNode location : locations) {
-                    boolean found = false;
-                    for (SerialWriteBarrier barrier : writeBarriers) {
-                        if (location == barrier.getLocation()) {
-                            found = true;
-                            break;
-                        }
-                    }
-                    if (!found) {
-                        throw new GraalInternalError("Failed to find write barrier at safepoint for precise written object");
-                    }
-                }
-            }
+    private static boolean validateBarrier(Node write, SerialWriteBarrier barrier) {
+        ValueNode writtenObject = null;
+        LocationNode writtenLocation = null;
+        if (write instanceof WriteNode) {
+            writtenObject = ((WriteNode) write).object();
+            writtenLocation = ((WriteNode) write).location();
+        } else if (write instanceof CompareAndSwapNode) {
+            writtenObject = ((CompareAndSwapNode) write).object();
+            writtenLocation = ((CompareAndSwapNode) write).getLocation();
+        } else {
+            assert false : "Node must be of type requiring a write barrier";
         }
-    }
 
-    private static void processSafepoint(MemoryMap state) {
-        state.lastMemorySnapshot.clear();
-        state.lastWriteBarrierSnapshot.clear();
+        if ((barrier.getObject() == writtenObject) && (!barrier.usePrecise() || (barrier.usePrecise() && barrier.getLocation() == writtenLocation))) {
+            return true;
+        }
+        return false;
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AESCryptSubstitutions.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AESCryptSubstitutions.java	Mon May 13 17:11:31 2013 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
-import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*;
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 import sun.misc.*;
 
 import com.oracle.graal.api.code.*;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopySnippets.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopySnippets.java	Mon May 13 17:11:31 2013 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
-import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*;
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 import static com.oracle.graal.replacements.nodes.BranchProbabilityNode.*;
 
 import java.lang.reflect.*;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CallSiteTargetNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CallSiteTargetNode.java	Mon May 13 17:11:31 2013 +0200
@@ -67,13 +67,12 @@
 
     @Override
     public void lower(LoweringTool tool, LoweringType loweringType) {
-        StructuredGraph graph = (StructuredGraph) graph();
         ConstantNode target = getConstantCallTarget(tool.getRuntime(), tool.assumptions());
 
         if (target != null) {
-            graph.replaceFixedWithFloating(this, target);
+            graph().replaceFixedWithFloating(this, target);
         } else {
-            graph.replaceFixedWithFixed(this, createInvoke());
+            graph().replaceFixedWithFixed(this, createInvoke());
         }
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CheckCastSnippets.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CheckCastSnippets.java	Mon May 13 17:11:31 2013 +0200
@@ -24,7 +24,7 @@
 
 import static com.oracle.graal.api.code.DeoptimizationAction.*;
 import static com.oracle.graal.api.meta.DeoptimizationReason.*;
-import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*;
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 import static com.oracle.graal.hotspot.replacements.TypeCheckSnippetUtils.*;
 import static com.oracle.graal.nodes.extended.UnsafeCastNode.*;
 import static com.oracle.graal.replacements.SnippetTemplate.*;
@@ -164,7 +164,7 @@
          * Lowers a checkcast node.
          */
         public void lower(CheckCastNode checkcast, LoweringTool tool) {
-            StructuredGraph graph = (StructuredGraph) checkcast.graph();
+            StructuredGraph graph = checkcast.graph();
             ValueNode object = checkcast.object();
             HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) checkcast.type();
             TypeCheckHints hintInfo = new TypeCheckHints(checkcast.type(), checkcast.profile(), tool.assumptions(), GraalOptions.CheckcastMinHintHitProbability, GraalOptions.CheckcastMaxHints);
@@ -200,7 +200,7 @@
          * Lowers a dynamic checkcast node.
          */
         public void lower(CheckCastDynamicNode checkcast) {
-            StructuredGraph graph = (StructuredGraph) checkcast.graph();
+            StructuredGraph graph = checkcast.graph();
             ValueNode object = checkcast.object();
 
             Arguments args = new Arguments(dynamic);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java	Mon May 13 17:11:31 2013 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
-import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*;
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 import sun.misc.*;
 
 import com.oracle.graal.api.code.*;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ClassSubstitutions.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ClassSubstitutions.java	Mon May 13 17:11:31 2013 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
-import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*;
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 import static com.oracle.graal.nodes.extended.UnsafeCastNode.*;
 
 import java.lang.reflect.*;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,687 @@
+/*
+ * 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.hotspot.replacements;
+
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+import static com.oracle.graal.replacements.nodes.BranchProbabilityNode.*;
+import sun.misc.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.Node.ConstantNodeParameter;
+import com.oracle.graal.graph.Node.NodeIntrinsic;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity;
+import com.oracle.graal.replacements.Snippet.Fold;
+import com.oracle.graal.replacements.nodes.*;
+import com.oracle.graal.word.*;
+
+//JaCoCo Exclude
+
+/**
+ * A collection of methods used in HotSpot snippets, substitutions and stubs.
+ */
+public class HotSpotReplacementsUtil {
+
+    public static final LocationIdentity ANY_LOCATION = LocationNode.ANY_LOCATION;
+    public static final LocationIdentity FINAL_LOCATION = LocationNode.FINAL_LOCATION;
+
+    public static HotSpotVMConfig config() {
+        return graalRuntime().getConfig();
+    }
+
+    @Fold
+    public static boolean useTLAB() {
+        return config().useTLAB;
+    }
+
+    @Fold
+    public static boolean verifyOops() {
+        return config().verifyOops;
+    }
+
+    public static final LocationIdentity EXCEPTION_OOP_LOCATION = LocationNode.createLocation("ExceptionOop");
+
+    /**
+     * @see HotSpotVMConfig#threadExceptionOopOffset
+     */
+    @Fold
+    public static int threadExceptionOopOffset() {
+        return config().threadExceptionOopOffset;
+    }
+
+    public static final LocationIdentity EXCEPTION_PC_LOCATION = LocationNode.createLocation("ExceptionPc");
+
+    @Fold
+    public static int threadExceptionPcOffset() {
+        return config().threadExceptionPcOffset;
+    }
+
+    public static final LocationIdentity TLAB_TOP_LOCATION = LocationNode.createLocation("TlabTop");
+
+    @Fold
+    public static int threadTlabTopOffset() {
+        return config().threadTlabTopOffset;
+    }
+
+    public static final LocationIdentity TLAB_END_LOCATION = LocationNode.createLocation("TlabEnd");
+
+    @Fold
+    private static int threadTlabEndOffset() {
+        return config().threadTlabEndOffset;
+    }
+
+    public static final LocationIdentity TLAB_START_LOCATION = LocationNode.createLocation("TlabStart");
+
+    @Fold
+    private static int threadTlabStartOffset() {
+        return config().threadTlabStartOffset;
+    }
+
+    public static final LocationIdentity PENDING_EXCEPTION_LOCATION = LocationNode.createLocation("PendingException");
+
+    /**
+     * @see HotSpotVMConfig#pendingExceptionOffset
+     */
+    @Fold
+    private static int threadPendingExceptionOffset() {
+        return config().pendingExceptionOffset;
+    }
+
+    public static final LocationIdentity OBJECT_RESULT_LOCATION = LocationNode.createLocation("ObjectResult");
+
+    @Fold
+    private static int objectResultOffset() {
+        return config().threadObjectResultOffset;
+    }
+
+    /**
+     * @see HotSpotVMConfig#threadExceptionOopOffset
+     */
+    public static Object readExceptionOop(Word thread) {
+        return thread.readObject(threadExceptionOopOffset(), EXCEPTION_OOP_LOCATION);
+    }
+
+    public static Word readExceptionPc(Word thread) {
+        return thread.readWord(threadExceptionPcOffset(), EXCEPTION_PC_LOCATION);
+    }
+
+    /**
+     * @see HotSpotVMConfig#threadExceptionOopOffset
+     */
+    public static void writeExceptionOop(Word thread, Object value) {
+        thread.writeObject(threadExceptionOopOffset(), value, EXCEPTION_OOP_LOCATION);
+    }
+
+    public static void writeExceptionPc(Word thread, Word value) {
+        thread.writeWord(threadExceptionPcOffset(), value, EXCEPTION_PC_LOCATION);
+    }
+
+    public static Word readTlabTop(Word thread) {
+        return thread.readWord(threadTlabTopOffset(), TLAB_TOP_LOCATION);
+    }
+
+    public static Word readTlabEnd(Word thread) {
+        return thread.readWord(threadTlabEndOffset(), TLAB_END_LOCATION);
+    }
+
+    public static Word readTlabStart(Word thread) {
+        return thread.readWord(threadTlabStartOffset(), TLAB_START_LOCATION);
+    }
+
+    public static void writeTlabTop(Word thread, Word top) {
+        thread.writeWord(threadTlabTopOffset(), top, TLAB_TOP_LOCATION);
+    }
+
+    public static void initializeTlab(Word thread, Word start, Word end) {
+        thread.writeWord(threadTlabStartOffset(), start, TLAB_START_LOCATION);
+        thread.writeWord(threadTlabTopOffset(), start, TLAB_TOP_LOCATION);
+        thread.writeWord(threadTlabEndOffset(), end, TLAB_END_LOCATION);
+    }
+
+    /**
+     * Clears the pending exception for the given thread.
+     * 
+     * @return {@code true} if there was a pending exception
+     */
+    public static boolean clearPendingException(Word thread) {
+        boolean result = thread.readObject(threadPendingExceptionOffset(), PENDING_EXCEPTION_LOCATION) != null;
+        thread.writeObject(threadPendingExceptionOffset(), null);
+        return result;
+    }
+
+    /**
+     * Gets and clears the object result from a runtime call stored in a thread local.
+     * 
+     * @return the object that was in the thread local
+     */
+    public static Object getAndClearObjectResult(Word thread) {
+        Object result = thread.readObject(objectResultOffset(), OBJECT_RESULT_LOCATION);
+        thread.writeObject(objectResultOffset(), null);
+        return result;
+    }
+
+    @Fold
+    public static int threadObjectOffset() {
+        return config().threadObjectOffset;
+    }
+
+    @Fold
+    public static int osThreadOffset() {
+        return config().osThreadOffset;
+    }
+
+    @Fold
+    public static int osThreadInterruptedOffset() {
+        return config().osThreadInterruptedOffset;
+    }
+
+    @Fold
+    public static Kind wordKind() {
+        return graalRuntime().getTarget().wordKind;
+    }
+
+    @Fold
+    public static Register threadRegister() {
+        return graalRuntime().getRuntime().threadRegister();
+    }
+
+    @Fold
+    public static Register stackPointerRegister() {
+        return graalRuntime().getRuntime().stackPointerRegister();
+    }
+
+    @Fold
+    public static int wordSize() {
+        return graalRuntime().getTarget().wordSize;
+    }
+
+    @Fold
+    public static int pageSize() {
+        return Unsafe.getUnsafe().pageSize();
+    }
+
+    public static final LocationIdentity PROTOTYPE_MARK_WORD_LOCATION = LocationNode.createLocation("PrototypeMarkWord");
+
+    @Fold
+    public static int prototypeMarkWordOffset() {
+        return config().prototypeMarkWordOffset;
+    }
+
+    @Fold
+    public static long arrayPrototypeMarkWord() {
+        return config().arrayPrototypeMarkWord;
+    }
+
+    @Fold
+    public static int klassAccessFlagsOffset() {
+        return config().klassAccessFlagsOffset;
+    }
+
+    @Fold
+    private static int klassLayoutHelperOffset() {
+        return config().klassLayoutHelperOffset;
+    }
+
+    public static int readLayoutHelper(Word hub) {
+        return hub.readInt(klassLayoutHelperOffset(), FINAL_LOCATION);
+    }
+
+    @Fold
+    public static int arrayKlassLayoutHelperIdentifier() {
+        return config().arrayKlassLayoutHelperIdentifier;
+    }
+
+    @Fold
+    public static int arrayKlassComponentMirrorOffset() {
+        return config().arrayKlassComponentMirrorOffset;
+    }
+
+    @Fold
+    public static int klassSuperKlassOffset() {
+        return config().klassSuperKlassOffset;
+    }
+
+    public static final LocationIdentity MARK_WORD_LOCATION = LocationNode.createLocation("MarkWord");
+
+    @Fold
+    public static int markOffset() {
+        return config().markOffset;
+    }
+
+    public static final LocationIdentity HUB_LOCATION = LocationNode.createLocation("Hub");
+
+    @Fold
+    private static int hubOffset() {
+        return config().hubOffset;
+    }
+
+    public static void initializeObjectHeader(Word memory, Word markWord, Word hub) {
+        memory.writeWord(markOffset(), markWord, MARK_WORD_LOCATION);
+        memory.writeWord(hubOffset(), hub, HUB_LOCATION);
+    }
+
+    @Fold
+    public static int unlockedMask() {
+        return config().unlockedMask;
+    }
+
+    /**
+     * Mask for a biasable, locked or unlocked mark word.
+     * 
+     * <pre>
+     * +----------------------------------+-+-+
+     * |                                 1|1|1|
+     * +----------------------------------+-+-+
+     * </pre>
+     * 
+     */
+    @Fold
+    public static int biasedLockMaskInPlace() {
+        return config().biasedLockMaskInPlace;
+    }
+
+    @Fold
+    public static int epochMaskInPlace() {
+        return config().epochMaskInPlace;
+    }
+
+    /**
+     * Pattern for a biasable, unlocked mark word.
+     * 
+     * <pre>
+     * +----------------------------------+-+-+
+     * |                                 1|0|1|
+     * +----------------------------------+-+-+
+     * </pre>
+     * 
+     */
+    @Fold
+    public static int biasedLockPattern() {
+        return config().biasedLockPattern;
+    }
+
+    @Fold
+    public static int ageMaskInPlace() {
+        return config().ageMaskInPlace;
+    }
+
+    @Fold
+    public static int metaspaceArrayLengthOffset() {
+        return config().metaspaceArrayLengthOffset;
+    }
+
+    @Fold
+    public static int metaspaceArrayBaseOffset() {
+        return config().metaspaceArrayBaseOffset;
+    }
+
+    @Fold
+    public static int arrayLengthOffset() {
+        return config().arrayLengthOffset;
+    }
+
+    @Fold
+    public static int arrayBaseOffset(Kind elementKind) {
+        return HotSpotRuntime.getArrayBaseOffset(elementKind);
+    }
+
+    @Fold
+    public static int arrayIndexScale(Kind elementKind) {
+        return HotSpotRuntime.getArrayIndexScale(elementKind);
+    }
+
+    @Fold
+    public static int cardTableShift() {
+        return config().cardtableShift;
+    }
+
+    @Fold
+    public static long cardTableStart() {
+        return config().cardtableStartAddress;
+    }
+
+    @Fold
+    public static int g1CardQueueIndexOffset() {
+        return config().g1CardQueueIndexOffset;
+    }
+
+    @Fold
+    public static int g1CardQueueBufferOffset() {
+        return config().g1CardQueueBufferOffset;
+    }
+
+    @Fold
+    public static int logOfHRGrainBytes() {
+        return config().logOfHRGrainBytes;
+    }
+
+    @Fold
+    public static int g1SATBQueueMarkingOffset() {
+        return config().g1SATBQueueMarkingOffset;
+    }
+
+    @Fold
+    public static int g1SATBQueueIndexOffset() {
+        return config().g1SATBQueueIndexOffset;
+    }
+
+    @Fold
+    public static int g1SATBQueueBufferOffset() {
+        return config().g1SATBQueueBufferOffset;
+    }
+
+    @Fold
+    public static int superCheckOffsetOffset() {
+        return config().superCheckOffsetOffset;
+    }
+
+    public static final LocationIdentity SECONDARY_SUPER_CACHE_LOCATION = LocationNode.createLocation("SecondarySuperCache");
+
+    @Fold
+    public static int secondarySuperCacheOffset() {
+        return config().secondarySuperCacheOffset;
+    }
+
+    public static final LocationIdentity SECONDARY_SUPERS_LOCATION = LocationNode.createLocation("SecondarySupers");
+
+    @Fold
+    public static int secondarySupersOffset() {
+        return config().secondarySupersOffset;
+    }
+
+    public static final LocationIdentity DISPLACED_MARK_WORD_LOCATION = LocationNode.createLocation("DisplacedMarkWord");
+
+    @Fold
+    public static int lockDisplacedMarkOffset() {
+        return config().basicLockDisplacedHeaderOffset;
+    }
+
+    @Fold
+    public static boolean useBiasedLocking() {
+        return config().useBiasedLocking;
+    }
+
+    @Fold
+    public static boolean useG1GC() {
+        return config().useG1GC;
+    }
+
+    @Fold
+    static int uninitializedIdentityHashCodeValue() {
+        return config().uninitializedIdentityHashCodeValue;
+    }
+
+    @Fold
+    static int identityHashCodeShift() {
+        return config().identityHashCodeShift;
+    }
+
+    /**
+     * Loads the hub from a object, null checking it first.
+     */
+    public static Word loadHub(Object object) {
+        return loadHubIntrinsic(object, wordKind());
+    }
+
+    public static Object verifyOop(Object object) {
+        if (verifyOops()) {
+            VerifyOopStubCall.call(object);
+        }
+        return object;
+    }
+
+    /**
+     * Gets the value of the stack pointer register as a Word.
+     */
+    public static Word stackPointer() {
+        return registerAsWord(stackPointerRegister(), true, false);
+    }
+
+    /**
+     * Gets the value of the thread register as a Word.
+     */
+    public static Word thread() {
+        return registerAsWord(threadRegister(), true, false);
+    }
+
+    public static Word loadWordFromObject(Object object, int offset) {
+        return loadWordFromObjectIntrinsic(object, 0, offset, wordKind());
+    }
+
+    @NodeIntrinsic(value = ReadRegisterNode.class, setStampFromReturnType = true)
+    public static native Word registerAsWord(@ConstantNodeParameter Register register, @ConstantNodeParameter boolean directUse, @ConstantNodeParameter boolean incoming);
+
+    @SuppressWarnings("unused")
+    @NodeIntrinsic(value = UnsafeLoadNode.class, setStampFromReturnType = true)
+    private static Word loadWordFromObjectIntrinsic(Object object, @ConstantNodeParameter int displacement, long offset, @ConstantNodeParameter Kind wordKind) {
+        return Word.box(unsafeReadWord(object, offset + displacement));
+    }
+
+    @SuppressWarnings("unused")
+    @NodeIntrinsic(value = LoadHubNode.class, setStampFromReturnType = true)
+    static Word loadHubIntrinsic(Object object, @ConstantNodeParameter Kind word) {
+        return Word.box(unsafeReadWord(object, hubOffset()));
+    }
+
+    @Fold
+    public static int log2WordSize() {
+        return CodeUtil.log2(wordSize());
+    }
+
+    public static final LocationIdentity CLASS_STATE_LOCATION = LocationNode.createLocation("ClassState");
+
+    @Fold
+    public static int klassStateOffset() {
+        return config().klassStateOffset;
+    }
+
+    @Fold
+    public static int klassStateFullyInitialized() {
+        return config().klassStateFullyInitialized;
+    }
+
+    @Fold
+    public static int klassModifierFlagsOffset() {
+        return config().klassModifierFlagsOffset;
+    }
+
+    @Fold
+    public static int klassOffset() {
+        return config().klassOffset;
+    }
+
+    @Fold
+    public static int classMirrorOffset() {
+        return config().classMirrorOffset;
+    }
+
+    @Fold
+    public static int klassInstanceSizeOffset() {
+        return config().klassInstanceSizeOffset;
+    }
+
+    public static final LocationIdentity HEAP_TOP_LOCATION = LocationNode.createLocation("HeapTop");
+
+    @Fold
+    public static long heapTopAddress() {
+        return config().heapTopAddress;
+    }
+
+    public static final LocationIdentity HEAP_END_LOCATION = LocationNode.createLocation("HeapEnd");
+
+    @Fold
+    public static long heapEndAddress() {
+        return config().heapEndAddress;
+    }
+
+    @Fold
+    public static long tlabIntArrayMarkWord() {
+        return config().tlabIntArrayMarkWord;
+    }
+
+    @Fold
+    public static boolean inlineContiguousAllocationSupported() {
+        return config().inlineContiguousAllocationSupported;
+    }
+
+    @Fold
+    public static int tlabAlignmentReserveInHeapWords() {
+        return config().tlabAlignmentReserve;
+    }
+
+    public static final LocationIdentity TLAB_SIZE_LOCATION = LocationNode.createLocation("TlabSize");
+
+    @Fold
+    public static int threadTlabSizeOffset() {
+        return config().threadTlabSizeOffset;
+    }
+
+    public static final LocationIdentity TLAB_THREAD_ALLOCATED_BYTES_LOCATION = LocationNode.createLocation("TlabThreadAllocatedBytes");
+
+    @Fold
+    public static int threadAllocatedBytesOffset() {
+        return config().threadAllocatedBytesOffset;
+    }
+
+    public static final LocationIdentity TLAB_REFILL_WASTE_LIMIT_LOCATION = LocationNode.createLocation("RefillWasteLimit");
+
+    @Fold
+    public static int tlabRefillWasteLimitOffset() {
+        return config().tlabRefillWasteLimitOffset;
+    }
+
+    public static final LocationIdentity TLAB_NOF_REFILLS_LOCATION = LocationNode.createLocation("TlabNOfRefills");
+
+    @Fold
+    public static int tlabNumberOfRefillsOffset() {
+        return config().tlabNumberOfRefillsOffset;
+    }
+
+    public static final LocationIdentity TLAB_FAST_REFILL_WASTE_LOCATION = LocationNode.createLocation("TlabFastRefillWaste");
+
+    @Fold
+    public static int tlabFastRefillWasteOffset() {
+        return config().tlabFastRefillWasteOffset;
+    }
+
+    public static final LocationIdentity TLAB_SLOW_ALLOCATIONS_LOCATION = LocationNode.createLocation("TlabSlowAllocations");
+
+    @Fold
+    public static int tlabSlowAllocationsOffset() {
+        return config().tlabSlowAllocationsOffset;
+    }
+
+    @Fold
+    public static int tlabRefillWasteIncrement() {
+        return config().tlabRefillWasteIncrement;
+    }
+
+    @Fold
+    public static boolean tlabStats() {
+        return config().tlabStats;
+    }
+
+    @Fold
+    public static int layoutHelperOffset() {
+        return config().layoutHelperOffset;
+    }
+
+    @Fold
+    public static int layoutHelperHeaderSizeShift() {
+        return config().layoutHelperHeaderSizeShift;
+    }
+
+    @Fold
+    public static int layoutHelperHeaderSizeMask() {
+        return config().layoutHelperHeaderSizeMask;
+    }
+
+    @Fold
+    public static int layoutHelperLog2ElementSizeShift() {
+        return config().layoutHelperLog2ElementSizeShift;
+    }
+
+    @Fold
+    public static int layoutHelperLog2ElementSizeMask() {
+        return config().layoutHelperLog2ElementSizeMask;
+    }
+
+    @Fold
+    public static int layoutHelperElementTypeShift() {
+        return config().layoutHelperElementTypeShift;
+    }
+
+    @Fold
+    public static int layoutHelperElementTypeMask() {
+        return config().layoutHelperElementTypeMask;
+    }
+
+    @Fold
+    public static int layoutHelperElementTypePrimitiveInPlace() {
+        return config().layoutHelperElementTypePrimitiveInPlace;
+    }
+
+    static {
+        assert arrayIndexScale(Kind.Byte) == 1;
+        assert arrayIndexScale(Kind.Boolean) == 1;
+        assert arrayIndexScale(Kind.Char) == 2;
+        assert arrayIndexScale(Kind.Short) == 2;
+        assert arrayIndexScale(Kind.Int) == 4;
+        assert arrayIndexScale(Kind.Long) == 8;
+        assert arrayIndexScale(Kind.Float) == 4;
+        assert arrayIndexScale(Kind.Double) == 8;
+    }
+
+    static int computeHashCode(Object x) {
+        Word mark = loadWordFromObject(x, markOffset());
+
+        // this code is independent from biased locking (although it does not look that way)
+        final Word biasedLock = mark.and(biasedLockMaskInPlace());
+        if (probability(FAST_PATH_PROBABILITY, biasedLock.equal(Word.unsigned(unlockedMask())))) {
+            int hash = (int) mark.unsignedShiftRight(identityHashCodeShift()).rawValue();
+            if (probability(FAST_PATH_PROBABILITY, hash != uninitializedIdentityHashCodeValue())) {
+                return hash;
+            }
+        }
+
+        return identityHashCode(IDENTITY_HASHCODE, x);
+    }
+
+    public static final Descriptor IDENTITY_HASHCODE = new Descriptor("identity_hashcode", false, int.class, Object.class);
+
+    @SuppressWarnings("unused")
+    @NodeIntrinsic(RuntimeCallNode.class)
+    public static int identityHashCode(@ConstantNodeParameter Descriptor descriptor, Object object) {
+        return System.identityHashCode(object);
+    }
+
+    @Fold
+    public static int verifiedEntryPointOffset() {
+        return config().nmethodEntryOffset;
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSnippetUtils.java	Mon May 13 16:46:39 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,625 +0,0 @@
-/*
- * 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.hotspot.replacements;
-
-import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
-import static com.oracle.graal.replacements.nodes.BranchProbabilityNode.*;
-import sun.misc.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.Node.ConstantNodeParameter;
-import com.oracle.graal.graph.Node.NodeIntrinsic;
-import com.oracle.graal.hotspot.*;
-import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.hotspot.nodes.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.replacements.Snippet.Fold;
-import com.oracle.graal.replacements.nodes.*;
-import com.oracle.graal.word.*;
-
-//JaCoCo Exclude
-
-/**
- * A collection of methods used in HotSpot snippets and substitutions.
- */
-public class HotSpotSnippetUtils {
-
-    public static final Object ANY_LOCATION = LocationNode.ANY_LOCATION;
-    public static final Object FINAL_LOCATION = LocationNode.FINAL_LOCATION;
-
-    public static HotSpotVMConfig config() {
-        return graalRuntime().getConfig();
-    }
-
-    @Fold
-    public static boolean useTLAB() {
-        return config().useTLAB;
-    }
-
-    @Fold
-    public static boolean verifyOops() {
-        return config().verifyOops;
-    }
-
-    public static final Object EXCEPTION_OOP_LOCATION = LocationNode.createLocation("ExceptionOop");
-
-    @Fold
-    public static int threadExceptionOopOffset() {
-        return config().threadExceptionOopOffset;
-    }
-
-    public static final Object EXCEPTION_PC_LOCATION = LocationNode.createLocation("ExceptionPc");
-
-    @Fold
-    public static int threadExceptionPcOffset() {
-        return config().threadExceptionPcOffset;
-    }
-
-    public static final Object TLAB_TOP_LOCATION = LocationNode.createLocation("TlabTop");
-
-    @Fold
-    public static int threadTlabTopOffset() {
-        return config().threadTlabTopOffset;
-    }
-
-    public static final Object TLAB_END_LOCATION = LocationNode.createLocation("TlabEnd");
-
-    @Fold
-    private static int threadTlabEndOffset() {
-        return config().threadTlabEndOffset;
-    }
-
-    public static final Object TLAB_START_LOCATION = LocationNode.createLocation("TlabStart");
-
-    @Fold
-    private static int threadTlabStartOffset() {
-        return config().threadTlabStartOffset;
-    }
-
-    public static Object readExceptionOop(Word thread) {
-        return thread.readObject(threadExceptionOopOffset(), EXCEPTION_OOP_LOCATION);
-    }
-
-    public static void writeExceptionOop(Word thread, Object value) {
-        thread.writeObject(threadExceptionOopOffset(), value, EXCEPTION_OOP_LOCATION);
-    }
-
-    public static void writeExceptionPc(Word thread, Word value) {
-        thread.writeWord(threadExceptionPcOffset(), value, EXCEPTION_PC_LOCATION);
-    }
-
-    public static Word readTlabTop(Word thread) {
-        return thread.readWord(threadTlabTopOffset(), TLAB_TOP_LOCATION);
-    }
-
-    public static Word readTlabEnd(Word thread) {
-        return thread.readWord(threadTlabEndOffset(), TLAB_END_LOCATION);
-    }
-
-    public static Word readTlabStart(Word thread) {
-        return thread.readWord(threadTlabStartOffset(), TLAB_START_LOCATION);
-    }
-
-    public static void writeTlabTop(Word thread, Word top) {
-        thread.writeWord(threadTlabTopOffset(), top, TLAB_TOP_LOCATION);
-    }
-
-    public static void initializeTlab(Word thread, Word start, Word end) {
-        thread.writeWord(threadTlabStartOffset(), start, TLAB_START_LOCATION);
-        thread.writeWord(threadTlabTopOffset(), start, TLAB_TOP_LOCATION);
-        thread.writeWord(threadTlabEndOffset(), end, TLAB_END_LOCATION);
-    }
-
-    @Fold
-    public static int threadObjectOffset() {
-        return config().threadObjectOffset;
-    }
-
-    @Fold
-    public static int osThreadOffset() {
-        return config().osThreadOffset;
-    }
-
-    @Fold
-    public static int osThreadInterruptedOffset() {
-        return config().osThreadInterruptedOffset;
-    }
-
-    @Fold
-    public static Kind wordKind() {
-        return graalRuntime().getTarget().wordKind;
-    }
-
-    @Fold
-    public static Register threadRegister() {
-        return graalRuntime().getRuntime().threadRegister();
-    }
-
-    @Fold
-    public static Register stackPointerRegister() {
-        return graalRuntime().getRuntime().stackPointerRegister();
-    }
-
-    @Fold
-    public static int wordSize() {
-        return graalRuntime().getTarget().wordSize;
-    }
-
-    @Fold
-    public static int pageSize() {
-        return Unsafe.getUnsafe().pageSize();
-    }
-
-    public static final Object PROTOTYPE_MARK_WORD_LOCATION = LocationNode.createLocation("PrototypeMarkWord");
-
-    @Fold
-    public static int prototypeMarkWordOffset() {
-        return config().prototypeMarkWordOffset;
-    }
-
-    @Fold
-    public static long arrayPrototypeMarkWord() {
-        return config().arrayPrototypeMarkWord;
-    }
-
-    @Fold
-    public static int klassAccessFlagsOffset() {
-        return config().klassAccessFlagsOffset;
-    }
-
-    @Fold
-    private static int klassLayoutHelperOffset() {
-        return config().klassLayoutHelperOffset;
-    }
-
-    public static int readLayoutHelper(Word hub) {
-        return hub.readInt(klassLayoutHelperOffset(), FINAL_LOCATION);
-    }
-
-    @Fold
-    public static int arrayKlassLayoutHelperIdentifier() {
-        return config().arrayKlassLayoutHelperIdentifier;
-    }
-
-    @Fold
-    public static int arrayKlassComponentMirrorOffset() {
-        return config().arrayKlassComponentMirrorOffset;
-    }
-
-    @Fold
-    public static int klassSuperKlassOffset() {
-        return config().klassSuperKlassOffset;
-    }
-
-    public static final Object MARK_WORD_LOCATION = LocationNode.createLocation("MarkWord");
-
-    @Fold
-    public static int markOffset() {
-        return config().markOffset;
-    }
-
-    public static final Object HUB_LOCATION = LocationNode.createLocation("Hub");
-
-    @Fold
-    private static int hubOffset() {
-        return config().hubOffset;
-    }
-
-    public static void initializeObjectHeader(Word memory, Word markWord, Word hub) {
-        memory.writeWord(markOffset(), markWord, MARK_WORD_LOCATION);
-        memory.writeWord(hubOffset(), hub, HUB_LOCATION);
-    }
-
-    @Fold
-    public static int unlockedMask() {
-        return config().unlockedMask;
-    }
-
-    /**
-     * Mask for a biasable, locked or unlocked mark word.
-     * 
-     * <pre>
-     * +----------------------------------+-+-+
-     * |                                 1|1|1|
-     * +----------------------------------+-+-+
-     * </pre>
-     * 
-     */
-    @Fold
-    public static int biasedLockMaskInPlace() {
-        return config().biasedLockMaskInPlace;
-    }
-
-    @Fold
-    public static int epochMaskInPlace() {
-        return config().epochMaskInPlace;
-    }
-
-    /**
-     * Pattern for a biasable, unlocked mark word.
-     * 
-     * <pre>
-     * +----------------------------------+-+-+
-     * |                                 1|0|1|
-     * +----------------------------------+-+-+
-     * </pre>
-     * 
-     */
-    @Fold
-    public static int biasedLockPattern() {
-        return config().biasedLockPattern;
-    }
-
-    @Fold
-    public static int ageMaskInPlace() {
-        return config().ageMaskInPlace;
-    }
-
-    @Fold
-    public static int metaspaceArrayLengthOffset() {
-        return config().metaspaceArrayLengthOffset;
-    }
-
-    @Fold
-    public static int metaspaceArrayBaseOffset() {
-        return config().metaspaceArrayBaseOffset;
-    }
-
-    @Fold
-    public static int arrayLengthOffset() {
-        return config().arrayLengthOffset;
-    }
-
-    @Fold
-    public static int arrayBaseOffset(Kind elementKind) {
-        return HotSpotRuntime.getArrayBaseOffset(elementKind);
-    }
-
-    @Fold
-    public static int arrayIndexScale(Kind elementKind) {
-        return HotSpotRuntime.getArrayIndexScale(elementKind);
-    }
-
-    @Fold
-    public static int cardTableShift() {
-        return config().cardtableShift;
-    }
-
-    @Fold
-    public static long cardTableStart() {
-        return config().cardtableStartAddress;
-    }
-
-    @Fold
-    public static int g1CardQueueIndexOffset() {
-        return config().g1CardQueueIndexOffset;
-    }
-
-    @Fold
-    public static int g1CardQueueBufferOffset() {
-        return config().g1CardQueueBufferOffset;
-    }
-
-    @Fold
-    public static int logOfHRGrainBytes() {
-        return config().logOfHRGrainBytes;
-    }
-
-    @Fold
-    public static int g1SATBQueueMarkingOffset() {
-        return config().g1SATBQueueMarkingOffset;
-    }
-
-    @Fold
-    public static int g1SATBQueueIndexOffset() {
-        return config().g1SATBQueueIndexOffset;
-    }
-
-    @Fold
-    public static int g1SATBQueueBufferOffset() {
-        return config().g1SATBQueueBufferOffset;
-    }
-
-    @Fold
-    public static int superCheckOffsetOffset() {
-        return config().superCheckOffsetOffset;
-    }
-
-    public static final Object SECONDARY_SUPER_CACHE_LOCATION = LocationNode.createLocation("SecondarySuperCache");
-
-    @Fold
-    public static int secondarySuperCacheOffset() {
-        return config().secondarySuperCacheOffset;
-    }
-
-    public static final Object SECONDARY_SUPERS_LOCATION = LocationNode.createLocation("SecondarySupers");
-
-    @Fold
-    public static int secondarySupersOffset() {
-        return config().secondarySupersOffset;
-    }
-
-    public static final Object DISPLACED_MARK_WORD_LOCATION = LocationNode.createLocation("DisplacedMarkWord");
-
-    @Fold
-    public static int lockDisplacedMarkOffset() {
-        return config().basicLockDisplacedHeaderOffset;
-    }
-
-    @Fold
-    public static boolean useBiasedLocking() {
-        return config().useBiasedLocking;
-    }
-
-    @Fold
-    public static boolean useG1GC() {
-        return config().useG1GC;
-    }
-
-    @Fold
-    static int uninitializedIdentityHashCodeValue() {
-        return config().uninitializedIdentityHashCodeValue;
-    }
-
-    @Fold
-    static int identityHashCodeShift() {
-        return config().identityHashCodeShift;
-    }
-
-    /**
-     * Loads the hub from a object, null checking it first.
-     */
-    public static Word loadHub(Object object) {
-        return loadHubIntrinsic(object, wordKind());
-    }
-
-    public static Object verifyOop(Object object) {
-        if (verifyOops()) {
-            VerifyOopStubCall.call(object);
-        }
-        return object;
-    }
-
-    /**
-     * Gets the value of the stack pointer register as a Word.
-     */
-    public static Word stackPointer() {
-        return HotSpotSnippetUtils.registerAsWord(stackPointerRegister(), true, false);
-    }
-
-    /**
-     * Gets the value of the thread register as a Word.
-     */
-    public static Word thread() {
-        return HotSpotSnippetUtils.registerAsWord(threadRegister(), true, false);
-    }
-
-    public static Word loadWordFromObject(Object object, int offset) {
-        return loadWordFromObjectIntrinsic(object, 0, offset, wordKind());
-    }
-
-    @NodeIntrinsic(value = ReadRegisterNode.class, setStampFromReturnType = true)
-    public static native Word registerAsWord(@ConstantNodeParameter Register register, @ConstantNodeParameter boolean directUse, @ConstantNodeParameter boolean incoming);
-
-    @SuppressWarnings("unused")
-    @NodeIntrinsic(value = UnsafeLoadNode.class, setStampFromReturnType = true)
-    private static Word loadWordFromObjectIntrinsic(Object object, @ConstantNodeParameter int displacement, long offset, @ConstantNodeParameter Kind wordKind) {
-        return Word.box(unsafeReadWord(object, offset + displacement));
-    }
-
-    @SuppressWarnings("unused")
-    @NodeIntrinsic(value = LoadHubNode.class, setStampFromReturnType = true)
-    static Word loadHubIntrinsic(Object object, @ConstantNodeParameter Kind word) {
-        return Word.box(unsafeReadWord(object, hubOffset()));
-    }
-
-    @Fold
-    public static int log2WordSize() {
-        return CodeUtil.log2(wordSize());
-    }
-
-    public static final Object CLASS_STATE_LOCATION = LocationNode.createLocation("ClassState");
-
-    @Fold
-    public static int klassStateOffset() {
-        return config().klassStateOffset;
-    }
-
-    @Fold
-    public static int klassStateFullyInitialized() {
-        return config().klassStateFullyInitialized;
-    }
-
-    @Fold
-    public static int klassModifierFlagsOffset() {
-        return config().klassModifierFlagsOffset;
-    }
-
-    @Fold
-    public static int klassOffset() {
-        return config().klassOffset;
-    }
-
-    @Fold
-    public static int classMirrorOffset() {
-        return config().classMirrorOffset;
-    }
-
-    @Fold
-    public static int klassInstanceSizeOffset() {
-        return config().klassInstanceSizeOffset;
-    }
-
-    public static final Object HEAP_TOP_LOCATION = LocationNode.createLocation("HeapTop");
-
-    @Fold
-    public static long heapTopAddress() {
-        return config().heapTopAddress;
-    }
-
-    public static final Object HEAP_END_LOCATION = LocationNode.createLocation("HeapEnd");
-
-    @Fold
-    public static long heapEndAddress() {
-        return config().heapEndAddress;
-    }
-
-    @Fold
-    public static long tlabIntArrayMarkWord() {
-        return config().tlabIntArrayMarkWord;
-    }
-
-    @Fold
-    public static boolean inlineContiguousAllocationSupported() {
-        return config().inlineContiguousAllocationSupported;
-    }
-
-    @Fold
-    public static int tlabAlignmentReserveInHeapWords() {
-        return config().tlabAlignmentReserve;
-    }
-
-    public static final Object TLAB_SIZE_LOCATION = LocationNode.createLocation("TlabSize");
-
-    @Fold
-    public static int threadTlabSizeOffset() {
-        return config().threadTlabSizeOffset;
-    }
-
-    public static final Object TLAB_THREAD_ALLOCATED_BYTES_LOCATION = LocationNode.createLocation("TlabThreadAllocatedBytes");
-
-    @Fold
-    public static int threadAllocatedBytesOffset() {
-        return config().threadAllocatedBytesOffset;
-    }
-
-    public static final Object TLAB_REFILL_WASTE_LIMIT_LOCATION = LocationNode.createLocation("RefillWasteLimit");
-
-    @Fold
-    public static int tlabRefillWasteLimitOffset() {
-        return config().tlabRefillWasteLimitOffset;
-    }
-
-    public static final Object TLAB_NOF_REFILLS_LOCATION = LocationNode.createLocation("TlabNOfRefills");
-
-    @Fold
-    public static int tlabNumberOfRefillsOffset() {
-        return config().tlabNumberOfRefillsOffset;
-    }
-
-    public static final Object TLAB_FAST_REFILL_WASTE_LOCATION = LocationNode.createLocation("TlabFastRefillWaste");
-
-    @Fold
-    public static int tlabFastRefillWasteOffset() {
-        return config().tlabFastRefillWasteOffset;
-    }
-
-    public static final Object TLAB_SLOW_ALLOCATIONS_LOCATION = LocationNode.createLocation("TlabSlowAllocations");
-
-    @Fold
-    public static int tlabSlowAllocationsOffset() {
-        return config().tlabSlowAllocationsOffset;
-    }
-
-    @Fold
-    public static int tlabRefillWasteIncrement() {
-        return config().tlabRefillWasteIncrement;
-    }
-
-    @Fold
-    public static boolean tlabStats() {
-        return config().tlabStats;
-    }
-
-    @Fold
-    public static int layoutHelperOffset() {
-        return config().layoutHelperOffset;
-    }
-
-    @Fold
-    public static int layoutHelperHeaderSizeShift() {
-        return config().layoutHelperHeaderSizeShift;
-    }
-
-    @Fold
-    public static int layoutHelperHeaderSizeMask() {
-        return config().layoutHelperHeaderSizeMask;
-    }
-
-    @Fold
-    public static int layoutHelperLog2ElementSizeShift() {
-        return config().layoutHelperLog2ElementSizeShift;
-    }
-
-    @Fold
-    public static int layoutHelperLog2ElementSizeMask() {
-        return config().layoutHelperLog2ElementSizeMask;
-    }
-
-    @Fold
-    public static int layoutHelperElementTypeShift() {
-        return config().layoutHelperElementTypeShift;
-    }
-
-    @Fold
-    public static int layoutHelperElementTypeMask() {
-        return config().layoutHelperElementTypeMask;
-    }
-
-    @Fold
-    public static int layoutHelperElementTypePrimitiveInPlace() {
-        return config().layoutHelperElementTypePrimitiveInPlace;
-    }
-
-    static {
-        assert arrayIndexScale(Kind.Byte) == 1;
-        assert arrayIndexScale(Kind.Boolean) == 1;
-        assert arrayIndexScale(Kind.Char) == 2;
-        assert arrayIndexScale(Kind.Short) == 2;
-        assert arrayIndexScale(Kind.Int) == 4;
-        assert arrayIndexScale(Kind.Long) == 8;
-        assert arrayIndexScale(Kind.Float) == 4;
-        assert arrayIndexScale(Kind.Double) == 8;
-    }
-
-    static int computeHashCode(Object x) {
-        Word mark = loadWordFromObject(x, markOffset());
-
-        // this code is independent from biased locking (although it does not look that way)
-        final Word biasedLock = mark.and(biasedLockMaskInPlace());
-        if (probability(FAST_PATH_PROBABILITY, biasedLock.equal(Word.unsigned(unlockedMask())))) {
-            int hash = (int) mark.unsignedShiftRight(identityHashCodeShift()).rawValue();
-            if (probability(FAST_PATH_PROBABILITY, hash != uninitializedIdentityHashCodeValue())) {
-                return hash;
-            }
-        }
-
-        return IdentityHashCodeStubCall.call(x);
-    }
-
-    @Fold
-    public static int verifiedEntryPointOffset() {
-        return config().nmethodEntryOffset;
-    }
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java	Mon May 13 17:11:31 2013 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
-import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*;
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 import static com.oracle.graal.hotspot.replacements.TypeCheckSnippetUtils.*;
 import static com.oracle.graal.replacements.nodes.BranchProbabilityNode.*;
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/LoadExceptionObjectSnippets.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/LoadExceptionObjectSnippets.java	Mon May 13 17:11:31 2013 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
-import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*;
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 import static com.oracle.graal.nodes.extended.UnsafeCastNode.*;
 import static com.oracle.graal.replacements.SnippetTemplate.*;
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java	Mon May 13 17:11:31 2013 +0200
@@ -26,7 +26,7 @@
 import static com.oracle.graal.hotspot.nodes.DirectCompareAndSwapNode.*;
 import static com.oracle.graal.hotspot.nodes.EndLockScopeNode.*;
 import static com.oracle.graal.hotspot.nodes.VMErrorNode.*;
-import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*;
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 import static com.oracle.graal.replacements.SnippetTemplate.*;
 import static com.oracle.graal.replacements.nodes.BranchProbabilityNode.*;
 
@@ -37,10 +37,10 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.graph.iterators.*;
-import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.spi.*;
@@ -76,7 +76,7 @@
     public static final boolean CHECK_BALANCED_MONITORS = Boolean.getBoolean("graal.monitors.checkBalanced");
 
     @Snippet
-    public static void monitorenter(Object object, @ConstantParameter boolean checkNull, @ConstantParameter boolean trace) {
+    public static void monitorenter(Object object, @ConstantParameter int lockDepth, @ConstantParameter boolean checkNull, @ConstantParameter boolean trace) {
         verifyOop(object);
 
         if (checkNull && object == null) {
@@ -86,7 +86,7 @@
         // Load the mark word - this includes a null-check on object
         final Word mark = loadWordFromObject(object, markOffset());
 
-        final Word lock = beginLockScope(false);
+        final Word lock = beginLockScope(lockDepth);
 
         trace(trace, "           object: 0x%016lx\n", Word.fromObject(object));
         trace(trace, "             lock: 0x%016lx\n", lock);
@@ -150,7 +150,7 @@
                         Word biasedMark = unbiasedMark.or(thread);
                         trace(trace, "     unbiasedMark: 0x%016lx\n", unbiasedMark);
                         trace(trace, "       biasedMark: 0x%016lx\n", biasedMark);
-                        if (probability(VERY_FAST_DEOPT_PATH_PROBABILITY, compareAndSwap(object, markOffset(), unbiasedMark, biasedMark, MARK_WORD_LOCATION).equal(unbiasedMark))) {
+                        if (probability(VERY_FAST_PATH_PROBABILITY, compareAndSwap(object, markOffset(), unbiasedMark, biasedMark, MARK_WORD_LOCATION).equal(unbiasedMark))) {
                             // Object is now biased to current thread -> done
                             traceObject(trace, "+lock{bias:acquired}", object);
                             return;
@@ -170,7 +170,7 @@
                         // the bias from one thread to another directly in this situation.
                         Word biasedMark = prototypeMarkWord.or(thread);
                         trace(trace, "       biasedMark: 0x%016lx\n", biasedMark);
-                        if (probability(VERY_FAST_DEOPT_PATH_PROBABILITY, compareAndSwap(object, markOffset(), mark, biasedMark, MARK_WORD_LOCATION).equal(mark))) {
+                        if (probability(VERY_FAST_PATH_PROBABILITY, compareAndSwap(object, markOffset(), mark, biasedMark, MARK_WORD_LOCATION).equal(mark))) {
                             // Object is now biased to current thread -> done
                             traceObject(trace, "+lock{bias:transfer}", object);
                             return;
@@ -248,17 +248,11 @@
         }
     }
 
-    @Snippet
-    public static void monitorenterEliminated() {
-        incCounter();
-        beginLockScope(true);
-    }
-
     /**
      * Calls straight out to the monitorenter stub.
      */
     @Snippet
-    public static void monitorenterStub(Object object, @ConstantParameter boolean checkNull, @ConstantParameter boolean trace) {
+    public static void monitorenterStub(Object object, @ConstantParameter int lockDepth, @ConstantParameter boolean checkNull, @ConstantParameter boolean trace) {
         verifyOop(object);
         incCounter();
         if (checkNull && object == null) {
@@ -266,13 +260,13 @@
         }
         // BeginLockScope nodes do not read from object so a use of object
         // cannot float about the null check above
-        final Word lock = beginLockScope(false);
+        final Word lock = beginLockScope(lockDepth);
         traceObject(trace, "+lock{stub}", object);
         MonitorEnterStubCall.call(object, lock);
     }
 
     @Snippet
-    public static void monitorexit(Object object, @ConstantParameter boolean trace) {
+    public static void monitorexit(Object object, @ConstantParameter int lockDepth, @ConstantParameter boolean trace) {
         trace(trace, "           object: 0x%016lx\n", Word.fromObject(object));
         if (useBiasedLocking()) {
             // Check for biased locking unlock case, which is a no-op
@@ -291,7 +285,7 @@
             }
         }
 
-        final Word lock = CurrentLockNode.currentLock();
+        final Word lock = CurrentLockNode.currentLock(lockDepth);
 
         // Load displaced mark
         final Word displacedMark = lock.readWord(lockDisplacedMarkOffset(), DISPLACED_MARK_WORD_LOCATION);
@@ -309,7 +303,7 @@
                 // The object's mark word was not pointing to the displaced header,
                 // we do unlocking via runtime call.
                 traceObject(trace, "-lock{stub}", object);
-                MonitorExitStubCall.call(object);
+                MonitorExitStubCall.call(object, lockDepth);
             } else {
                 traceObject(trace, "-lock{cas}", object);
             }
@@ -322,16 +316,10 @@
      * Calls straight out to the monitorexit stub.
      */
     @Snippet
-    public static void monitorexitStub(Object object, @ConstantParameter boolean trace) {
+    public static void monitorexitStub(Object object, @ConstantParameter int lockDepth, @ConstantParameter boolean trace) {
         verifyOop(object);
         traceObject(trace, "-lock{stub}", object);
-        MonitorExitStubCall.call(object);
-        endLockScope();
-        decCounter();
-    }
-
-    @Snippet
-    public static void monitorexitEliminated() {
+        MonitorExitStubCall.call(object, lockDepth);
         endLockScope();
         decCounter();
     }
@@ -356,7 +344,7 @@
      */
     private static final boolean ENABLE_BREAKPOINT = false;
 
-    private static final Object MONITOR_COUNTER_LOCATION = LocationNode.createLocation("MonitorCounter");
+    private static final LocationIdentity MONITOR_COUNTER_LOCATION = LocationNode.createLocation("MonitorCounter");
 
     @NodeIntrinsic(BreakpointNode.class)
     static native void bkpt(Object object, Word mark, Word tmp, Word value);
@@ -384,7 +372,7 @@
     }
 
     @Snippet
-    private static void checkCounter(String errMsg) {
+    private static void checkCounter(@ConstantParameter String errMsg) {
         final Word counter = MonitorCounterNode.counter();
         final int count = counter.readInt(0, MONITOR_COUNTER_LOCATION);
         if (count != 0) {
@@ -398,8 +386,6 @@
         private final SnippetInfo monitorexit = snippet(MonitorSnippets.class, "monitorexit");
         private final SnippetInfo monitorenterStub = snippet(MonitorSnippets.class, "monitorenterStub");
         private final SnippetInfo monitorexitStub = snippet(MonitorSnippets.class, "monitorexitStub");
-        private final SnippetInfo monitorenterEliminated = snippet(MonitorSnippets.class, "monitorenterEliminated");
-        private final SnippetInfo monitorexitEliminated = snippet(MonitorSnippets.class, "monitorexitEliminated");
         private final SnippetInfo initCounter = snippet(MonitorSnippets.class, "initCounter");
         private final SnippetInfo checkCounter = snippet(MonitorSnippets.class, "checkCounter");
 
@@ -411,23 +397,21 @@
         }
 
         public void lower(MonitorEnterNode monitorenterNode, @SuppressWarnings("unused") LoweringTool tool) {
-            StructuredGraph graph = (StructuredGraph) monitorenterNode.graph();
+            StructuredGraph graph = monitorenterNode.graph();
             checkBalancedMonitors(graph);
             FrameState stateAfter = monitorenterNode.stateAfter();
 
             Arguments args;
-            if (monitorenterNode.eliminated()) {
-                args = new Arguments(monitorenterEliminated);
+            if (useFastLocking) {
+                args = new Arguments(monitorenter);
             } else {
-                if (useFastLocking) {
-                    args = new Arguments(monitorenter);
-                } else {
-                    args = new Arguments(monitorenterStub);
-                }
-                args.add("object", monitorenterNode.object());
-                args.addConst("checkNull", !monitorenterNode.object().stamp().nonNull());
-                args.addConst("trace", isTracingEnabledForType(monitorenterNode.object()) || isTracingEnabledForMethod(stateAfter.method()) || isTracingEnabledForMethod(graph.method()));
+                args = new Arguments(monitorenterStub);
             }
+            args.add("object", monitorenterNode.object());
+            args.addConst("lockDepth", monitorenterNode.getLockDepth());
+            args.addConst("checkNull", !monitorenterNode.object().stamp().nonNull());
+            boolean tracingEnabledForMethod = stateAfter != null && (isTracingEnabledForMethod(stateAfter.method()) || isTracingEnabledForMethod(graph.method()));
+            args.addConst("trace", isTracingEnabledForType(monitorenterNode.object()) || tracingEnabledForMethod);
 
             Map<Node, Node> nodes = template(args).instantiate(runtime, monitorenterNode, DEFAULT_REPLACER, args);
 
@@ -436,28 +420,22 @@
                     BeginLockScopeNode begin = (BeginLockScopeNode) n;
                     begin.setStateAfter(stateAfter);
                 }
-                if (n instanceof MonitorReference) {
-                    ((MonitorReference) n).setLockDepth(monitorenterNode.getLockDepth());
-                }
             }
         }
 
         public void lower(MonitorExitNode monitorexitNode, @SuppressWarnings("unused") LoweringTool tool) {
-            StructuredGraph graph = (StructuredGraph) monitorexitNode.graph();
+            StructuredGraph graph = monitorexitNode.graph();
             FrameState stateAfter = monitorexitNode.stateAfter();
 
             Arguments args;
-            if (monitorexitNode.eliminated()) {
-                args = new Arguments(monitorexitEliminated);
+            if (useFastLocking) {
+                args = new Arguments(monitorexit);
             } else {
-                if (useFastLocking) {
-                    args = new Arguments(monitorexit);
-                } else {
-                    args = new Arguments(monitorexitStub);
-                }
-                args.add("object", monitorexitNode.object());
-                args.addConst("trace", isTracingEnabledForType(monitorexitNode.object()) || isTracingEnabledForMethod(stateAfter.method()) || isTracingEnabledForMethod(graph.method()));
+                args = new Arguments(monitorexitStub);
             }
+            args.add("object", monitorexitNode.object());
+            args.addConst("lockDepth", monitorexitNode.getLockDepth());
+            args.addConst("trace", isTracingEnabledForType(monitorexitNode.object()) || isTracingEnabledForMethod(stateAfter.method()) || isTracingEnabledForMethod(graph.method()));
 
             Map<Node, Node> nodes = template(args).instantiate(runtime, monitorexitNode, DEFAULT_REPLACER, args);
 
@@ -466,9 +444,6 @@
                     EndLockScopeNode end = (EndLockScopeNode) n;
                     end.setStateAfter(stateAfter);
                 }
-                if (n instanceof MonitorReference) {
-                    ((MonitorReference) n).setLockDepth(monitorexitNode.getLockDepth());
-                }
             }
         }
 
@@ -522,7 +497,7 @@
                     List<ReturnNode> rets = graph.getNodes().filter(ReturnNode.class).snapshot();
                     for (ReturnNode ret : rets) {
                         returnType = checkCounter.getMethod().getSignature().getReturnType(checkCounter.getMethod().getDeclaringClass());
-                        Object msg = ((HotSpotRuntime) runtime).registerGCRoot("unbalanced monitors in " + MetaUtil.format("%H.%n(%p)", graph.method()) + ", count = %d");
+                        String msg = "unbalanced monitors in " + MetaUtil.format("%H.%n(%p)", graph.method()) + ", count = %d";
                         ConstantNode errMsg = ConstantNode.forObject(msg, runtime, graph);
                         callTarget = graph.add(new MethodCallTargetNode(InvokeKind.Static, checkCounter.getMethod(), new ValueNode[]{errMsg}, returnType));
                         invoke = graph.add(new InvokeNode(callTarget, 0));
@@ -530,7 +505,12 @@
                         FrameState stateAfter = new FrameState(graph.method(), FrameState.AFTER_BCI, new ValueNode[0], stack, new ValueNode[0], false, false);
                         invoke.setStateAfter(graph.add(stateAfter));
                         graph.addBeforeFixed(ret, invoke);
-                        inlineeGraph = replacements.getSnippet(checkCounter.getMethod());
+
+                        Arguments args = new Arguments(checkCounter);
+                        args.addConst("errMsg", msg);
+                        inlineeGraph = template(args).copySpecializedGraph();
+
+                        // inlineeGraph = replacements.getSnippet(checkCounter.getMethod());
                         InliningUtil.inline(invoke, inlineeGraph, false);
                     }
                 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Mon May 13 17:11:31 2013 +0200
@@ -23,7 +23,7 @@
 package com.oracle.graal.hotspot.replacements;
 
 import static com.oracle.graal.api.code.UnsignedMath.*;
-import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*;
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 import static com.oracle.graal.nodes.extended.UnsafeArrayCastNode.*;
 import static com.oracle.graal.nodes.extended.UnsafeCastNode.*;
 import static com.oracle.graal.replacements.SnippetTemplate.*;
@@ -72,18 +72,14 @@
     }
 
     @Snippet
-    public static Object initializeObject(Word memory, Word hub, Word prototypeMarkWord, @ConstantParameter int size, @ConstantParameter boolean fillContents, @ConstantParameter boolean locked) {
+    public static Object initializeObject(Word memory, Word hub, Word prototypeMarkWord, @ConstantParameter int size, @ConstantParameter boolean fillContents) {
 
         Object result;
         if (probability(SLOW_PATH_PROBABILITY, memory.equal(0))) {
             new_stub.inc();
             result = NewInstanceStubCall.call(hub);
         } else {
-            if (locked) {
-                formatObject(hub, size, memory, thread().or(biasedLockPattern()), fillContents);
-            } else {
-                formatObject(hub, size, memory, prototypeMarkWord, fillContents);
-            }
+            formatObject(hub, size, memory, prototypeMarkWord, fillContents);
             result = memory.toObject();
         }
         /*
@@ -95,16 +91,7 @@
     }
 
     @Snippet
-    public static Object initializeArray(Word memory, Word hub, int length, int allocationSize, Word prototypeMarkWord, @ConstantParameter int headerSize, @ConstantParameter boolean fillContents,
-                    @ConstantParameter boolean locked) {
-        if (locked) {
-            return initializeArray(memory, hub, length, allocationSize, thread().or(biasedLockPattern()), headerSize, fillContents);
-        } else {
-            return initializeArray(memory, hub, length, allocationSize, prototypeMarkWord, headerSize, fillContents);
-        }
-    }
-
-    private static Object initializeArray(Word memory, Word hub, int length, int allocationSize, Word prototypeMarkWord, int headerSize, boolean fillContents) {
+    public static Object initializeArray(Word memory, Word hub, int length, int allocationSize, Word prototypeMarkWord, @ConstantParameter int headerSize, @ConstantParameter boolean fillContents) {
         Object result;
         if (probability(SLOW_PATH_PROBABILITY, memory.equal(0))) {
             newarray_stub.inc();
@@ -132,7 +119,7 @@
         }
         int allocationSize = computeArrayAllocationSize(length, alignment, headerSize, log2ElementSize);
         Word memory = TLABAllocateNode.allocateVariableSize(allocationSize);
-        return InitializeArrayNode.initialize(memory, length, allocationSize, type, fillContents, false);
+        return InitializeArrayNode.initialize(memory, length, allocationSize, type, fillContents);
     }
 
     /**
@@ -229,7 +216,7 @@
          */
         @SuppressWarnings("unused")
         public void lower(NewInstanceNode newInstanceNode, LoweringTool tool) {
-            StructuredGraph graph = (StructuredGraph) newInstanceNode.graph();
+            StructuredGraph graph = newInstanceNode.graph();
             HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) newInstanceNode.instanceClass();
             ConstantNode hub = ConstantNode.forConstant(type.klass(), runtime, graph);
             int size = instanceSize(type);
@@ -243,7 +230,7 @@
                 graph.addBeforeFixed(newInstanceNode, tlabAllocateNode);
                 memory = tlabAllocateNode;
             }
-            InitializeObjectNode initializeNode = graph.add(new InitializeObjectNode(memory, type, newInstanceNode.fillContents(), newInstanceNode.locked()));
+            InitializeObjectNode initializeNode = graph.add(new InitializeObjectNode(memory, type, newInstanceNode.fillContents()));
             graph.replaceFixedWithFixed(newInstanceNode, initializeNode);
         }
 
@@ -252,7 +239,7 @@
          */
         @SuppressWarnings("unused")
         public void lower(NewArrayNode newArrayNode, LoweringTool tool) {
-            StructuredGraph graph = (StructuredGraph) newArrayNode.graph();
+            StructuredGraph graph = newArrayNode.graph();
             ValueNode lengthNode = newArrayNode.length();
             TLABAllocateNode tlabAllocateNode;
             ResolvedJavaType elementType = newArrayNode.elementType();
@@ -261,7 +248,7 @@
             final int alignment = target.wordSize;
             final int headerSize = HotSpotRuntime.getArrayBaseOffset(elementKind);
             final Integer length = lengthNode.isConstant() ? Integer.valueOf(lengthNode.asConstant().asInt()) : null;
-            int log2ElementSize = CodeUtil.log2(target.sizeInBytes(elementKind));
+            int log2ElementSize = CodeUtil.log2(target.arch.getSizeInBytes(elementKind));
             if (!useTLAB) {
                 ConstantNode zero = ConstantNode.defaultForKind(target.wordKind, graph);
                 /*
@@ -269,7 +256,7 @@
                  * anyway for both allocation and initialization - it just needs to be non-null
                  */
                 ConstantNode size = ConstantNode.forInt(-1, graph);
-                InitializeArrayNode initializeNode = graph.add(new InitializeArrayNode(zero, lengthNode, size, arrayType, newArrayNode.fillContents(), newArrayNode.locked()));
+                InitializeArrayNode initializeNode = graph.add(new InitializeArrayNode(zero, lengthNode, size, arrayType, newArrayNode.fillContents()));
                 graph.replaceFixedWithFixed(newArrayNode, initializeNode);
             } else if (length != null && belowThan(length, MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH)) {
                 // Calculate aligned size
@@ -277,7 +264,7 @@
                 ConstantNode sizeNode = ConstantNode.forInt(size, graph);
                 tlabAllocateNode = graph.add(new TLABAllocateNode(sizeNode));
                 graph.addBeforeFixed(newArrayNode, tlabAllocateNode);
-                InitializeArrayNode initializeNode = graph.add(new InitializeArrayNode(tlabAllocateNode, lengthNode, sizeNode, arrayType, newArrayNode.fillContents(), newArrayNode.locked()));
+                InitializeArrayNode initializeNode = graph.add(new InitializeArrayNode(tlabAllocateNode, lengthNode, sizeNode, arrayType, newArrayNode.fillContents()));
                 graph.replaceFixedWithFixed(newArrayNode, initializeNode);
             } else {
                 Arguments args = new Arguments(allocateArrayAndInitialize);
@@ -296,7 +283,7 @@
 
         @SuppressWarnings("unused")
         public void lower(TLABAllocateNode tlabAllocateNode, LoweringTool tool) {
-            StructuredGraph graph = (StructuredGraph) tlabAllocateNode.graph();
+            StructuredGraph graph = tlabAllocateNode.graph();
             ValueNode size = tlabAllocateNode.size();
             Arguments args = new Arguments(allocate).add("size", size);
 
@@ -307,7 +294,7 @@
 
         @SuppressWarnings("unused")
         public void lower(InitializeObjectNode initializeNode, LoweringTool tool) {
-            StructuredGraph graph = (StructuredGraph) initializeNode.graph();
+            StructuredGraph graph = initializeNode.graph();
             HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) initializeNode.type();
             assert !type.isArray();
             ConstantNode hub = ConstantNode.forConstant(type.klass(), runtime, graph);
@@ -319,7 +306,6 @@
             args.add("hub", hub);
             args.add("prototypeMarkWord", type.prototypeMarkWord());
             args.addConst("size", size).addConst("fillContents", initializeNode.fillContents());
-            args.addConst("locked", initializeNode.locked());
 
             SnippetTemplate template = template(args);
             Debug.log("Lowering initializeObject in %s: node=%s, template=%s, arguments=%s", graph, initializeNode, template, args);
@@ -328,7 +314,7 @@
 
         @SuppressWarnings("unused")
         public void lower(InitializeArrayNode initializeNode, LoweringTool tool) {
-            StructuredGraph graph = (StructuredGraph) initializeNode.graph();
+            StructuredGraph graph = initializeNode.graph();
             HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) initializeNode.type();
             ResolvedJavaType elementType = type.getComponentType();
             assert elementType != null;
@@ -345,7 +331,6 @@
             args.add("prototypeMarkWord", type.prototypeMarkWord());
             args.addConst("headerSize", headerSize);
             args.addConst("fillContents", initializeNode.fillContents());
-            args.addConst("locked", initializeNode.locked());
 
             SnippetTemplate template = template(args);
             Debug.log("Lowering initializeArray in %s: node=%s, template=%s, arguments=%s", graph, initializeNode, template, args);
@@ -354,7 +339,7 @@
 
         @SuppressWarnings("unused")
         public void lower(NewMultiArrayNode newmultiarrayNode, LoweringTool tool) {
-            StructuredGraph graph = (StructuredGraph) newmultiarrayNode.graph();
+            StructuredGraph graph = newmultiarrayNode.graph();
             int rank = newmultiarrayNode.dimensionCount();
             ValueNode[] dims = new ValueNode[rank];
             for (int i = 0; i < newmultiarrayNode.dimensionCount(); i++) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java	Mon May 13 17:11:31 2013 +0200
@@ -103,7 +103,7 @@
                     newEntryState[i] = originalState.getEntry(i);
                 }
                 VirtualObjectNode newVirtual = originalVirtual.duplicate();
-                tool.createVirtualObject(newVirtual, newEntryState, 0);
+                tool.createVirtualObject(newVirtual, newEntryState, null);
                 tool.replaceWithVirtual(newVirtual);
             }
         } else {
@@ -123,18 +123,9 @@
                     final LoadFieldNode[] loads = new LoadFieldNode[fields.length];
                     for (int i = 0; i < fields.length; i++) {
                         state[i] = loads[i] = new LoadFieldNode(obj, fields[i]);
+                        tool.addNode(loads[i]);
                     }
-
-                    final StructuredGraph structuredGraph = (StructuredGraph) graph();
-                    tool.customAction(new Runnable() {
-
-                        public void run() {
-                            for (LoadFieldNode load : loads) {
-                                structuredGraph.addBeforeFixed(ObjectCloneNode.this, structuredGraph.add(load));
-                            }
-                        }
-                    });
-                    tool.createVirtualObject(newVirtual, state, 0);
+                    tool.createVirtualObject(newVirtual, state, null);
                     tool.replaceWithVirtual(newVirtual);
                 }
             }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java	Mon May 13 17:11:31 2013 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
-import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*;
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 import static com.oracle.graal.replacements.nodes.BranchProbabilityNode.*;
 
 import java.lang.reflect.*;
@@ -54,7 +54,7 @@
         int instanceSize = layoutHelper;
         Pointer memory = NewObjectSnippets.allocate(instanceSize);
         Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION);
-        Object result = NewObjectSnippets.initializeObject((Word) memory, hub, prototypeMarkWord, instanceSize, false, false);
+        Object result = NewObjectSnippets.initializeObject((Word) memory, hub, prototypeMarkWord, instanceSize, false);
 
         memory = Word.fromObject(result);
         for (int offset = 2 * wordSize(); offset < instanceSize; offset += wordSize()) {
@@ -72,7 +72,7 @@
 
         Pointer memory = NewObjectSnippets.allocate(sizeInBytes);
         Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION);
-        Object result = NewObjectSnippets.initializeArray((Word) memory, hub, arrayLength, sizeInBytes, prototypeMarkWord, headerSize, false, false);
+        Object result = NewObjectSnippets.initializeArray((Word) memory, hub, arrayLength, sizeInBytes, prototypeMarkWord, headerSize, false);
 
         memory = Word.fromObject(result);
         for (int offset = headerSize; offset < sizeInBytes; offset += wordSize()) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectSubstitutions.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectSubstitutions.java	Mon May 13 17:11:31 2013 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
-import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*;
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 import static com.oracle.graal.nodes.extended.UnsafeCastNode.*;
 
 import com.oracle.graal.api.replacements.*;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ReflectionGetCallerClassNode.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,100 @@
+/*
+ * 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.hotspot.replacements;
+
+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.nodes.spi.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.replacements.nodes.*;
+
+public class ReflectionGetCallerClassNode extends MacroNode implements Canonicalizable, Lowerable {
+
+    public ReflectionGetCallerClassNode(Invoke invoke) {
+        super(invoke);
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool) {
+        ConstantNode callerClassNode = getCallerClassNode(tool.runtime());
+        if (callerClassNode != null) {
+            return callerClassNode;
+        }
+        return this;
+    }
+
+    @Override
+    public void lower(LoweringTool tool, LoweringType loweringType) {
+        ConstantNode callerClassNode = getCallerClassNode(tool.getRuntime());
+
+        if (callerClassNode != null) {
+            graph().replaceFixedWithFloating(this, callerClassNode);
+        } else {
+            graph().replaceFixedWithFixed(this, createInvoke());
+        }
+    }
+
+    /**
+     * If inlining is deep enough this method returns a {@link ConstantNode} of the caller class by
+     * walking the the stack.
+     * 
+     * @param runtime
+     * @return ConstantNode of the caller class, or null
+     */
+    private ConstantNode getCallerClassNode(MetaAccessProvider runtime) {
+        if (!GraalOptions.IntrinsifyReflectionMethods) {
+            return null;
+        }
+
+        // Walk back up the frame states to find the caller at the required depth.
+        FrameState state = stateAfter();
+
+        // Cf. JVM_GetCallerClass
+        // NOTE: Start the loop at depth 1 because the current frame state does
+        // not include the Reflection.getCallerClass() frame.
+        for (int n = 1; state != null; state = state.outerFrameState(), n++) {
+            HotSpotResolvedJavaMethod method = (HotSpotResolvedJavaMethod) state.method();
+            switch (n) {
+                case 0:
+                    throw GraalInternalError.shouldNotReachHere("current frame state does not include the Reflection.getCallerClass frame");
+                case 1:
+                    // Frame 0 and 1 must be caller sensitive (see JVM_GetCallerClass).
+                    if (!method.isCallerSensitive()) {
+                        return null;  // bail-out; let JVM_GetCallerClass do the work
+                    }
+                    break;
+                default:
+                    if (!method.ignoredBySecurityStackWalk()) {
+                        // We have reached the desired frame; return the holder class.
+                        HotSpotResolvedObjectType callerClass = (HotSpotResolvedObjectType) method.getDeclaringClass();
+                        return ConstantNode.forObject(callerClass.mirror(), runtime, graph());
+                    }
+                    break;
+            }
+        }
+        return null;  // bail-out; let JVM_GetCallerClass do the work
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ReflectionSubstitutions.java	Mon May 13 17:11:31 2013 +0200
@@ -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.hotspot.replacements;
+
+import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.nodes.spi.MacroSubstitution;
+
+/**
+ * Substitutions for {@link sun.reflect.Reflection} methods.
+ */
+@ClassSubstitution(sun.reflect.Reflection.class)
+public class ReflectionSubstitutions {
+
+    @MacroSubstitution(macro = ReflectionGetCallerClassNode.class, optional = true)
+    public static native Class<?> getCallerClass();
+
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/SystemSubstitutions.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/SystemSubstitutions.java	Mon May 13 17:11:31 2013 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
-import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*;
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 import static com.oracle.graal.replacements.nodes.BranchProbabilityNode.*;
 
 import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ThreadSubstitutions.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ThreadSubstitutions.java	Mon May 13 17:11:31 2013 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
-import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*;
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.hotspot.nodes.*;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/TypeCheckSnippetUtils.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/TypeCheckSnippetUtils.java	Mon May 13 17:11:31 2013 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
-import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*;
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 import static com.oracle.graal.replacements.nodes.BranchProbabilityNode.*;
 
 import java.util.*;
@@ -33,16 +33,19 @@
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.word.*;
 
+//JaCoCo Exclude
+
 /**
  * Utilities and common code paths used by the type check snippets.
  */
 public class TypeCheckSnippetUtils {
 
-    public static final Object TYPE_DISPLAY_LOCATION = LocationNode.createLocation("TypeDisplay");
+    public static final LocationIdentity TYPE_DISPLAY_LOCATION = LocationNode.createLocation("TypeDisplay");
 
     static boolean checkSecondarySubType(Word t, Word s) {
         // if (S.cache == T) return true
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/WriteBarrierSnippets.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/WriteBarrierSnippets.java	Mon May 13 17:11:31 2013 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
-import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*;
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 import static com.oracle.graal.replacements.SnippetTemplate.*;
 
 import com.oracle.graal.api.code.*;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/CRuntimeStub.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.stubs;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.replacements.SnippetTemplate.Arguments;
+import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo;
+
+/**
+ * Base class for a stub that saves registers around a C runtime call.
+ */
+public abstract class CRuntimeStub extends SnippetStub {
+
+    public CRuntimeStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) {
+        super(runtime, replacements, target, linkage);
+    }
+
+    @Override
+    protected Arguments makeArguments(SnippetInfo stub) {
+        Arguments args = new Arguments(stub);
+        for (int i = 0; i < stub.getParameterCount(); i++) {
+            args.add(stub.getParameterName(i), null);
+        }
+        return args;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/CreateNullPointerExceptionStub.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,58 @@
+/*
+ * 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.hotspot.stubs;
+
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.code.RuntimeCallTarget.*;
+import com.oracle.graal.graph.Node.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.replacements.*;
+import com.oracle.graal.word.*;
+
+/**
+ * Stub called to create a {@link NullPointerException}.
+ */
+public class CreateNullPointerExceptionStub extends CRuntimeStub {
+
+    public CreateNullPointerExceptionStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) {
+        super(runtime, replacements, target, linkage);
+    }
+
+    @Snippet
+    private static Object createNullPointerException() {
+        createNullPointerExceptionC(CREATE_NULL_POINTER_EXCEPTION_C, thread());
+        StubUtil.handlePendingException(true);
+        return StubUtil.verifyObject(getAndClearObjectResult(thread()));
+    }
+
+    public static final Descriptor CREATE_NULL_POINTER_EXCEPTION_C = StubUtil.descriptorFor(CreateNullPointerExceptionStub.class, "createNullPointerExceptionC", false);
+
+    @NodeIntrinsic(CRuntimeCall.class)
+    public static native void createNullPointerExceptionC(@ConstantNodeParameter Descriptor createNullPointerExceptionC, Word thread);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/CreateOutOfBoundsExceptionStub.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,58 @@
+/*
+ * 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.hotspot.stubs;
+
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.code.RuntimeCallTarget.*;
+import com.oracle.graal.graph.Node.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.replacements.*;
+import com.oracle.graal.word.*;
+
+/**
+ * Stub called to create a {@link ArrayIndexOutOfBoundsException}.
+ */
+public class CreateOutOfBoundsExceptionStub extends CRuntimeStub {
+
+    public CreateOutOfBoundsExceptionStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) {
+        super(runtime, replacements, target, linkage);
+    }
+
+    @Snippet
+    private static Object createOutOfBoundsException(int index) {
+        createOutOfBoundsExceptionC(CREATE_OUT_OF_BOUNDS_C, thread(), index);
+        StubUtil.handlePendingException(true);
+        return StubUtil.verifyObject(getAndClearObjectResult(thread()));
+    }
+
+    public static final Descriptor CREATE_OUT_OF_BOUNDS_C = StubUtil.descriptorFor(CreateOutOfBoundsExceptionStub.class, "createOutOfBoundsExceptionC", false);
+
+    @NodeIntrinsic(CRuntimeCall.class)
+    public static native void createOutOfBoundsExceptionC(@ConstantNodeParameter Descriptor createOutOfBoundsExceptionC, Word thread, int index);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ExceptionHandlerStub.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,131 @@
+/*
+ * 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.hotspot.stubs;
+
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+import static com.oracle.graal.hotspot.nodes.PatchReturnAddressNode.*;
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
+
+import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.graph.Node.ConstantNodeParameter;
+import com.oracle.graal.graph.Node.NodeIntrinsic;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.bridge.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.replacements.*;
+import com.oracle.graal.replacements.Snippet.Fold;
+import com.oracle.graal.word.*;
+
+/**
+ * Stub called by the {@linkplain Marks#MARK_EXCEPTION_HANDLER_ENTRY exception handler entry point}
+ * in a compiled method. This entry point is used when returning to a method to handle an exception
+ * thrown by a callee. It is not used for routing implicit exceptions. Therefore, it does not need
+ * to save any registers as HotSpot uses a caller save convention.
+ * <p>
+ * The descriptor for a call to this stub is {@link HotSpotBackend#EXCEPTION_HANDLER}.
+ */
+public class ExceptionHandlerStub extends CRuntimeStub {
+
+    public ExceptionHandlerStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) {
+        super(runtime, replacements, target, linkage);
+    }
+
+    /**
+     * This stub is called when returning to a method to handle an exception thrown by a callee. It
+     * is not used for routing implicit exceptions. Therefore, it does not need to save any
+     * registers as HotSpot uses a caller save convention.
+     */
+    @Override
+    public boolean preservesRegisters() {
+        return false;
+    }
+
+    @Snippet
+    private static void exceptionHandler(Object exception, Word exceptionPc) {
+        checkNoExceptionInThread(assertionsEnabled());
+        checkExceptionNotNull(assertionsEnabled(), exception);
+        writeExceptionOop(thread(), exception);
+        writeExceptionPc(thread(), exceptionPc);
+        if (logging()) {
+            StubUtil.printf("handling exception %p (", Word.fromObject(exception).rawValue());
+            StubUtil.decipher(Word.fromObject(exception).rawValue());
+            StubUtil.printf(") at %p (", Word.fromObject(exception).rawValue(), exceptionPc.rawValue());
+            StubUtil.decipher(exceptionPc.rawValue());
+            StubUtil.printf(")\n");
+        }
+
+        // patch throwing pc into return address so that deoptimization finds the right debug info
+        patchReturnAddress(exceptionPc);
+
+        Word handlerPc = exceptionHandlerForPc(EXCEPTION_HANDLER_FOR_PC, thread());
+
+        if (logging()) {
+            StubUtil.printf("handler for exception %p at %p is at %p (", Word.fromObject(exception).rawValue(), exceptionPc.rawValue(), handlerPc.rawValue());
+            StubUtil.decipher(handlerPc.rawValue());
+            StubUtil.printf(")\n");
+        }
+
+        // patch the return address so that this stub returns to the exception handler
+        patchReturnAddress(handlerPc);
+    }
+
+    static void checkNoExceptionInThread(boolean enabled) {
+        if (enabled) {
+            Object currentException = readExceptionOop(thread());
+            if (currentException != null) {
+                StubUtil.fatal("exception object in thread must be null, not %p", Word.fromObject(currentException).rawValue());
+            }
+            Word currentExceptionPc = readExceptionPc(thread());
+            if (currentExceptionPc.notEqual(Word.zero())) {
+                StubUtil.fatal("exception PC in thread must be zero, not %p", currentExceptionPc.rawValue());
+            }
+        }
+    }
+
+    static void checkExceptionNotNull(boolean enabled, Object exception) {
+        if (enabled && exception == null) {
+            StubUtil.fatal("exception must not be null");
+        }
+    }
+
+    @Fold
+    private static boolean logging() {
+        return Boolean.getBoolean("graal.logExceptionHandlerStub");
+    }
+
+    @Fold
+    @SuppressWarnings("all")
+    private static boolean assertionsEnabled() {
+        boolean enabled = false;
+        assert enabled = true;
+        return enabled || graalRuntime().getConfig().cAssertions;
+    }
+
+    public static final Descriptor EXCEPTION_HANDLER_FOR_PC = StubUtil.descriptorFor(ExceptionHandlerStub.class, "exceptionHandlerForPc", false);
+
+    @NodeIntrinsic(value = CRuntimeCall.class, setStampFromReturnType = true)
+    public static native Word exceptionHandlerForPc(@ConstantNodeParameter Descriptor exceptionHandlerForPc, Word thread);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/LogObjectStub.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,56 @@
+/*
+ * 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.hotspot.stubs;
+
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
+
+import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.graph.Node.ConstantNodeParameter;
+import com.oracle.graal.graph.Node.NodeIntrinsic;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.replacements.*;
+import com.oracle.graal.word.*;
+
+/**
+ * Stub called from {@link Log}.
+ */
+public class LogObjectStub extends CRuntimeStub {
+
+    public LogObjectStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) {
+        super(runtime, replacements, target, linkage);
+    }
+
+    @Snippet
+    private static void logObject(Object object, int flags) {
+        logObjectC(LOG_OBJECT_C, thread(), object, flags);
+    }
+
+    public static final Descriptor LOG_OBJECT_C = StubUtil.descriptorFor(LogObjectStub.class, "logObjectC", false);
+
+    @NodeIntrinsic(CRuntimeCall.class)
+    public static native void logObjectC(@ConstantNodeParameter Descriptor logObjectC, Word thread, Object object, int flags);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/LogPrimitiveStub.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,56 @@
+/*
+ * 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.hotspot.stubs;
+
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
+
+import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.graph.Node.ConstantNodeParameter;
+import com.oracle.graal.graph.Node.NodeIntrinsic;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.replacements.*;
+import com.oracle.graal.word.*;
+
+/**
+ * Stub called from {@link Log}.
+ */
+public class LogPrimitiveStub extends CRuntimeStub {
+
+    public LogPrimitiveStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) {
+        super(runtime, replacements, target, linkage);
+    }
+
+    @Snippet
+    private static void logPrimitive(char typeChar, long value, boolean newline) {
+        logPrimitivefC(LOG_PRIMITIVE_C, thread(), typeChar, value, newline);
+    }
+
+    public static final Descriptor LOG_PRIMITIVE_C = StubUtil.descriptorFor(LogPrimitiveStub.class, "logPrimitivefC", false);
+
+    @NodeIntrinsic(CRuntimeCall.class)
+    public static native void logPrimitivefC(@ConstantNodeParameter Descriptor logPrimitivefC, Word thread, char typeChar, long value, boolean newline);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/LogPrintfStub.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,56 @@
+/*
+ * 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.hotspot.stubs;
+
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
+
+import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.graph.Node.ConstantNodeParameter;
+import com.oracle.graal.graph.Node.NodeIntrinsic;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.replacements.*;
+import com.oracle.graal.word.*;
+
+/**
+ * Stub called from {@link Log}.
+ */
+public class LogPrintfStub extends CRuntimeStub {
+
+    public LogPrintfStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) {
+        super(runtime, replacements, target, linkage);
+    }
+
+    @Snippet
+    private static void logPrintf(String format, long v1, long v2, long v3) {
+        logPrintfC(LOG_PRINTF_C, thread(), format, v1, v2, v3);
+    }
+
+    public static final Descriptor LOG_PRINTF_C = StubUtil.descriptorFor(LogPrintfStub.class, "logPrintfC", false);
+
+    @NodeIntrinsic(CRuntimeCall.class)
+    public static native void logPrintfC(@ConstantNodeParameter Descriptor logPrintfC, Word thread, String format, long v1, long v2, long v3);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/MonitorEnterStub.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,57 @@
+/*
+ * 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.hotspot.stubs;
+
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
+
+import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.graph.Node.ConstantNodeParameter;
+import com.oracle.graal.graph.Node.NodeIntrinsic;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.replacements.*;
+import com.oracle.graal.word.*;
+
+/**
+ * Stub called from {@link MonitorEnterStubCall}.
+ */
+public class MonitorEnterStub extends CRuntimeStub {
+
+    public MonitorEnterStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) {
+        super(runtime, replacements, target, linkage);
+    }
+
+    @Snippet
+    private static void monitorenter(Object object, Word lock) {
+        monitorenterC(MONITORENTER_C, thread(), object, lock);
+        StubUtil.handlePendingException(false);
+    }
+
+    public static final Descriptor MONITORENTER_C = StubUtil.descriptorFor(MonitorEnterStub.class, "monitorenterC", false);
+
+    @NodeIntrinsic(CRuntimeCall.class)
+    public static native void monitorenterC(@ConstantNodeParameter Descriptor monitorenterC, Word thread, Object object, Word lock);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/MonitorExitStub.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,56 @@
+/*
+ * 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.hotspot.stubs;
+
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
+
+import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.graph.Node.ConstantNodeParameter;
+import com.oracle.graal.graph.Node.NodeIntrinsic;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.replacements.*;
+import com.oracle.graal.word.*;
+
+/**
+ * Stub called from {@link MonitorExitStubCall}.
+ */
+public class MonitorExitStub extends CRuntimeStub {
+
+    public MonitorExitStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) {
+        super(runtime, replacements, target, linkage);
+    }
+
+    @Snippet
+    private static void monitorexit(Object object, Word lock) {
+        monitorexitC(MONITOREXIT_C, thread(), object, lock);
+    }
+
+    public static final Descriptor MONITOREXIT_C = StubUtil.descriptorFor(MonitorExitStub.class, "monitorexitC", false);
+
+    @NodeIntrinsic(CRuntimeCall.class)
+    public static native void monitorexitC(@ConstantNodeParameter Descriptor monitorexitC, Word thread, Object object, Word lock);
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java	Mon May 13 17:11:31 2013 +0200
@@ -22,46 +22,62 @@
  */
 package com.oracle.graal.hotspot.stubs;
 
-import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*;
+import static com.oracle.graal.api.code.DeoptimizationAction.*;
+import static com.oracle.graal.api.meta.DeoptimizationReason.*;
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 import static com.oracle.graal.hotspot.replacements.NewObjectSnippets.*;
 import static com.oracle.graal.hotspot.stubs.NewInstanceStub.*;
 
+import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.Node.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.hotspot.replacements.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.replacements.*;
-import com.oracle.graal.replacements.Snippet.ConstantParameter;
+import com.oracle.graal.replacements.Snippet.*;
 import com.oracle.graal.replacements.SnippetTemplate.Arguments;
 import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo;
 import com.oracle.graal.word.*;
 
 /**
  * Stub implementing the fast path for TLAB refill during instance class allocation. This stub is
- * called from the {@linkplain NewObjectSnippets inline} allocation code when TLAB allocation fails.
- * If this stub fails to refill the TLAB or allocate the object, it calls out to the HotSpot C++
- * runtime for to complete the allocation.
+ * called via {@link NewArrayStubCall} from the {@linkplain NewObjectSnippets inline} allocation
+ * code when TLAB allocation fails. If this stub fails to refill the TLAB or allocate the object, it
+ * calls out to the HotSpot C++ runtime to complete the allocation.
  */
-public class NewArrayStub extends Stub {
+public class NewArrayStub extends SnippetStub {
 
     public NewArrayStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) {
-        super(runtime, replacements, target, linkage, "newArray");
+        super(runtime, replacements, target, linkage);
     }
 
     @Override
     protected Arguments makeArguments(SnippetInfo stub) {
         HotSpotResolvedObjectType intArrayType = (HotSpotResolvedObjectType) runtime.lookupJavaType(int[].class);
 
+        // RuntimeStub cannot (currently) support oops or metadata embedded in the code so we
+        // convert the hub (i.e., Klass*) for int[] to be a naked word. This should be safe since
+        // the int[] class will never be unloaded.
+        Constant intArrayHub = intArrayType.klass();
+        intArrayHub = Constant.forIntegerKind(graalRuntime().getTarget().wordKind, intArrayHub.asLong(), null);
+
         Arguments args = new Arguments(stub);
         args.add("hub", null);
         args.add("length", null);
-        args.addConst("intArrayHub", intArrayType.klass());
-        args.addConst("log", Boolean.getBoolean("graal.logNewArrayStub"));
+        args.addConst("intArrayHub", intArrayHub);
         return args;
     }
 
+    @Fold
+    private static boolean logging() {
+        return Boolean.getBoolean("graal.logNewArrayStub");
+    }
+
     /**
      * Re-attempts allocation after an initial TLAB allocation failed or was skipped (e.g., due to
      * -XX:-UseTLAB).
@@ -69,30 +85,50 @@
      * @param hub the hub of the object to be allocated
      * @param length the length of the array
      * @param intArrayHub the hub for {@code int[].class}
-     * @param log specifies if logging is enabled
      */
     @Snippet
-    private static Object newArray(Word hub, int length, @ConstantParameter Word intArrayHub, @ConstantParameter boolean log) {
+    private static Object newArray(Word hub, int length, @ConstantParameter Word intArrayHub) {
         int layoutHelper = hub.readInt(layoutHelperOffset(), FINAL_LOCATION);
         int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask();
         int headerSize = (layoutHelper >> layoutHelperHeaderSizeShift()) & layoutHelperHeaderSizeMask();
         int elementKind = (layoutHelper >> layoutHelperElementTypeShift()) & layoutHelperElementTypeMask();
         int sizeInBytes = computeArrayAllocationSize(length, wordSize(), headerSize, log2ElementSize);
-        log(log, "newArray: element kind %d\n", elementKind);
-        log(log, "newArray: array length %d\n", length);
-        log(log, "newArray: array size %d\n", sizeInBytes);
-        log(log, "newArray: hub=%p\n", hub);
+        if (logging()) {
+            StubUtil.printf("newArray: element kind %d\n", elementKind);
+            StubUtil.printf("newArray: array length %d\n", length);
+            StubUtil.printf("newArray: array size %d\n", sizeInBytes);
+            StubUtil.printf("newArray: hub=%p\n", hub.rawValue());
+        }
 
         // check that array length is small enough for fast path.
         if (length <= MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH) {
-            Word memory = refillAllocate(intArrayHub, sizeInBytes, log);
+            Word memory = refillAllocate(intArrayHub, sizeInBytes, logging());
             if (memory.notEqual(0)) {
-                log(log, "newArray: allocated new array at %p\n", memory);
+                if (logging()) {
+                    StubUtil.printf("newArray: allocated new array at %p\n", memory.rawValue());
+                }
                 formatArray(hub, sizeInBytes, length, headerSize, memory, Word.unsigned(arrayPrototypeMarkWord()), true);
-                return verifyOop(memory.toObject());
+                return StubUtil.verifyObject(memory.toObject());
             }
         }
-        log(log, "newArray: calling new_array_slow", 0L);
-        return verifyOop(NewArraySlowStubCall.call(hub, length));
+        if (logging()) {
+            StubUtil.printf("newArray: calling new_array_c\n");
+        }
+
+        newArrayC(NEW_ARRAY_C, thread(), hub, length);
+
+        if (clearPendingException(thread())) {
+            if (logging()) {
+                StubUtil.printf("newArray: deoptimizing to caller\n");
+            }
+            getAndClearObjectResult(thread());
+            DeoptimizeCallerNode.deopt(InvalidateReprofile, RuntimeConstraint);
+        }
+        return StubUtil.verifyObject(getAndClearObjectResult(thread()));
     }
+
+    public static final Descriptor NEW_ARRAY_C = StubUtil.descriptorFor(NewArrayStub.class, "newArrayC", false);
+
+    @NodeIntrinsic(CRuntimeCall.class)
+    public static native void newArrayC(@ConstantNodeParameter Descriptor newArrayC, Word thread, Word hub, int length);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java	Mon May 13 17:11:31 2013 +0200
@@ -22,12 +22,18 @@
  */
 package com.oracle.graal.hotspot.stubs;
 
+import static com.oracle.graal.api.code.DeoptimizationAction.*;
+import static com.oracle.graal.api.meta.DeoptimizationReason.*;
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 import static com.oracle.graal.hotspot.nodes.DirectCompareAndSwapNode.*;
-import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*;
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 import static com.oracle.graal.hotspot.replacements.NewObjectSnippets.*;
 
+import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.Node.ConstantNodeParameter;
+import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
@@ -42,27 +48,37 @@
 
 /**
  * Stub implementing the fast path for TLAB refill during instance class allocation. This stub is
- * called from the {@linkplain NewObjectSnippets inline} allocation code when TLAB allocation fails.
- * If this stub fails to refill the TLAB or allocate the object, it calls out to the HotSpot C++
- * runtime for to complete the allocation.
+ * called via {@link NewInstanceStubCall} from the {@linkplain NewObjectSnippets inline} allocation
+ * code when TLAB allocation fails. If this stub fails to refill the TLAB or allocate the object, it
+ * calls out to the HotSpot C++ runtime for to complete the allocation.
  */
-public class NewInstanceStub extends Stub {
+public class NewInstanceStub extends SnippetStub {
 
     public NewInstanceStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) {
-        super(runtime, replacements, target, linkage, "newInstance");
+        super(runtime, replacements, target, linkage);
     }
 
     @Override
     protected Arguments makeArguments(SnippetInfo stub) {
         HotSpotResolvedObjectType intArrayType = (HotSpotResolvedObjectType) runtime.lookupJavaType(int[].class);
 
+        // RuntimeStub cannot (currently) support oops or metadata embedded in the code so we
+        // convert the hub (i.e., Klass*) for int[] to be a naked word. This should be safe since
+        // the int[] class will never be unloaded.
+        Constant intArrayHub = intArrayType.klass();
+        intArrayHub = Constant.forIntegerKind(graalRuntime().getTarget().wordKind, intArrayHub.asLong(), null);
+
         Arguments args = new Arguments(stub);
         args.add("hub", null);
-        args.addConst("intArrayHub", intArrayType.klass());
-        args.addConst("log", Boolean.getBoolean("graal.logNewInstanceStub"));
+        args.addConst("intArrayHub", intArrayHub);
         return args;
     }
 
+    @Fold
+    private static boolean logging() {
+        return Boolean.getBoolean("graal.logNewInstanceStub");
+    }
+
     /**
      * Re-attempts allocation after an initial TLAB allocation failed or was skipped (e.g., due to
      * -XX:-UseTLAB).
@@ -71,22 +87,36 @@
      * @param intArrayHub the hub for {@code int[].class}
      */
     @Snippet
-    private static Object newInstance(Word hub, @ConstantParameter Word intArrayHub, @ConstantParameter boolean log) {
+    private static Object newInstance(Word hub, @ConstantParameter Word intArrayHub) {
         int sizeInBytes = hub.readInt(klassInstanceSizeOffset(), FINAL_LOCATION);
         if (!forceSlowPath() && inlineContiguousAllocationSupported()) {
             if (hub.readInt(klassStateOffset(), CLASS_STATE_LOCATION) == klassStateFullyInitialized()) {
-                Word memory = refillAllocate(intArrayHub, sizeInBytes, log);
+                Word memory = refillAllocate(intArrayHub, sizeInBytes, logging());
                 if (memory.notEqual(0)) {
                     Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION);
                     initializeObjectHeader(memory, prototypeMarkWord, hub);
                     for (int offset = 2 * wordSize(); offset < sizeInBytes; offset += wordSize()) {
                         memory.writeWord(offset, Word.zero(), ANY_LOCATION);
                     }
-                    return verifyOop(memory.toObject());
+                    return StubUtil.verifyObject(memory.toObject());
                 }
             }
         }
-        return verifyOop(NewInstanceSlowStubCall.call(hub));
+
+        if (logging()) {
+            StubUtil.printf("newInstance: calling new_instance_c\n");
+        }
+
+        newInstanceC(NEW_INSTANCE_C, thread(), hub);
+
+        if (clearPendingException(thread())) {
+            if (logging()) {
+                StubUtil.printf("newInstance: deoptimizing to caller\n");
+            }
+            getAndClearObjectResult(thread());
+            DeoptimizeCallerNode.deopt(InvalidateReprofile, RuntimeConstraint);
+        }
+        return StubUtil.verifyObject(getAndClearObjectResult(thread()));
     }
 
     /**
@@ -112,10 +142,12 @@
         // calculate amount of free space
         Word tlabFreeSpaceInBytes = end.subtract(top);
 
-        log(log, "refillTLAB: thread=%p\n", thread);
-        log(log, "refillTLAB: top=%p\n", top);
-        log(log, "refillTLAB: end=%p\n", end);
-        log(log, "refillTLAB: tlabFreeSpaceInBytes=%d\n", tlabFreeSpaceInBytes);
+        if (log) {
+            StubUtil.printf("refillTLAB: thread=%p\n", thread.rawValue());
+            StubUtil.printf("refillTLAB: top=%p\n", top.rawValue());
+            StubUtil.printf("refillTLAB: end=%p\n", end.rawValue());
+            StubUtil.printf("refillTLAB: tlabFreeSpaceInBytes=%d\n", tlabFreeSpaceInBytes.rawValue());
+        }
 
         Word tlabFreeSpaceInWords = tlabFreeSpaceInBytes.unsignedShiftRight(log2WordSize());
 
@@ -126,10 +158,14 @@
             if (tlabStats()) {
                 // increment number of refills
                 thread.writeInt(tlabNumberOfRefillsOffset(), thread.readInt(tlabNumberOfRefillsOffset(), TLAB_NOF_REFILLS_LOCATION) + 1, TLAB_NOF_REFILLS_LOCATION);
-                log(log, "thread: %p -- number_of_refills %d\n", thread, thread.readInt(tlabNumberOfRefillsOffset(), TLAB_NOF_REFILLS_LOCATION));
+                if (log) {
+                    StubUtil.printf("thread: %p -- number_of_refills %d\n", thread.rawValue(), thread.readInt(tlabNumberOfRefillsOffset(), TLAB_NOF_REFILLS_LOCATION));
+                }
                 // accumulate wastage
                 Word wastage = thread.readWord(tlabFastRefillWasteOffset(), TLAB_FAST_REFILL_WASTE_LOCATION).add(tlabFreeSpaceInWords);
-                log(log, "thread: %p -- accumulated wastage %d\n", thread, wastage);
+                if (log) {
+                    StubUtil.printf("thread: %p -- accumulated wastage %d\n", thread.rawValue(), wastage.rawValue());
+                }
                 thread.writeWord(tlabFastRefillWasteOffset(), wastage, TLAB_FAST_REFILL_WASTE_LOCATION);
             }
 
@@ -165,7 +201,9 @@
             // Retain TLAB
             Word newRefillWasteLimit = refillWasteLimit.add(tlabRefillWasteIncrement());
             thread.writeWord(tlabRefillWasteLimitOffset(), newRefillWasteLimit, TLAB_REFILL_WASTE_LIMIT_LOCATION);
-            log(log, "refillTLAB: retaining TLAB - newRefillWasteLimit=%p\n", newRefillWasteLimit);
+            if (log) {
+                StubUtil.printf("refillTLAB: retaining TLAB - newRefillWasteLimit=%p\n", newRefillWasteLimit.rawValue());
+            }
 
             if (tlabStats()) {
                 thread.writeInt(tlabSlowAllocationsOffset(), thread.readInt(tlabSlowAllocationsOffset(), TLAB_SLOW_ALLOCATIONS_LOCATION) + 1, TLAB_SLOW_ALLOCATIONS_LOCATION);
@@ -208,4 +246,9 @@
     private static boolean forceSlowPath() {
         return Boolean.getBoolean("graal.newInstanceStub.forceSlowPath");
     }
+
+    public static final Descriptor NEW_INSTANCE_C = StubUtil.descriptorFor(NewInstanceStub.class, "newInstanceC", false);
+
+    @NodeIntrinsic(CRuntimeCall.class)
+    public static native void newInstanceC(@ConstantNodeParameter Descriptor newInstanceC, Word thread, Word hub);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewMultiArrayStub.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,58 @@
+/*
+ * 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.hotspot.stubs;
+
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
+
+import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.graph.Node.ConstantNodeParameter;
+import com.oracle.graal.graph.Node.NodeIntrinsic;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.replacements.*;
+import com.oracle.graal.word.*;
+
+/**
+ * Stub called from {@link NewMultiArrayStubCall}.
+ */
+public class NewMultiArrayStub extends CRuntimeStub {
+
+    public NewMultiArrayStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) {
+        super(runtime, replacements, target, linkage);
+    }
+
+    @Snippet
+    private static Object newMultiArray(Word hub, int rank, Word dims) {
+        newMultiArrayC(NEW_MULTI_ARRAY_C, thread(), hub, rank, dims);
+        StubUtil.handlePendingException(true);
+        return getAndClearObjectResult(thread());
+    }
+
+    public static final Descriptor NEW_MULTI_ARRAY_C = StubUtil.descriptorFor(NewMultiArrayStub.class, "newMultiArrayC", false);
+
+    @NodeIntrinsic(CRuntimeCall.class)
+    public static native void newMultiArrayC(@ConstantNodeParameter Descriptor newArrayC, Word thread, Word hub, int rank, Word dims);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/OSRMigrationEndStub.java	Mon May 13 17:11:31 2013 +0200
@@ -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.hotspot.stubs;
+
+import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.graph.Node.ConstantNodeParameter;
+import com.oracle.graal.graph.Node.NodeIntrinsic;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.replacements.*;
+import com.oracle.graal.word.*;
+
+/**
+ * Stub called from {@link OSRStartNode}.
+ */
+public class OSRMigrationEndStub extends CRuntimeStub {
+
+    public OSRMigrationEndStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) {
+        super(runtime, replacements, target, linkage);
+    }
+
+    @Snippet
+    private static void osrMigrationEnd(Word buffer) {
+        osrMigrationEndC(OSR_MIGRATION_END_C, buffer);
+    }
+
+    public static final Descriptor OSR_MIGRATION_END_C = StubUtil.descriptorFor(OSRMigrationEndStub.class, "osrMigrationEndC", false);
+
+    @NodeIntrinsic(CRuntimeCall.class)
+    public static native void osrMigrationEndC(@ConstantNodeParameter Descriptor osrMigrationEndC, Word buffer);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/RegisterFinalizerStub.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,58 @@
+/*
+ * 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.hotspot.stubs;
+
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
+
+import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.graph.Node.ConstantNodeParameter;
+import com.oracle.graal.graph.Node.NodeIntrinsic;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.replacements.*;
+import com.oracle.graal.word.*;
+
+/**
+ * Stub called from {@link RegisterFinalizerNode}.
+ */
+public class RegisterFinalizerStub extends CRuntimeStub {
+
+    public RegisterFinalizerStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) {
+        super(runtime, replacements, target, linkage);
+    }
+
+    @Snippet
+    private static void registerFinalizer(Object object) {
+        registerFinalizerC(REGISTER_FINALIZER_C, thread(), object);
+        StubUtil.handlePendingException(false);
+    }
+
+    public static final Descriptor REGISTER_FINALIZER_C = StubUtil.descriptorFor(RegisterFinalizerStub.class, "registerFinalizerC", false);
+
+    @NodeIntrinsic(CRuntimeCall.class)
+    public static native void registerFinalizerC(@ConstantNodeParameter Descriptor registerFinalizerC, Word thread, Object object);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/RuntimeCallStub.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,244 @@
+/*
+ * 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.hotspot.stubs;
+
+import static com.oracle.graal.api.meta.MetaUtil.*;
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.code.CallingConvention.Type;
+import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.bridge.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.phases.common.*;
+import com.oracle.graal.replacements.*;
+import com.oracle.graal.replacements.nodes.*;
+import com.oracle.graal.word.*;
+import com.oracle.graal.word.phases.*;
+
+/**
+ * Base class for a stub that calls into a HotSpot C/C++ runtime function using the native
+ * {@link CallingConvention}.
+ */
+public class RuntimeCallStub extends Stub {
+
+    /**
+     * The target of the call.
+     */
+    private final HotSpotRuntimeCallTarget target;
+
+    /**
+     * Specifies if the JavaThread value for the current thread is to be prepended to the arguments
+     * for the call to {@link #target}.
+     */
+    protected final boolean prependThread;
+
+    /**
+     * Creates a stub for a call to code at a given address.
+     * 
+     * @param address the address of the code to call
+     * @param sig the signature of the call to this stub
+     * @param prependThread true if the JavaThread value for the current thread is to be prepended
+     *            to the arguments for the call to {@code address}
+     * @param regConfig used to get the calling convention for the call to this stub from Graal
+     *            compiled Java code as well as the calling convention for the call to
+     *            {@code address}
+     * @param vm the Java to HotSpot C/C++ runtime interface
+     */
+    public RuntimeCallStub(long address, Descriptor sig, boolean prependThread, HotSpotRuntime runtime, Replacements replacements, RegisterConfig regConfig, CompilerToVM vm) {
+        super(runtime, replacements, new HotSpotRuntimeCallTarget(sig, 0L, false, createCallingConvention(runtime, regConfig, sig), vm));
+        this.prependThread = prependThread;
+        Class[] targetParameterTypes = createTargetParameters(sig);
+        Descriptor targetSig = new Descriptor(sig.getName() + ":C", sig.hasSideEffect(), sig.getResultType(), targetParameterTypes);
+        CallingConvention targetCc = createCallingConvention(runtime, regConfig, targetSig);
+        target = new HotSpotRuntimeCallTarget(targetSig, address, true, targetCc, vm);
+    }
+
+    /**
+     * Gets the linkage information for the runtime call.
+     */
+    public HotSpotRuntimeCallTarget getTargetLinkage() {
+        return target;
+    }
+
+    private static CallingConvention createCallingConvention(HotSpotRuntime runtime, RegisterConfig regConfig, Descriptor d) {
+        Class<?>[] argumentTypes = d.getArgumentTypes();
+        JavaType[] parameterTypes = new JavaType[argumentTypes.length];
+        for (int i = 0; i < parameterTypes.length; ++i) {
+            parameterTypes[i] = runtime.lookupJavaType(argumentTypes[i]);
+        }
+        TargetDescription target = graalRuntime().getTarget();
+        JavaType returnType = runtime.lookupJavaType(d.getResultType());
+        return regConfig.getCallingConvention(Type.NativeCall, returnType, parameterTypes, target, false);
+    }
+
+    private Class[] createTargetParameters(Descriptor sig) {
+        Class[] parameters = sig.getArgumentTypes();
+        if (prependThread) {
+            Class[] newParameters = new Class[parameters.length + 1];
+            System.arraycopy(parameters, 0, newParameters, 1, parameters.length);
+            newParameters[0] = Word.class;
+            return newParameters;
+        }
+        return parameters;
+    }
+
+    @Override
+    protected ResolvedJavaMethod getInstalledCodeOwner() {
+        return null;
+    }
+
+    @Override
+    protected Object debugScopeContext() {
+        return new JavaMethod() {
+
+            public Signature getSignature() {
+                Descriptor d = linkage.descriptor;
+                Class<?>[] arguments = d.getArgumentTypes();
+                JavaType[] parameters = new JavaType[arguments.length];
+                for (int i = 0; i < arguments.length; i++) {
+                    parameters[i] = runtime.lookupJavaType(arguments[i]);
+                }
+                return new HotSpotSignature(runtime.lookupJavaType(d.getResultType()), parameters);
+            }
+
+            public String getName() {
+                return linkage.descriptor.getName();
+            }
+
+            public JavaType getDeclaringClass() {
+                return runtime.lookupJavaType(RuntimeCallStub.class);
+            }
+
+            @Override
+            public String toString() {
+                return format("HotSpotStub<%n(%p)>", this);
+            }
+        };
+    }
+
+    @Override
+    protected StructuredGraph getGraph() {
+        Class<?>[] args = linkage.getDescriptor().getArgumentTypes();
+        LocalNode[] locals = new LocalNode[args.length];
+
+        StructuredGraph graph = new StructuredGraph(toString(), null);
+        StubStartNode start = graph.add(new StubStartNode(this));
+        graph.replaceFixed(graph.start(), start);
+
+        ResolvedJavaType accessingClass = runtime.lookupJavaType(getClass());
+        for (int i = 0; i < args.length; i++) {
+            JavaType type = runtime.lookupJavaType(args[i]).resolve(accessingClass);
+            Kind kind = type.getKind().getStackKind();
+            Stamp stamp;
+            if (kind == Kind.Object) {
+                stamp = StampFactory.declared((ResolvedJavaType) type);
+            } else {
+                stamp = StampFactory.forKind(kind);
+            }
+            LocalNode local = graph.unique(new LocalNode(i, stamp));
+            locals[i] = local;
+        }
+
+        // Create target call
+        CRuntimeCall call = createTargetCall(locals, graph, start);
+
+        // Create call to handlePendingException
+        ResolvedJavaMethod hpeMethod = resolveMethod(StubUtil.class, "handlePendingException", boolean.class);
+        JavaType returnType = hpeMethod.getSignature().getReturnType(null);
+        ValueNode[] hpeArgs = {ConstantNode.forBoolean(linkage.getCallingConvention().getReturn().getKind() == Kind.Object, graph)};
+        MethodCallTargetNode hpeTarget = graph.add(new MethodCallTargetNode(InvokeKind.Static, hpeMethod, hpeArgs, returnType));
+        InvokeNode hpeInvoke = graph.add(new InvokeNode(hpeTarget, FrameState.UNKNOWN_BCI));
+        List<ValueNode> emptyStack = Collections.emptyList();
+        hpeInvoke.setStateAfter(graph.add(new FrameState(null, FrameState.INVALID_FRAMESTATE_BCI, new ValueNode[0], emptyStack, new ValueNode[0], false, false)));
+        graph.addAfterFixed(call, hpeInvoke);
+
+        // Create return node
+        ReturnNode ret = graph.add(new ReturnNode(linkage.descriptor.getResultType() == void.class ? null : call));
+        graph.addAfterFixed(hpeInvoke, ret);
+
+        if (Debug.isDumpEnabled()) {
+            Debug.dump(graph, "Initial stub graph");
+        }
+
+        // Inline call to handlePendingException
+        inline(hpeInvoke);
+
+        if (Debug.isDumpEnabled()) {
+            Debug.dump(graph, "Stub graph before compilation");
+        }
+
+        return graph;
+    }
+
+    private CRuntimeCall createTargetCall(LocalNode[] locals, StructuredGraph graph, StubStartNode start) {
+        CRuntimeCall call;
+        ValueNode[] targetArguments;
+        if (prependThread) {
+            ReadRegisterNode thread = graph.add(new ReadRegisterNode(runtime.threadRegister(), true, false));
+            graph.addAfterFixed(start, thread);
+            targetArguments = new ValueNode[1 + locals.length];
+            targetArguments[0] = thread;
+            System.arraycopy(locals, 0, targetArguments, 1, locals.length);
+            call = graph.add(new CRuntimeCall(target.descriptor, targetArguments));
+            graph.addAfterFixed(thread, call);
+        } else {
+            targetArguments = new ValueNode[locals.length];
+            System.arraycopy(locals, 0, targetArguments, 0, locals.length);
+            call = graph.add(new CRuntimeCall(target.descriptor, targetArguments));
+            graph.addAfterFixed(start, call);
+        }
+        return call;
+    }
+
+    private void inline(InvokeNode invoke) {
+        StructuredGraph graph = invoke.graph();
+        ResolvedJavaMethod method = ((MethodCallTargetNode) invoke.callTarget()).targetMethod();
+        ReplacementsImpl repl = new ReplacementsImpl(runtime, new Assumptions(false), runtime.getTarget());
+        StructuredGraph hpeGraph = repl.makeGraph(method, null, null);
+        InliningUtil.inline(invoke, hpeGraph, false);
+        new NodeIntrinsificationPhase(runtime).apply(graph);
+        new WordTypeRewriterPhase(runtime, wordKind()).apply(graph);
+        new DeadCodeEliminationPhase().apply(graph);
+    }
+
+    private ResolvedJavaMethod resolveMethod(Class<?> declaringClass, String name, Class... parameterTypes) {
+        try {
+            return runtime.lookupJavaMethod(declaringClass.getDeclaredMethod(name, parameterTypes));
+        } catch (Exception e) {
+            throw new GraalInternalError(e);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,98 @@
+/*
+ * 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.hotspot.stubs;
+
+import static com.oracle.graal.api.meta.MetaUtil.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.replacements.Snippet.ConstantParameter;
+import com.oracle.graal.replacements.*;
+import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates;
+import com.oracle.graal.replacements.SnippetTemplate.Arguments;
+import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo;
+
+/**
+ * Base class for a stub defined by a snippet.
+ */
+public abstract class SnippetStub extends Stub implements Snippets {
+
+    static class Template extends AbstractTemplates {
+
+        Template(HotSpotRuntime runtime, Replacements replacements, TargetDescription target, Class<? extends Snippets> declaringClass) {
+            super(runtime, replacements, target);
+            this.info = snippet(declaringClass, null);
+        }
+
+        /**
+         * Info for the method implementing the stub.
+         */
+        protected final SnippetInfo info;
+
+        protected StructuredGraph getGraph(Arguments args) {
+            SnippetTemplate template = template(args);
+            return template.copySpecializedGraph();
+        }
+    }
+
+    protected final Template snippet;
+
+    /**
+     * Creates a new snippet stub.
+     * 
+     * @param linkage linkage details for a call to the stub
+     */
+    public SnippetStub(HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) {
+        super(runtime, replacements, linkage);
+        this.snippet = new Template(runtime, replacements, target, getClass());
+    }
+
+    @Override
+    protected StructuredGraph getGraph() {
+        return snippet.getGraph(makeArguments(snippet.info));
+    }
+
+    /**
+     * Adds the {@linkplain ConstantParameter constant} arguments of this stub.
+     */
+    protected abstract Arguments makeArguments(SnippetInfo stub);
+
+    @Override
+    protected Object debugScopeContext() {
+        return getInstalledCodeOwner();
+    }
+
+    @Override
+    public ResolvedJavaMethod getInstalledCodeOwner() {
+        return snippet.info.getMethod();
+    }
+
+    @Override
+    public String toString() {
+        return "Stub<" + format("%h.%n", getInstalledCodeOwner()) + ">";
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java	Mon May 13 17:11:31 2013 +0200
@@ -22,51 +22,39 @@
  */
 package com.oracle.graal.hotspot.stubs;
 
-import static com.oracle.graal.hotspot.nodes.CStringNode.*;
+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.code.RuntimeCallTarget.Descriptor;
 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.internal.*;
-import com.oracle.graal.graph.Node.ConstantNodeParameter;
-import com.oracle.graal.graph.Node.NodeIntrinsic;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.bridge.CompilerToVM.CodeInstallResult;
 import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.PhasePlan.PhasePosition;
-import com.oracle.graal.replacements.*;
-import com.oracle.graal.replacements.Snippet.ConstantParameter;
-import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates;
-import com.oracle.graal.replacements.SnippetTemplate.Arguments;
-import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo;
-import com.oracle.graal.word.*;
+
+//JaCoCo Exclude
 
 /**
- * Base class for implementing some low level code providing the out-of-line slow path for a
- * snippet. A concrete stub is defined a subclass of this class.
- * <p>
- * Implementation detail: The stub classes re-use some of the functionality for {@link Snippet}s
- * purely for convenience (e.g., can re-use the {@link ReplacementsImpl}).
+ * Base class for implementing some low level code providing the out-of-line slow path for a snippet
+ * and/or a callee saved call to a HotSpot C/C++ runtime function or even a another compiled Java
+ * method.
  */
-public abstract class Stub extends AbstractTemplates implements Snippets {
+public abstract class Stub {
 
     /**
-     * The method implementing the stub.
-     */
-    protected final SnippetInfo stubInfo;
-
-    /**
-     * The linkage information for the stub.
+     * The linkage information for a call to this stub from compiled code.
      */
     protected final HotSpotRuntimeCallTarget linkage;
 
@@ -76,139 +64,125 @@
     protected InstalledCode code;
 
     /**
-     * The registers defined by this stub.
+     * The registers destroyed by this stub.
      */
-    private Set<Register> definedRegisters;
+    private Set<Register> destroyedRegisters;
 
-    public void initDefinedRegisters(Set<Register> registers) {
+    public void initDestroyedRegisters(Set<Register> registers) {
         assert registers != null;
-        assert definedRegisters == null : "cannot redefine";
-        definedRegisters = registers;
-    }
-
-    public Set<Register> getDefinedRegisters() {
-        assert definedRegisters != null : "not yet initialized";
-        return definedRegisters;
+        assert destroyedRegisters == null || registers.equals(destroyedRegisters) : "cannot redefine";
+        destroyedRegisters = registers;
     }
 
     /**
-     * Creates a new stub container..
+     * Gets the registers defined by this stub. These are the temporaries of this stub and must thus
+     * be caller saved by a callers of this stub.
+     */
+    public Set<Register> getDestroyedRegisters() {
+        assert destroyedRegisters != null : "not yet initialized";
+        return destroyedRegisters;
+    }
+
+    /**
+     * Determines if this stub preserves all registers apart from those it
+     * {@linkplain #getDestroyedRegisters() destroys}.
+     */
+    public boolean preservesRegisters() {
+        return true;
+    }
+
+    protected final HotSpotRuntime runtime;
+
+    protected final Replacements replacements;
+
+    /**
+     * Creates a new stub.
      * 
      * @param linkage linkage details for a call to the stub
      */
-    public Stub(HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage, String methodName) {
-        super(runtime, replacements, target);
-        this.stubInfo = snippet(getClass(), methodName);
+    public Stub(HotSpotRuntime runtime, Replacements replacements, HotSpotRuntimeCallTarget linkage) {
         this.linkage = linkage;
+        this.runtime = runtime;
+        this.replacements = replacements;
+    }
 
+    /**
+     * Gets the linkage for a call to this stub from compiled code.
+     */
+    public HotSpotRuntimeCallTarget getLinkage() {
+        return linkage;
     }
 
     /**
-     * Adds the {@linkplain ConstantParameter constant} arguments of this stub.
+     * Gets the graph that from which the code for this stub will be compiled.
      */
-    protected abstract Arguments makeArguments(SnippetInfo stub);
+    protected abstract StructuredGraph getGraph();
 
-    protected HotSpotRuntime runtime() {
-        return (HotSpotRuntime) runtime;
+    @Override
+    public String toString() {
+        return "Stub<" + linkage.getDescriptor() + ">";
     }
 
     /**
-     * Gets the method implementing this stub.
+     * Gets the method the stub's code will be {@linkplain InstalledCode#getMethod() associated}
+     * with once installed. This may be null.
      */
-    public ResolvedJavaMethod getMethod() {
-        return stubInfo.getMethod();
-    }
+    protected abstract ResolvedJavaMethod getInstalledCodeOwner();
 
-    public HotSpotRuntimeCallTarget getLinkage() {
-        return linkage;
-    }
+    /**
+     * Gets a context object for the debug scope created when producing the code for this stub.
+     */
+    protected abstract Object debugScopeContext();
 
     /**
      * Gets the code for this stub, compiling it first if necessary.
      */
     public synchronized InstalledCode getCode(final Backend backend) {
         if (code == null) {
-            Debug.sandbox("CompilingStub", new Object[]{runtime(), getMethod()}, DebugScope.getConfig(), new Runnable() {
+            Debug.sandbox("CompilingStub", new Object[]{runtime, debugScopeContext()}, DebugScope.getConfig(), new Runnable() {
 
                 @Override
                 public void run() {
 
-                    Arguments args = makeArguments(stubInfo);
-                    SnippetTemplate template = template(args);
-                    StructuredGraph graph = template.copySpecializedGraph();
+                    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();
                     GraphBuilderPhase graphBuilderPhase = new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getDefault(), OptimisticOptimizations.ALL);
                     phasePlan.addPhase(PhasePosition.AFTER_PARSING, graphBuilderPhase);
-                    final CompilationResult compResult = GraalCompiler.compileMethod(runtime(), replacements, backend, runtime().getTarget(), getMethod(), graph, null, phasePlan,
+                    CallingConvention cc = linkage.getCallingConvention();
+                    final CompilationResult compResult = GraalCompiler.compileGraph(graph, cc, getInstalledCodeOwner(), runtime, replacements, backend, runtime.getTarget(), null, phasePlan,
                                     OptimisticOptimizations.ALL, new SpeculationLog());
 
-                    assert definedRegisters != null;
+                    assert destroyedRegisters != null;
                     code = Debug.scope("CodeInstall", new Callable<InstalledCode>() {
 
                         @Override
                         public InstalledCode call() {
-                            InstalledCode installedCode = runtime().addMethod(getMethod(), compResult);
-                            assert installedCode != null : "error installing stub " + getMethod();
+                            Stub stub = Stub.this;
+                            HotSpotInstalledCode installedCode = new HotSpotInstalledCode(stub);
+                            HotSpotCompilationResult hsCompResult = new HotSpotCompilationResult(stub, compResult);
+                            CodeInstallResult result = graalRuntime().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");
                             }
+                            // TTY.println(stub.toString());
+                            // TTY.println(runtime.disassemble(installedCode));
                             return installedCode;
                         }
                     });
 
                 }
             });
-            assert code != null : "error installing stub " + getMethod();
+            assert code != null : "error installing stub " + this;
         }
         return code;
     }
-
-    static void log(boolean enabled, String format, long value) {
-        if (enabled) {
-            printf(format, value);
-        }
-    }
-
-    static void log(boolean enabled, String format, WordBase value) {
-        if (enabled) {
-            printf(format, value.rawValue());
-        }
-    }
-
-    static void log(boolean enabled, String format, Word v1, long v2) {
-        if (enabled) {
-            printf(format, v1.rawValue(), v2);
-        }
-    }
-
-    static void log(boolean enabled, String format, Word v1, Word v2) {
-        if (enabled) {
-            printf(format, v1.rawValue(), v2.rawValue());
-        }
-    }
-
-    public static final Descriptor STUB_PRINTF = new Descriptor("stubPrintf", false, void.class, Word.class, long.class, long.class, long.class);
-
-    @NodeIntrinsic(RuntimeCallNode.class)
-    private static native void printf(@ConstantNodeParameter Descriptor stubPrintf, Word format, long v1, long v2, long v3);
-
-    /**
-     * Prints a formatted string to the log stream.
-     * 
-     * @param format a C style printf format value that can contain at most one conversion specifier
-     *            (i.e., a sequence of characters starting with '%').
-     * @param value the value associated with the conversion specifier
-     */
-    public static void printf(String format, long value) {
-        printf(STUB_PRINTF, cstring(format), value, 0L, 0L);
-    }
-
-    public static void printf(String format, long v1, long v2) {
-        printf(STUB_PRINTF, cstring(format), v1, v2, 0L);
-    }
-
-    public static void printf(String format, long v1, long v2, long v3) {
-        printf(STUB_PRINTF, cstring(format), v1, v2, v3);
-    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/StubUtil.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,243 @@
+/*
+ * 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.hotspot.stubs;
+
+import static com.oracle.graal.api.code.DeoptimizationAction.*;
+import static com.oracle.graal.api.meta.DeoptimizationReason.*;
+import static com.oracle.graal.hotspot.nodes.CStringNode.*;
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
+import static com.oracle.graal.word.Word.*;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
+import com.oracle.graal.graph.Node.ConstantNodeParameter;
+import com.oracle.graal.graph.Node.NodeIntrinsic;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.replacements.*;
+import com.oracle.graal.replacements.Snippet.Fold;
+import com.oracle.graal.word.*;
+
+//JaCoCo Exclude
+
+/**
+ * A collection of methods used in {@link Stub}s.
+ */
+public class StubUtil {
+
+    public static final Descriptor VM_MESSAGE_C = descriptorFor(StubUtil.class, "vmMessageC", false);
+
+    /**
+     * Looks for a {@link CRuntimeCall} node intrinsic named {@code name} in {@code stubClass} and
+     * returns a {@link Descriptor} based on its signature and the value of {@code hasSideEffect}.
+     */
+    public static Descriptor descriptorFor(Class<?> stubClass, String name, boolean hasSideEffect) {
+        Method found = null;
+        for (Method method : stubClass.getDeclaredMethods()) {
+            if (Modifier.isStatic(method.getModifiers()) && method.getAnnotation(NodeIntrinsic.class) != null && method.getName().equals(name)) {
+                if (method.getAnnotation(NodeIntrinsic.class).value() == CRuntimeCall.class) {
+                    assert found == null : "found more than one C runtime call named " + name + " in " + stubClass;
+                    assert method.getParameterTypes().length != 0 && method.getParameterTypes()[0] == Descriptor.class : "first parameter of C runtime call '" + name + "' in " + stubClass +
+                                    " must be of type " + Descriptor.class.getSimpleName();
+                    found = method;
+                }
+            }
+        }
+        assert found != null : "could not find C runtime call named " + name + " in " + stubClass;
+        List<Class<?>> paramList = Arrays.asList(found.getParameterTypes());
+        Class[] cCallTypes = paramList.subList(1, paramList.size()).toArray(new Class[paramList.size() - 1]);
+        return new Descriptor(name, hasSideEffect, found.getReturnType(), cCallTypes);
+    }
+
+    public static void handlePendingException(boolean isObjectResult) {
+        if (clearPendingException(thread())) {
+            if (isObjectResult) {
+                getAndClearObjectResult(thread());
+            }
+            DeoptimizeCallerNode.deopt(InvalidateReprofile, RuntimeConstraint);
+        }
+    }
+
+    @NodeIntrinsic(CRuntimeCall.class)
+    private static native void vmMessageC(@ConstantNodeParameter Descriptor stubPrintfC, boolean vmError, Word format, long v1, long v2, long v3);
+
+    /**
+     * Prints a message to the log stream.
+     * <p>
+     * <b>Stubs must use this instead of {@link Log#printf(String, long)} to avoid an object
+     * constant in a RuntimeStub.</b>
+     * 
+     * @param message a message string
+     */
+    public static void printf(String message) {
+        vmMessageC(VM_MESSAGE_C, false, cstring(message), 0L, 0L, 0L);
+    }
+
+    /**
+     * Prints a message to the log stream.
+     * <p>
+     * <b>Stubs must use this instead of {@link Log#printf(String, long)} to avoid an object
+     * constant in a RuntimeStub.</b>
+     * 
+     * @param format a C style printf format value
+     * @param value the value associated with the first conversion specifier in {@code format}
+     */
+    public static void printf(String format, long value) {
+        vmMessageC(VM_MESSAGE_C, false, cstring(format), value, 0L, 0L);
+    }
+
+    /**
+     * Prints a message to the log stream.
+     * <p>
+     * <b>Stubs must use this instead of {@link Log#printf(String, long, long)} to avoid an object
+     * constant in a RuntimeStub.</b>
+     * 
+     * @param format a C style printf format value
+     * @param v1 the value associated with the first conversion specifier in {@code format}
+     * @param v2 the value associated with the second conversion specifier in {@code format}
+     */
+    public static void printf(String format, long v1, long v2) {
+        vmMessageC(VM_MESSAGE_C, false, cstring(format), v1, v2, 0L);
+    }
+
+    /**
+     * Prints a message to the log stream.
+     * <p>
+     * <b>Stubs must use this instead of {@link Log#printf(String, long, long, long)} to avoid an
+     * object constant in a RuntimeStub.</b>
+     * 
+     * @param format a C style printf format value
+     * @param v1 the value associated with the first conversion specifier in {@code format}
+     * @param v2 the value associated with the second conversion specifier in {@code format}
+     * @param v3 the value associated with the third conversion specifier in {@code format}
+     */
+    public static void printf(String format, long v1, long v2, long v3) {
+        vmMessageC(VM_MESSAGE_C, false, cstring(format), v1, v2, v3);
+    }
+
+    /**
+     * Analyzes a given value and prints information about it to the log stream.
+     */
+    public static void decipher(long value) {
+        vmMessageC(VM_MESSAGE_C, false, Word.zero(), value, 0L, 0L);
+    }
+
+    /**
+     * Exits the VM with a given error message.
+     * <p>
+     * <b>Stubs must use this instead of {@link VMErrorNode#vmError(String, long)} to avoid an
+     * object constant in a RuntimeStub.</b>
+     * 
+     * @param message an error message
+     */
+    public static void fatal(String message) {
+        vmMessageC(VM_MESSAGE_C, true, cstring(message), 0L, 0L, 0L);
+    }
+
+    /**
+     * Exits the VM with a given error message.
+     * <p>
+     * <b>Stubs must use this instead of {@link Log#printf(String, long, long, long)} to avoid an
+     * object constant in a RuntimeStub.</b>
+     * 
+     * @param format a C style printf format value
+     * @param value the value associated with the first conversion specifier in {@code format}
+     */
+    public static void fatal(String format, long value) {
+        vmMessageC(VM_MESSAGE_C, true, cstring(format), value, 0L, 0L);
+    }
+
+    /**
+     * Exits the VM with a given error message.
+     * <p>
+     * <b>Stubs must use this instead of {@link Log#printf(String, long, long, long)} to avoid an
+     * object constant in a RuntimeStub.</b>
+     * 
+     * @param format a C style printf format value
+     * @param v1 the value associated with the first conversion specifier in {@code format}
+     * @param v2 the value associated with the second conversion specifier in {@code format}
+     */
+    public static void fatal(String format, long v1, long v2) {
+        vmMessageC(VM_MESSAGE_C, true, cstring(format), v1, v2, 0L);
+    }
+
+    /**
+     * Exits the VM with a given error message.
+     * <p>
+     * <b>Stubs must use this instead of {@link Log#printf(String, long, long, long)} to avoid an
+     * object constant in a RuntimeStub.</b>
+     * 
+     * @param format a C style printf format value
+     * @param v1 the value associated with the first conversion specifier in {@code format}
+     * @param v2 the value associated with the second conversion specifier in {@code format}
+     * @param v3 the value associated with the third conversion specifier in {@code format}
+     */
+    public static void fatal(String format, long v1, long v2, long v3) {
+        vmMessageC(VM_MESSAGE_C, true, cstring(format), v1, v2, v3);
+    }
+
+    /**
+     * Verifies that a given object value is well formed if {@code -XX:+VerifyOops} is enabled.
+     */
+    public static Object verifyObject(Object object) {
+        if (verifyOops()) {
+            Word verifyOopCounter = Word.unsigned(verifyOopCounterAddress());
+            verifyOopCounter.writeInt(0, verifyOopCounter.readInt(0) + 1);
+
+            Pointer oop = Word.fromObject(object);
+            if (object != null) {
+                // make sure object is 'reasonable'
+                if (!oop.and(unsigned(verifyOopMask())).equal(unsigned(verifyOopBits()))) {
+                    fatal("oop not in heap: %p", oop.rawValue());
+                }
+
+                Word klass = oop.readWord(hubOffset());
+                if (klass.equal(Word.zero())) {
+                    fatal("klass for oop %p is null", oop.rawValue());
+                }
+            }
+        }
+        return object;
+    }
+
+    @Fold
+    private static long verifyOopCounterAddress() {
+        return config().verifyOopCounterAddress;
+    }
+
+    @Fold
+    private static long verifyOopMask() {
+        return config().verifyOopMask;
+    }
+
+    @Fold
+    private static long verifyOopBits() {
+        return config().verifyOopBits;
+    }
+
+    @Fold
+    private static int hubOffset() {
+        return config().hubOffset;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ThreadIsInterruptedStub.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,58 @@
+/*
+ * 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.hotspot.stubs;
+
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
+
+import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.graph.Node.ConstantNodeParameter;
+import com.oracle.graal.graph.Node.NodeIntrinsic;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.replacements.*;
+import com.oracle.graal.word.*;
+
+/**
+ * Stub called from {@link ThreadIsInterruptedStubCall}.
+ */
+public class ThreadIsInterruptedStub extends CRuntimeStub {
+
+    public ThreadIsInterruptedStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) {
+        super(runtime, replacements, target, linkage);
+    }
+
+    @Snippet
+    private static boolean threadIsInterrupted(Thread receiverThread, boolean clearIsInterrupted) {
+        boolean result = threadIsInterruptedC(THREAD_IS_INTERRUPTED_C, thread(), receiverThread, clearIsInterrupted);
+        StubUtil.handlePendingException(false);
+        return result;
+    }
+
+    public static final Descriptor THREAD_IS_INTERRUPTED_C = StubUtil.descriptorFor(ThreadIsInterruptedStub.class, "threadIsInterruptedC", false);
+
+    @NodeIntrinsic(CRuntimeCall.class)
+    public static native boolean threadIsInterruptedC(@ConstantNodeParameter Descriptor threadIsInterruptedC, Word thread, Thread receiverThread, boolean clearIsInterrupted);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/UnwindExceptionToCallerStub.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,103 @@
+/*
+ * 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.hotspot.stubs;
+
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+import static com.oracle.graal.hotspot.nodes.JumpToExceptionHandlerInCallerNode.*;
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
+import static com.oracle.graal.hotspot.stubs.ExceptionHandlerStub.*;
+
+import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.graph.Node.ConstantNodeParameter;
+import com.oracle.graal.graph.Node.NodeIntrinsic;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.replacements.*;
+import com.oracle.graal.replacements.Snippet.Fold;
+import com.oracle.graal.word.*;
+
+/**
+ * Stub called by an {@link UnwindNode}. This stub executes in the frame of the method throwing an
+ * exception and completes by jumping to the exception handler in the calling frame.
+ */
+public class UnwindExceptionToCallerStub extends CRuntimeStub {
+
+    public UnwindExceptionToCallerStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) {
+        super(runtime, replacements, target, linkage);
+    }
+
+    /**
+     * The current frame is unwound by this stub. Therefore, it does not need to save any registers
+     * as HotSpot uses a caller save convention.
+     */
+    @Override
+    public boolean preservesRegisters() {
+        return false;
+    }
+
+    @Snippet
+    private static void unwindExceptionToCaller(Object exception, Word returnAddress) {
+        Pointer exceptionOop = Word.fromObject(exception);
+        if (logging()) {
+            StubUtil.printf("unwinding exception %p (", exceptionOop.rawValue());
+            StubUtil.decipher(exceptionOop.rawValue());
+            StubUtil.printf(") at %p (", exceptionOop.rawValue(), returnAddress.rawValue());
+            StubUtil.decipher(returnAddress.rawValue());
+            StubUtil.printf(")\n");
+        }
+        checkNoExceptionInThread(assertionsEnabled());
+        checkExceptionNotNull(assertionsEnabled(), exception);
+
+        Word handlerInCallerPc = exceptionHandlerForReturnAddress(EXCEPTION_HANDLER_FOR_RETURN_ADDRESS, thread(), returnAddress);
+
+        if (logging()) {
+            StubUtil.printf("handler for exception %p at return address %p is at %p (", exceptionOop.rawValue(), returnAddress.rawValue(), handlerInCallerPc.rawValue());
+            StubUtil.decipher(handlerInCallerPc.rawValue());
+            StubUtil.printf(")\n");
+        }
+
+        jumpToExceptionHandlerInCaller(handlerInCallerPc, exception, returnAddress);
+    }
+
+    @Fold
+    private static boolean logging() {
+        return Boolean.getBoolean("graal.logUnwindExceptionToCallerStub");
+    }
+
+    @Fold
+    @SuppressWarnings("all")
+    private static boolean assertionsEnabled() {
+        boolean enabled = false;
+        assert enabled = true;
+        return enabled || graalRuntime().getConfig().cAssertions;
+    }
+
+    public static final Descriptor EXCEPTION_HANDLER_FOR_RETURN_ADDRESS = StubUtil.descriptorFor(UnwindExceptionToCallerStub.class, "exceptionHandlerForReturnAddress", false);
+
+    @NodeIntrinsic(value = CRuntimeCall.class, setStampFromReturnType = true)
+    public static native Word exceptionHandlerForReturnAddress(@ConstantNodeParameter Descriptor exceptionHandlerForReturnAddress, Word thread, Word returnAddress);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/VMErrorStub.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,56 @@
+/*
+ * 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.hotspot.stubs;
+
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
+
+import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.graph.Node.ConstantNodeParameter;
+import com.oracle.graal.graph.Node.NodeIntrinsic;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.replacements.*;
+import com.oracle.graal.word.*;
+
+/**
+ * Stub called from {@link VMErrorNode}.
+ */
+public class VMErrorStub extends CRuntimeStub {
+
+    public VMErrorStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) {
+        super(runtime, replacements, target, linkage);
+    }
+
+    @Snippet
+    private static void vmError(String where, String format, long value) {
+        vmErrorC(VM_ERROR_C, thread(), where, format, value);
+    }
+
+    public static final Descriptor VM_ERROR_C = StubUtil.descriptorFor(VMErrorStub.class, "vmErrorC", false);
+
+    @NodeIntrinsic(CRuntimeCall.class)
+    public static native void vmErrorC(@ConstantNodeParameter Descriptor vmErrorC, Word thread, String where, String format, long value);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/VerifyOopStub.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.stubs;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.replacements.*;
+
+/**
+ * Stub called from {@link VerifyOopStubCall}.
+ */
+public class VerifyOopStub extends CRuntimeStub {
+
+    public VerifyOopStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) {
+        super(runtime, replacements, target, linkage);
+    }
+
+    @Snippet
+    private static Object verifyOop(Object object) {
+        return StubUtil.verifyObject(object);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/WriteBarrierPostStub.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,56 @@
+/*
+ * 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.hotspot.stubs;
+
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
+
+import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.graph.Node.ConstantNodeParameter;
+import com.oracle.graal.graph.Node.NodeIntrinsic;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.replacements.*;
+import com.oracle.graal.word.*;
+
+/**
+ * Stub called from {@link WriteBarrierPostStubCall}.
+ */
+public class WriteBarrierPostStub extends CRuntimeStub {
+
+    public WriteBarrierPostStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) {
+        super(runtime, replacements, target, linkage);
+    }
+
+    @Snippet
+    private static void writeBarrierPost(Object object, Word card) {
+        writeBarrierPostC(WRITE_BARRIER_POST_C, thread(), object, card);
+    }
+
+    public static final Descriptor WRITE_BARRIER_POST_C = StubUtil.descriptorFor(WriteBarrierPostStub.class, "writeBarrierPostC", false);
+
+    @NodeIntrinsic(CRuntimeCall.class)
+    public static native void writeBarrierPostC(@ConstantNodeParameter Descriptor vmErrorC, Word thread, Object object, Word card);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/WriteBarrierPreStub.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,56 @@
+/*
+ * 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.hotspot.stubs;
+
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
+
+import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.graph.Node.ConstantNodeParameter;
+import com.oracle.graal.graph.Node.NodeIntrinsic;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.replacements.*;
+import com.oracle.graal.word.*;
+
+/**
+ * Stub called from {@link WriteBarrierPreStubCall}.
+ */
+public class WriteBarrierPreStub extends CRuntimeStub {
+
+    public WriteBarrierPreStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) {
+        super(runtime, replacements, target, linkage);
+    }
+
+    @Snippet
+    private static void writeBarrierPre(Object object) {
+        writeBarrierPreC(WRITE_BARRIER_PRE_C, thread(), object);
+    }
+
+    public static final Descriptor WRITE_BARRIER_PRE_C = StubUtil.descriptorFor(WriteBarrierPreStub.class, "writeBarrierPreC", false);
+
+    @NodeIntrinsic(CRuntimeCall.class)
+    public static native void writeBarrierPreC(@ConstantNodeParameter Descriptor vmErrorC, Word thread, Object object);
+}
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java	Mon May 13 17:11:31 2013 +0200
@@ -253,7 +253,7 @@
         }
     }
 
-    public void insertProxies(BeginNode begin) {
+    public void insertProxies(AbstractBeginNode begin) {
         for (int i = 0; i < localsSize(); i++) {
             ValueNode value = localAt(i);
             if (value != null) {
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Mon May 13 17:11:31 2013 +0200
@@ -34,7 +34,6 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.meta.JavaTypeProfile.ProfiledType;
 import com.oracle.graal.api.meta.ProfilingInfo.TriState;
 import com.oracle.graal.api.meta.ResolvedJavaType.Representation;
 import com.oracle.graal.bytecode.*;
@@ -680,11 +679,7 @@
     }
 
     private void genGoto() {
-        double probability = profilingInfo.getBranchTakenProbability(bci());
-        if (probability < 0) {
-            probability = 1;
-        }
-        appendGoto(createTarget(probability, currentBlock.successors.get(0), frameState));
+        appendGoto(createTarget(currentBlock.successors.get(0), frameState));
         assert currentBlock.numNormalSuccessors() == 1;
     }
 
@@ -726,8 +721,8 @@
         }
         condition = currentGraph.unique(condition);
 
-        BeginNode trueSuccessor = createBlockTarget(probability, trueBlock, frameState);
-        BeginNode falseSuccessor = createBlockTarget(1 - probability, falseBlock, frameState);
+        AbstractBeginNode trueSuccessor = createBlockTarget(probability, trueBlock, frameState);
+        AbstractBeginNode falseSuccessor = createBlockTarget(1 - probability, falseBlock, frameState);
 
         IfNode ifNode = negate ? new IfNode(condition, falseSuccessor, trueSuccessor, 1 - probability) : new IfNode(condition, trueSuccessor, falseSuccessor, probability);
         append(currentGraph.add(ifNode));
@@ -798,12 +793,7 @@
         if (!optimisticOpts.useTypeCheckHints() || !canHaveSubtype(type)) {
             return null;
         } else {
-            ResolvedJavaType uniqueSubtype = type.findUniqueConcreteSubtype();
-            if (uniqueSubtype != null) {
-                return new JavaTypeProfile(profilingInfo.getNullSeen(bci()), 0.0D, new ProfiledType(uniqueSubtype, 1.0D));
-            } else {
-                return profilingInfo.getTypeProfile(bci());
-            }
+            return profilingInfo.getTypeProfile(bci());
         }
     }
 
@@ -812,7 +802,8 @@
         JavaType type = lookupType(cpi, CHECKCAST);
         ValueNode object = frameState.apop();
         if (type instanceof ResolvedJavaType) {
-            CheckCastNode checkCast = currentGraph.add(new CheckCastNode((ResolvedJavaType) type, object, getProfileForTypeCheck((ResolvedJavaType) type)));
+            JavaTypeProfile profileForTypeCheck = getProfileForTypeCheck((ResolvedJavaType) type);
+            CheckCastNode checkCast = currentGraph.add(new CheckCastNode((ResolvedJavaType) type, object, profileForTypeCheck, false));
             append(checkCast);
             frameState.apush(checkCast);
         } else {
@@ -837,7 +828,7 @@
     void genNewInstance(int cpi) {
         JavaType type = lookupType(cpi, NEW);
         if (type instanceof ResolvedJavaType && ((ResolvedJavaType) type).isInitialized()) {
-            NewInstanceNode n = currentGraph.add(new NewInstanceNode((ResolvedJavaType) type, true, false));
+            NewInstanceNode n = currentGraph.add(new NewInstanceNode((ResolvedJavaType) type, true));
             frameState.apush(append(n));
         } else {
             handleUnresolvedNewInstance(type);
@@ -879,7 +870,7 @@
     private void genNewPrimitiveArray(int typeCode) {
         Class<?> clazz = arrayTypeCodeToClass(typeCode);
         ResolvedJavaType elementType = runtime.lookupJavaType(clazz);
-        NewArrayNode nta = currentGraph.add(new NewArrayNode(elementType, frameState.ipop(), true, false));
+        NewArrayNode nta = currentGraph.add(new NewArrayNode(elementType, frameState.ipop(), true));
         frameState.apush(append(nta));
     }
 
@@ -887,7 +878,7 @@
         JavaType type = lookupType(cpi, ANEWARRAY);
         ValueNode length = frameState.ipop();
         if (type instanceof ResolvedJavaType) {
-            NewArrayNode n = currentGraph.add(new NewArrayNode((ResolvedJavaType) type, length, true, false));
+            NewArrayNode n = currentGraph.add(new NewArrayNode((ResolvedJavaType) type, length, true));
             frameState.apush(append(n));
         } else {
             handleUnresolvedNewObjectArray(type, length);
@@ -1012,13 +1003,8 @@
     private void genGetStatic(JavaField field) {
         Kind kind = field.getKind();
         if (field instanceof ResolvedJavaField && ((ResolvedJavaType) field.getDeclaringClass()).isInitialized()) {
-            Constant constantValue = ((ResolvedJavaField) field).readConstantValue(null);
-            if (constantValue != null) {
-                frameState.push(constantValue.getKind().getStackKind(), appendConstant(constantValue));
-            } else {
-                LoadFieldNode load = currentGraph.add(new LoadFieldNode(null, (ResolvedJavaField) field));
-                appendOptimizedLoadField(kind, load);
-            }
+            LoadFieldNode load = currentGraph.add(new LoadFieldNode(null, (ResolvedJavaField) field));
+            appendOptimizedLoadField(kind, load);
         } else {
             handleUnresolvedLoadField(field, null);
         }
@@ -1165,6 +1151,10 @@
         if (graphBuilderConfig.eagerResolving()) {
             returnType = returnType.resolve(targetMethod.getDeclaringClass());
         }
+        if (invokeKind != InvokeKind.Static && invokeKind != InvokeKind.Special) {
+            JavaTypeProfile profile = profilingInfo.getTypeProfile(bci());
+            args[0] = TypeProfileProxyNode.create(args[0], profile);
+        }
         MethodCallTargetNode callTarget = currentGraph.add(new MethodCallTargetNode(invokeKind, targetMethod, args, returnType));
         createInvokeNode(callTarget, resultType);
     }
@@ -1494,7 +1484,7 @@
             BlockPlaceholderNode placeholder = (BlockPlaceholderNode) block.firstInstruction;
 
             // The EndNode for the already existing edge.
-            EndNode end = currentGraph.add(new EndNode());
+            AbstractEndNode end = currentGraph.add(new EndNode());
             // The MergeNode that replaces the placeholder.
             MergeNode mergeNode = currentGraph.add(new MergeNode());
             FixedNode next = placeholder.next();
@@ -1509,7 +1499,7 @@
         MergeNode mergeNode = (MergeNode) block.firstInstruction;
 
         // The EndNode for the newly merged edge.
-        EndNode newEnd = currentGraph.add(new EndNode());
+        AbstractEndNode newEnd = currentGraph.add(new EndNode());
         Target target = checkLoopExit(newEnd, block, state);
         FixedNode result = target.fixed;
         block.entryState.merge(mergeNode, target.state);
@@ -1523,9 +1513,9 @@
      * Returns a block begin node with the specified state. If the specified probability is 0, the
      * block deoptimizes immediately.
      */
-    private BeginNode createBlockTarget(double probability, Block block, FrameStateBuilder stateAfter) {
+    private AbstractBeginNode createBlockTarget(double probability, Block block, FrameStateBuilder stateAfter) {
         FixedNode target = createTarget(probability, block, stateAfter);
-        BeginNode begin = BeginNode.begin(target);
+        AbstractBeginNode begin = AbstractBeginNode.begin(target);
 
         assert !(target instanceof DeoptimizeNode && begin.stateAfter() != null) : "We are not allowed to set the stateAfter of the begin node, because we have to deoptimize "
                         + "to a bci _before_ the actual if, so that the interpreter can update the profiling information.";
@@ -1666,7 +1656,7 @@
         if (typeInstruction != null) {
             Block nextBlock = block.successors.size() == 1 ? unwindBlock(block.deoptBci) : block.successors.get(1);
             ValueNode exception = frameState.stackAt(0);
-            CheckCastNode checkCast = currentGraph.add(new CheckCastNode((ResolvedJavaType) catchType, exception, null));
+            CheckCastNode checkCast = currentGraph.add(new CheckCastNode((ResolvedJavaType) catchType, exception, null, false));
             frameState.apop();
             frameState.push(Kind.Object, checkCast);
             FixedNode catchSuccessor = createTarget(block.successors.get(0), frameState);
@@ -1706,7 +1696,7 @@
         if (block.isLoopHeader) {
             // Create the loop header block, which later will merge the backward branches of the
             // loop.
-            EndNode preLoopEnd = currentGraph.add(new EndNode());
+            AbstractEndNode preLoopEnd = currentGraph.add(new EndNode());
             LoopBeginNode loopBegin = currentGraph.add(new LoopBeginNode());
             lastInstr.setNext(preLoopEnd);
             // Add the single non-loop predecessor of the loop header.
@@ -1774,7 +1764,7 @@
                 frameState.clearNonLiveLocals(currentBlock.localsLiveOut);
             }
             if (lastInstr instanceof StateSplit) {
-                if (lastInstr.getClass() == BeginNode.class) {
+                if (lastInstr.getClass() == AbstractBeginNode.class) {
                     // BeginNodes do not need a frame state
                 } else {
                     StateSplit stateSplit = (StateSplit) lastInstr;
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/JTTTest.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/JTTTest.java	Mon May 13 17:11:31 2013 +0200
@@ -60,9 +60,9 @@
             Object[] args = argsWithReceiver(receiver, argsToBind);
             JavaType[] parameterTypes = signatureToTypes(runtime.lookupJavaMethod(m));
             assert parameterTypes.length == args.length;
-            for (int i = 0; i < argsToBind.length; i++) {
+            for (int i = 0; i < args.length; i++) {
                 LocalNode local = graph.getLocal(i);
-                Constant c = Constant.forBoxed(parameterTypes[i].getKind(), argsToBind[i]);
+                Constant c = Constant.forBoxed(parameterTypes[i].getKind(), args[i]);
                 ConstantNode replacement = ConstantNode.forConstant(c, runtime, graph);
                 local.replaceAtUsages(replacement);
             }
@@ -99,8 +99,10 @@
         Result expect = executeExpected(method, receiver, args);
 
         test(method, expect, receiver, args);
-        this.argsToBind = args;
-        test(method, expect, receiver, args);
-        this.argsToBind = null;
+        if (args.length > 0) {
+            this.argsToBind = args;
+            test(method, expect, receiver, args);
+            this.argsToBind = null;
+        }
     }
 }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/System_currentTimeMillis02.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/System_currentTimeMillis02.java	Mon May 13 17:11:31 2013 +0200
@@ -36,8 +36,8 @@
             delta = System.currentTimeMillis() - start;
             // do nothing.
         }
-        // better get at least 40 millisecond resolution.
-        return delta >= 1 && delta < 40;
+        // better get at least 100 millisecond resolution.
+        return delta >= 1 && delta < 100;
     }
 
     @Test
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Reflection_getCallerClass01.java	Mon May 13 16:46:39 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +0,0 @@
-/*
- * Copyright (c) 2007, 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.jtt.reflect;
-
-import com.oracle.graal.jtt.*;
-import org.junit.*;
-
-import sun.reflect.*;
-
-/*
- */
-public final class Reflection_getCallerClass01 extends JTTTest {
-
-    public static final class Caller1 {
-
-        private Caller1() {
-        }
-
-        static String caller1(int depth) {
-            return Reflection.getCallerClass(depth).getName();
-        }
-    }
-
-    public static final class Caller2 {
-
-        private Caller2() {
-        }
-
-        static String caller2(int depth) {
-            return Caller1.caller1(depth);
-        }
-    }
-
-    public static String test(int depth) {
-        return Caller2.caller2(depth);
-    }
-
-    @Test
-    public void run0() throws Throwable {
-        runTest("test", 0);
-    }
-
-    @Test
-    public void run1() throws Throwable {
-        runTest("test", 1);
-    }
-
-    @Test
-    public void run2() throws Throwable {
-        runTest("test", 2);
-    }
-
-}
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64AddressValue.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64AddressValue.java	Mon May 13 17:11:31 2013 +0200
@@ -41,11 +41,11 @@
     protected final Scale scale;
     protected final int displacement;
 
-    public AMD64AddressValue(Kind kind, AllocatableValue base, int displacement) {
+    public AMD64AddressValue(PlatformKind kind, AllocatableValue base, int displacement) {
         this(kind, base, Value.ILLEGAL, Scale.Times1, displacement);
     }
 
-    public AMD64AddressValue(Kind kind, AllocatableValue base, AllocatableValue index, Scale scale, int displacement) {
+    public AMD64AddressValue(PlatformKind kind, AllocatableValue base, AllocatableValue index, Scale scale, int displacement) {
         super(kind);
         this.base = base;
         this.index = index;
@@ -54,7 +54,7 @@
     }
 
     private static Register toRegister(AllocatableValue value) {
-        if (value == Value.ILLEGAL) {
+        if (value.equals(Value.ILLEGAL)) {
             return Register.None;
         } else {
             RegisterValue reg = (RegisterValue) value;
@@ -91,13 +91,13 @@
     public boolean equals(Object obj) {
         if (obj instanceof AMD64AddressValue) {
             AMD64AddressValue addr = (AMD64AddressValue) obj;
-            return getKind() == addr.getKind() && displacement == addr.displacement && base.equals(addr.base) && scale == addr.scale && index.equals(addr.index);
+            return getPlatformKind() == addr.getPlatformKind() && displacement == addr.displacement && base.equals(addr.base) && scale == addr.scale && index.equals(addr.index);
         }
         return false;
     }
 
     @Override
     public int hashCode() {
-        return base.hashCode() ^ index.hashCode() ^ (displacement << 4) ^ (scale.value << 8) ^ (getKind().ordinal() << 12);
+        return base.hashCode() ^ index.hashCode() ^ (displacement << 4) ^ (scale.value << 8) ^ getPlatformKind().hashCode();
     }
 }
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java	Mon May 13 17:11:31 2013 +0200
@@ -27,7 +27,9 @@
 
 import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.*;
 import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.asm.amd64.AMD64Assembler.ConditionFlag;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
@@ -36,8 +38,8 @@
 public enum AMD64Arithmetic {
     IADD, ISUB, IMUL, IDIV, IDIVREM, IREM, IUDIV, IUREM, IAND, IOR, IXOR, ISHL, ISHR, IUSHR,
     LADD, LSUB, LMUL, LDIV, LDIVREM, LREM, LUDIV, LUREM, LAND, LOR, LXOR, LSHL, LSHR, LUSHR,
-    FADD, FSUB, FMUL, FDIV, FAND, FOR, FXOR,
-    DADD, DSUB, DMUL, DDIV, DAND, DOR, DXOR,
+    FADD, FSUB, FMUL, FDIV, FREM, FAND, FOR, FXOR,
+    DADD, DSUB, DMUL, DDIV, DREM, DAND, DOR, DXOR,
     INEG, LNEG,
     I2L, L2I, I2B, I2C, I2S,
     F2D, D2F,
@@ -255,8 +257,8 @@
 
         public DivRemOp(AMD64Arithmetic opcode, AllocatableValue x, AllocatableValue y, LIRFrameState state) {
             this.opcode = opcode;
-            this.divResult = AMD64.rax.asValue(x.getKind());
-            this.remResult = AMD64.rdx.asValue(x.getKind());
+            this.divResult = AMD64.rax.asValue(x.getPlatformKind());
+            this.remResult = AMD64.rdx.asValue(x.getPlatformKind());
             this.x = x;
             this.y = y;
             this.state = state;
@@ -278,6 +280,64 @@
         }
     }
 
+    public static class FPDivRemOp extends AMD64LIRInstruction {
+        @Opcode private final AMD64Arithmetic opcode;
+        @Def protected AllocatableValue result;
+        @Use protected AllocatableValue x;
+        @Use protected AllocatableValue y;
+        @Temp protected AllocatableValue raxTemp;
+
+        public FPDivRemOp(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x, AllocatableValue y) {
+            this.opcode = opcode;
+            this.result = result;
+            this.raxTemp = AMD64.rax.asValue(Kind.Int);
+            this.x = x;
+            this.y = y;
+        }
+
+        @Override
+        public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
+            AMD64Address tmp = new AMD64Address(AMD64.rsp);
+            masm.subq(AMD64.rsp, 8);
+            if (opcode == FREM) {
+                masm.movflt(tmp, asRegister(y));
+                masm.fld_s(tmp);
+                masm.movflt(tmp, asRegister(x));
+                masm.fld_s(tmp);
+            } else {
+                assert opcode == DREM;
+                masm.movsd(tmp, asRegister(y));
+                masm.fld_d(tmp);
+                masm.movsd(tmp, asRegister(x));
+                masm.fld_d(tmp);
+            }
+
+            Label label = new Label();
+            masm.bind(label);
+            masm.fprem();
+            masm.fwait();
+            masm.fnstsw_ax();
+            masm.testl(AMD64.rax, 0x400);
+            masm.jcc(ConditionFlag.NotZero, label);
+            masm.fxch(1);
+            masm.fpop();
+
+            if (opcode == FREM) {
+                masm.fstp_s(tmp);
+                masm.movflt(asRegister(result), tmp);
+            } else {
+                masm.fstp_d(tmp);
+                masm.movsd(asRegister(result), tmp);
+            }
+            masm.addq(AMD64.rsp, 8);
+        }
+
+        @Override
+        protected void verify() {
+            super.verify();
+            verifyKind(opcode, result, x, y);
+        }
+    }
 
     @SuppressWarnings("unused")
     protected static void emit(TargetMethodAssembler tasm, AMD64MacroAssembler masm, AMD64Arithmetic opcode, AllocatableValue result) {
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Call.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Call.java	Mon May 13 17:11:31 2013 +0200
@@ -51,7 +51,7 @@
         }
 
         @Override
-        public boolean hasCall() {
+        public boolean destroysCallerSavedRegisters() {
             return true;
         }
     }
@@ -112,8 +112,8 @@
         }
 
         @Override
-        public boolean hasCall() {
-            return !callTarget.preservesRegisters();
+        public boolean destroysCallerSavedRegisters() {
+            return callTarget.destroysRegisters();
         }
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64RegistersPreservationOp.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,41 @@
+/*
+ * 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.lir.amd64;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.lir.*;
+
+/**
+ * Base class for operations that preserve a set of registers.
+ */
+public abstract class AMD64RegistersPreservationOp extends AMD64LIRInstruction {
+
+    /**
+     * Prunes the set of registers preserved by this operation to exclude those in {@code ignored}
+     * and updates {@code debugInfo} with a {@linkplain DebugInfo#getCalleeSaveInfo() description}
+     * of where each preserved register is saved.
+     */
+    public abstract void update(Set<Register> ignored, DebugInfo debugInfo, FrameMap frameMap);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64RestoreRegistersOp.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,71 @@
+/*
+ * 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.lir.amd64;
+
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.lir.LIRInstruction.Opcode;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * Restores registers from stack slots.
+ */
+@Opcode("RESTORE_REGISTER")
+public class AMD64RestoreRegistersOp extends AMD64LIRInstruction {
+
+    /**
+     * The slots from which the registers are restored.
+     */
+    @Use(STACK) protected final StackSlot[] slots;
+
+    /**
+     * The operation that saved the registers restored by this operation.
+     */
+    private final AMD64SaveRegistersOp save;
+
+    public AMD64RestoreRegistersOp(StackSlot[] source, AMD64SaveRegistersOp save) {
+        this.slots = source;
+        this.save = save;
+    }
+
+    protected Register[] getSavedRegisters() {
+        return save.savedRegisters;
+    }
+
+    protected void restoreRegister(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Register register, StackSlot input) {
+        RegisterValue result = register.asValue(input.getKind());
+        AMD64Move.move(tasm, masm, result, input);
+    }
+
+    @Override
+    public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
+        Register[] savedRegisters = getSavedRegisters();
+        for (int i = 0; i < savedRegisters.length; i++) {
+            if (savedRegisters[i] != null) {
+                restoreRegister(tasm, masm, savedRegisters[i], slots[i]);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64SaveRegistersOp.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,106 @@
+/*
+ * 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.lir.amd64;
+
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.LIRInstruction.Opcode;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * Saves registers to stack slots.
+ */
+@Opcode("SAVE_REGISTER")
+public class AMD64SaveRegistersOp extends AMD64RegistersPreservationOp {
+
+    /**
+     * The registers (potentially) saved by this operation.
+     */
+    protected final Register[] savedRegisters;
+
+    /**
+     * The slots to which the registers are saved.
+     */
+    @Def(STACK) protected final StackSlot[] slots;
+
+    public AMD64SaveRegistersOp(Register[] savedRegisters, StackSlot[] slots) {
+        this.savedRegisters = savedRegisters;
+        this.slots = slots;
+    }
+
+    protected void saveRegister(TargetMethodAssembler tasm, AMD64MacroAssembler masm, StackSlot result, Register register) {
+        RegisterValue input = register.asValue(result.getKind());
+        AMD64Move.move(tasm, masm, result, input);
+    }
+
+    @Override
+    public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
+        for (int i = 0; i < savedRegisters.length; i++) {
+            if (savedRegisters[i] != null) {
+                saveRegister(tasm, masm, slots[i], savedRegisters[i]);
+            }
+        }
+    }
+
+    public StackSlot[] getSlots() {
+        return slots;
+    }
+
+    /**
+     * Prunes the set of registers saved by this operation to exclude those in {@code ignored} and
+     * updates {@code debugInfo} with a {@linkplain DebugInfo#getCalleeSaveInfo() description} of
+     * where each preserved register is saved.
+     */
+    @Override
+    public void update(Set<Register> ignored, DebugInfo debugInfo, FrameMap frameMap) {
+        int preserved = 0;
+        for (int i = 0; i < savedRegisters.length; i++) {
+            if (savedRegisters[i] != null) {
+                if (ignored.contains(savedRegisters[i])) {
+                    savedRegisters[i] = null;
+                } else {
+                    preserved++;
+                }
+            }
+        }
+        if (preserved != 0) {
+            Register[] keys = new Register[preserved];
+            int[] values = new int[keys.length];
+            int mapIndex = 0;
+            for (int i = 0; i < savedRegisters.length; i++) {
+                if (savedRegisters[i] != null) {
+                    keys[mapIndex] = savedRegisters[i];
+                    values[mapIndex] = frameMap.indexForStackSlot(slots[i]);
+                    mapIndex++;
+                }
+            }
+            assert mapIndex == preserved;
+            debugInfo.setCalleeSaveInfo(new RegisterSaveLayout(keys, values));
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ZapRegistersOp.java	Mon May 13 17:11:31 2013 +0200
@@ -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.lir.amd64;
+
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.LIRInstruction.Opcode;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * Writes well known garbage values to registers.
+ */
+@Opcode("ZAP_REGISTER")
+public final class AMD64ZapRegistersOp extends AMD64RegistersPreservationOp {
+
+    /**
+     * The registers that are zapped.
+     */
+    protected final Register[] zappedRegisters;
+
+    /**
+     * The garbage values that are written to the registers.
+     */
+    @Use({CONST}) protected Constant[] zapValues;
+
+    public AMD64ZapRegistersOp(Register[] zappedRegisters, Constant[] zapValues) {
+        this.zappedRegisters = zappedRegisters;
+        this.zapValues = zapValues;
+    }
+
+    @Override
+    public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
+        for (int i = 0; i < zappedRegisters.length; i++) {
+            if (zappedRegisters[i] != null) {
+                RegisterValue registerValue = zappedRegisters[i].asValue(zapValues[i].getPlatformKind());
+                AMD64Move.move(tasm, masm, registerValue, zapValues[i]);
+            }
+        }
+    }
+
+    /**
+     * Prunes the set of registers zapped by this operation to exclude those in {@code ignored}.
+     */
+    @Override
+    public void update(Set<Register> ignored, DebugInfo debugInfo, FrameMap frameMap) {
+        for (int i = 0; i < zappedRegisters.length; i++) {
+            if (zappedRegisters[i] != null) {
+                if (ignored.contains(zappedRegisters[i])) {
+                    zappedRegisters[i] = null;
+                }
+            }
+        }
+    }
+}
--- a/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXAddressValue.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXAddressValue.java	Mon May 13 17:11:31 2013 +0200
@@ -48,7 +48,7 @@
      * @param kind the kind of the value being addressed
      * @param base the base register
      */
-    public PTXAddressValue(Kind kind, AllocatableValue base) {
+    public PTXAddressValue(PlatformKind kind, AllocatableValue base) {
         this(kind, base, 0);
     }
 
@@ -60,7 +60,7 @@
      * @param base the base register
      * @param displacement the displacement
      */
-    public PTXAddressValue(Kind kind, AllocatableValue base, long displacement) {
+    public PTXAddressValue(PlatformKind kind, AllocatableValue base, long displacement) {
         super(kind);
         this.base = base;
         this.displacement = displacement;
@@ -95,13 +95,13 @@
     public boolean equals(Object obj) {
         if (obj instanceof PTXAddressValue) {
             PTXAddressValue addr = (PTXAddressValue) obj;
-            return getKind() == addr.getKind() && displacement == addr.displacement && base.equals(addr.base);
+            return getPlatformKind() == addr.getPlatformKind() && displacement == addr.displacement && base.equals(addr.base);
         }
         return false;
     }
 
     @Override
     public int hashCode() {
-        return base.hashCode() ^ ((int) displacement << 4) ^ (getKind().ordinal() << 12);
+        return base.hashCode() ^ ((int) displacement << 4) ^ getPlatformKind().hashCode();
     }
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValue.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValue.java	Mon May 13 17:11:31 2013 +0200
@@ -45,7 +45,7 @@
 
     private final CompositeValueClass valueClass;
 
-    public CompositeValue(Kind kind) {
+    public CompositeValue(PlatformKind kind) {
         super(kind);
         valueClass = CompositeValueClass.get(getClass());
     }
@@ -58,4 +58,18 @@
     public String toString() {
         return valueClass.toString(this);
     }
+
+    @Override
+    public int hashCode() {
+        return 53 * super.hashCode() + valueClass.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof CompositeValue) {
+            CompositeValue other = (CompositeValue) obj;
+            return super.equals(other) && valueClass.equals(other.valueClass);
+        }
+        return false;
+    }
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/EdgeMoveOptimizer.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/EdgeMoveOptimizer.java	Mon May 13 17:11:31 2013 +0200
@@ -91,7 +91,7 @@
         if (op1 instanceof MoveOp && op2 instanceof MoveOp) {
             MoveOp move1 = (MoveOp) op1;
             MoveOp move2 = (MoveOp) op2;
-            if (move1.getInput() == move2.getInput() && move1.getResult() == move2.getResult()) {
+            if (move1.getInput().equals(move2.getInput()) && move1.getResult().equals(move2.getResult())) {
                 // these moves are exactly equal and can be optimized
                 return true;
             }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java	Mon May 13 17:11:31 2013 +0200
@@ -198,7 +198,7 @@
             // Without this, frameNeedsAllocating() would never return true.
             int total = 0;
             for (StackSlot s : freedSlots) {
-                total += target.sizeInBytes(s.getKind());
+                total += target.arch.getSizeInBytes(s.getKind());
             }
             int initialSpillSize = returnAddressSize() + calleeSaveAreaSize();
             if (total == spillSize - initialSpillSize) {
@@ -211,8 +211,7 @@
     }
 
     /**
-     * Computes the offset of a stack slot relative to the frame register. This is also the bit
-     * index of stack slots in the reference map.
+     * Computes the offset of a stack slot relative to the frame register.
      * 
      * @param slot a stack slot
      * @return the offset of the stack slot
@@ -227,6 +226,18 @@
     }
 
     /**
+     * Computes the index of a stack slot relative to slot 0. This is also the bit index of stack
+     * slots in the reference map.
+     * 
+     * @param slot a stack slot
+     * @return the index of the stack slot
+     */
+    public int indexForStackSlot(StackSlot slot) {
+        assert offsetForStackSlot(slot) % target.wordSize == 0;
+        return offsetForStackSlot(slot) / target.wordSize;
+    }
+
+    /**
      * Gets the offset to the stack area where callee-saved registers are stored.
      * 
      * @return The offset to the callee save area (in bytes).
@@ -256,7 +267,7 @@
         hasOutgoingStackArguments = hasOutgoingStackArguments || argsSize > 0;
     }
 
-    private StackSlot getSlot(Kind kind, int additionalOffset) {
+    private StackSlot getSlot(PlatformKind kind, int additionalOffset) {
         return StackSlot.get(kind, -spillSize + additionalOffset, true);
     }
 
@@ -267,12 +278,12 @@
      * @param kind The kind of the spill slot to be reserved.
      * @return A spill slot denoting the reserved memory area.
      */
-    public StackSlot allocateSpillSlot(Kind kind) {
+    public StackSlot allocateSpillSlot(PlatformKind kind) {
         assert frameSize == -1 : "frame size must not yet be fixed";
         if (freedSlots != null) {
             for (Iterator<StackSlot> iter = freedSlots.iterator(); iter.hasNext();) {
                 StackSlot s = iter.next();
-                if (s.getKind() == kind) {
+                if (s.getPlatformKind() == kind) {
                     iter.remove();
                     if (freedSlots.isEmpty()) {
                         freedSlots = null;
@@ -281,20 +292,20 @@
                 }
             }
         }
-        int size = target.sizeInBytes(kind);
+        int size = target.arch.getSizeInBytes(kind);
         spillSize = NumUtil.roundUp(spillSize + size, size);
         return getSlot(kind, 0);
     }
 
-    private List<StackSlot> freedSlots;
+    private Set<StackSlot> freedSlots;
 
     /**
-     * Frees a spill slot that was obtained via {@link #allocateSpillSlot(Kind)} such that it can be
-     * reused for the next allocation request for the same kind of slot.
+     * Frees a spill slot that was obtained via {@link #allocateSpillSlot(PlatformKind)} such that
+     * it can be reused for the next allocation request for the same kind of slot.
      */
     public void freeSpillSlot(StackSlot slot) {
         if (freedSlots == null) {
-            freedSlots = new ArrayList<>();
+            freedSlots = new HashSet<>();
         }
         freedSlots.add(slot);
     }
@@ -330,11 +341,6 @@
         }
     }
 
-    private int frameRefMapIndex(StackSlot slot) {
-        assert offsetForStackSlot(slot) % target.wordSize == 0;
-        return offsetForStackSlot(slot) / target.wordSize;
-    }
-
     /**
      * Initializes a reference map that covers all registers of the target architecture.
      */
@@ -369,7 +375,7 @@
             if (isRegister(location)) {
                 registerRefMap.set(asRegister(location).number);
             } else if (isStackSlot(location)) {
-                int index = frameRefMapIndex(asStackSlot(location));
+                int index = indexForStackSlot(asStackSlot(location));
                 frameRefMap.set(index);
             } else {
                 assert isConstant(location);
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java	Mon May 13 17:11:31 2013 +0200
@@ -84,16 +84,16 @@
         /**
          * The value must have been defined before. It is alive before the instruction until the
          * beginning of the instruction, but not necessarily throughout the instruction. A register
-         * assigned to it can also be assigend to a Temp or Output operand. The value can be used
-         * again after the instruction, so the instruction must not modify the register.
+         * assigned to it can also be assigned to a {@link #TEMP} or {@link #DEF} operand. The value
+         * can be used again after the instruction, so the instruction must not modify the register.
          */
         USE,
 
         /**
          * The value must have been defined before. It is alive before the instruction and
-         * throughout the instruction. A register assigned to it cannot be assigned to a Temp or
-         * Output operand. The value can be used again after the instruction, so the instruction
-         * must not modify the register.
+         * throughout the instruction. A register assigned to it cannot be assigned to a
+         * {@link #TEMP} or {@link #DEF} operand. The value can be used again after the instruction,
+         * so the instruction must not modify the register.
          */
         ALIVE,
 
@@ -244,7 +244,7 @@
     }
 
     public final boolean hasOperands() {
-        return instructionClass.hasOperands() || hasState() || hasCall();
+        return instructionClass.hasOperands() || hasState() || destroysCallerSavedRegisters();
     }
 
     public final boolean hasState() {
@@ -252,10 +252,9 @@
     }
 
     /**
-     * Returns true when this instruction is a call instruction that destroys all caller-saved
-     * registers.
+     * Determines if this instruction destroys all caller-saved registers..
      */
-    public boolean hasCall() {
+    public boolean destroysCallerSavedRegisters() {
         return false;
     }
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRVerifier.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRVerifier.java	Mon May 13 17:11:31 2013 +0200
@@ -138,7 +138,7 @@
                 curInstruction = op;
 
                 op.forEachInput(useProc);
-                if (op.hasCall()) {
+                if (op.destroysCallerSavedRegisters()) {
                     for (Register register : frameMap.registerConfig.getCallerSaveRegisters()) {
                         curRegistersLive[register.number] = null;
                     }
@@ -179,7 +179,7 @@
                 curRegistersDefined.set(regNum);
             }
 
-            if (beforeRegisterAllocation && curRegistersLive[regNum] != value) {
+            if (beforeRegisterAllocation && !curRegistersLive[regNum].equals(value)) {
                 TTY.println("block %s  instruction %s", curBlock, curInstruction);
                 TTY.println("live registers: %s", Arrays.toString(curRegistersLive));
                 TTY.println("ERROR: Use of fixed register %s that is not defined in this block", value);
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/Variable.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/Variable.java	Mon May 13 17:11:31 2013 +0200
@@ -39,31 +39,33 @@
     public final int index;
 
     /**
-     * The type of register that this variable needs to get assigned.
-     */
-    public final Register.RegisterFlag flag;
-
-    /**
      * Creates a new variable.
      * 
      * @param kind
      * @param index
      */
-    public Variable(Kind kind, int index, Register.RegisterFlag flag) {
+    public Variable(PlatformKind kind, int index) {
         super(kind);
-        assert kind == kind.getStackKind() : "Variables can be only created for stack kinds";
         assert index >= 0;
         this.index = index;
-        this.flag = flag;
-    }
-
-    @Override
-    public int hashCode() {
-        return (index << 4) | getKind().ordinal();
     }
 
     @Override
     public String toString() {
         return "v" + index + getKindSuffix();
     }
+
+    @Override
+    public int hashCode() {
+        return 71 * super.hashCode() + index;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof Variable) {
+            Variable other = (Variable) obj;
+            return super.equals(other) && index == other.index;
+        }
+        return false;
+    }
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/TargetMethodAssembler.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/TargetMethodAssembler.java	Mon May 13 17:11:31 2013 +0200
@@ -33,6 +33,7 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.nodes.*;
 
 public class TargetMethodAssembler {
 
@@ -88,7 +89,7 @@
         compilationResult.addAnnotation(new CompilationResult.CodeComment(asm.codeBuffer.position(), s));
     }
 
-    public CompilationResult finishTargetMethod(Object name, boolean isStub) {
+    public CompilationResult finishTargetMethod(StructuredGraph graph) {
         // Install code, data and frame size
         compilationResult.setTargetCode(asm.codeBuffer.close(false), asm.codeBuffer.position());
 
@@ -113,11 +114,11 @@
 
             Debug.metric("TargetMethods").increment();
             Debug.metric("CodeBytesEmitted").add(compilationResult.getTargetCodeSize());
-            Debug.metric("SafepointsEmitted").add(compilationResult.getInfopoints().size());
+            Debug.metric("InfopointsEmitted").add(compilationResult.getInfopoints().size());
             Debug.metric("DataPatches").add(ldp.size());
             Debug.metric("ExceptionHandlersEmitted").add(compilationResult.getExceptionHandlers().size());
         }
-        Debug.log("Finished target method %s, isStub %b", name, isStub);
+        Debug.log("Finished compiling %s", graph);
         return compilationResult;
     }
 
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/BasicInductionVariable.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/BasicInductionVariable.java	Mon May 13 17:11:31 2013 +0200
@@ -22,9 +22,11 @@
  */
 package com.oracle.graal.loop;
 
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.calc.ConvertNode.Op;
 import com.oracle.graal.nodes.type.*;
 
 public class BasicInductionVariable extends InductionVariable {
@@ -113,8 +115,19 @@
     }
 
     @Override
-    public ValueNode extremumNode() {
-        return IntegerArithmeticNode.add(IntegerArithmeticNode.mul(strideNode(), loop.counted().maxTripCountNode()), init);
+    public ValueNode extremumNode(boolean assumePositiveTripCount, Kind kind) {
+        Kind fromKind = phi.kind();
+        Graph graph = phi.graph();
+        ValueNode stride = strideNode();
+        ValueNode maxTripCount = loop.counted().maxTripCountNode(assumePositiveTripCount);
+        ValueNode initNode = this.initNode();
+        if (fromKind != kind) {
+            Op convertOp = Op.getOp(fromKind, kind);
+            stride = graph.unique(new ConvertNode(convertOp, stride));
+            maxTripCount = graph.unique(new ConvertNode(convertOp, maxTripCount));
+            initNode = graph.unique(new ConvertNode(convertOp, initNode));
+        }
+        return IntegerArithmeticNode.add(IntegerArithmeticNode.mul(stride, IntegerArithmeticNode.sub(maxTripCount, ConstantNode.forIntegerKind(kind, 1, graph))), initNode);
     }
 
     @Override
@@ -124,6 +137,6 @@
 
     @Override
     public long constantExtremum() {
-        return constantStride() * loop.counted().constantMaxTripCount() + constantInit();
+        return constantStride() * (loop.counted().constantMaxTripCount() - 1) + constantInit();
     }
 }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/CountedLoopInfo.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/CountedLoopInfo.java	Mon May 13 17:11:31 2013 +0200
@@ -22,9 +22,15 @@
  */
 package com.oracle.graal.loop;
 
+import static com.oracle.graal.nodes.calc.IntegerArithmeticNode.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.loop.InductionVariable.Direction;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.extended.*;
 
 public class CountedLoopInfo {
 
@@ -32,19 +38,38 @@
     private InductionVariable iv;
     private ValueNode end;
     private boolean oneOff;
+    private AbstractBeginNode body;
 
-    CountedLoopInfo(LoopEx loop, InductionVariable iv, ValueNode end, boolean oneOff) {
+    CountedLoopInfo(LoopEx loop, InductionVariable iv, ValueNode end, boolean oneOff, AbstractBeginNode body) {
         this.loop = loop;
         this.iv = iv;
         this.end = end;
         this.oneOff = oneOff;
+        this.body = body;
     }
 
     public ValueNode maxTripCountNode() {
-        // TODO (gd) stuarte and respect oneOff
-        throw GraalInternalError.unimplemented("division is a fixed node that needs to be inserted into the control flow");
-        // return IntegerArithmeticNode.div(IntegerArithmeticNode.sub(end, iv.initNode()),
-        // iv.strideNode());
+        return maxTripCountNode(false);
+    }
+
+    public ValueNode maxTripCountNode(boolean assumePositive) {
+        StructuredGraph graph = iv.valueNode().graph();
+        Kind kind = iv.valueNode().kind();
+        IntegerArithmeticNode range = IntegerArithmeticNode.sub(end, iv.initNode());
+        if (oneOff) {
+            if (iv.direction() == Direction.Up) {
+                range = IntegerArithmeticNode.add(range, ConstantNode.forIntegerKind(kind, 1, graph));
+            } else {
+                range = IntegerArithmeticNode.sub(range, ConstantNode.forIntegerKind(kind, 1, graph));
+            }
+        }
+        IntegerDivNode div = graph.add(new IntegerDivNode(kind, range, iv.strideNode()));
+        graph.addBeforeFixed(loop.entryPoint(), div);
+        ConstantNode zero = ConstantNode.forIntegerKind(kind, 0, graph);
+        if (assumePositive) {
+            return div;
+        }
+        return graph.unique(new ConditionalNode(graph.unique(new IntegerLessThanNode(zero, div)), div, zero));
     }
 
     public boolean isConstantMaxTripCount() {
@@ -80,4 +105,60 @@
     public String toString() {
         return "iv=" + iv + " until " + end + (oneOff ? iv.direction() == Direction.Up ? "+1" : "-1" : "");
     }
+
+    public ValueNode getLimit() {
+        return end;
+    }
+
+    public ValueNode getStart() {
+        return iv.initNode();
+    }
+
+    public boolean isLimitIncluded() {
+        return oneOff;
+    }
+
+    public AbstractBeginNode getBody() {
+        return body;
+    }
+
+    public Direction getDirection() {
+        return iv.direction();
+    }
+
+    public GuardingNode getOverFlowGuard() {
+        return loop.loopBegin().getOverflowGuard();
+    }
+
+    public GuardingNode createOverFlowGuard() {
+        GuardingNode overflowGuard = getOverFlowGuard();
+        if (overflowGuard != null) {
+            return overflowGuard;
+        }
+        Kind kind = iv.valueNode().kind();
+        Graph graph = iv.valueNode().graph();
+        CompareNode cond; // we use a negated guard with a < condition to achieve a >=
+        ConstantNode one = ConstantNode.forIntegerKind(kind, 1, graph);
+        if (iv.direction() == Direction.Up) {
+            IntegerArithmeticNode v1 = sub(ConstantNode.forIntegerKind(kind, kind.getMaxValue(), graph), sub(iv.strideNode(), one));
+            if (oneOff) {
+                v1 = sub(v1, one);
+            }
+            cond = graph.unique(new IntegerLessThanNode(v1, end));
+        } else {
+            assert iv.direction() == Direction.Down;
+            IntegerArithmeticNode v1 = add(ConstantNode.forIntegerKind(kind, kind.getMinValue(), graph), sub(one, iv.strideNode()));
+            if (oneOff) {
+                v1 = add(v1, one);
+            }
+            cond = graph.unique(new IntegerLessThanNode(end, v1));
+        }
+        overflowGuard = graph.unique(new GuardNode(cond, BeginNode.prevBegin(loop.entryPoint()), DeoptimizationReason.LoopLimitCheck, DeoptimizationAction.InvalidateRecompile, true));
+        loop.loopBegin().setOverflowGuard(overflowGuard);
+        return overflowGuard;
+    }
+
+    public Kind getKind() {
+        return iv.valueNode().kind();
+    }
 }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedOffsetInductionVariable.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedOffsetInductionVariable.java	Mon May 13 17:11:31 2013 +0200
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.loop;
 
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
@@ -86,8 +87,8 @@
     }
 
     @Override
-    public ValueNode extremumNode() {
-        return op(offset, base.extremumNode());
+    public ValueNode extremumNode(boolean assumePositiveTripCount, Kind kind) {
+        return op(base.extremumNode(assumePositiveTripCount, kind), ConvertNode.convert(kind, offset));
     }
 
     @Override
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedScaledInductionVariable.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedScaledInductionVariable.java	Mon May 13 17:11:31 2013 +0200
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.loop;
 
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.type.*;
@@ -96,8 +97,8 @@
     }
 
     @Override
-    public ValueNode extremumNode() {
-        return IntegerArithmeticNode.mul(base.extremumNode(), scale);
+    public ValueNode extremumNode(boolean assumePositiveTripCount, Kind kind) {
+        return IntegerArithmeticNode.mul(base.extremumNode(assumePositiveTripCount, kind), ConvertNode.convert(kind, scale));
     }
 
     @Override
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariable.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariable.java	Mon May 13 17:11:31 2013 +0200
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.loop;
 
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 
@@ -48,6 +49,10 @@
         this.loop = loop;
     }
 
+    public LoopEx getLoop() {
+        return loop;
+    }
+
     public abstract Direction direction();
 
     public abstract ValueNode valueNode();
@@ -64,7 +69,11 @@
 
     public abstract long constantStride();
 
-    public abstract ValueNode extremumNode();
+    public ValueNode extremumNode() {
+        return extremumNode(false, valueNode().kind());
+    }
+
+    public abstract ValueNode extremumNode(boolean assumePositiveTripCount, Kind kind);
 
     public abstract boolean isConstantExtremum();
 
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariables.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariables.java	Mon May 13 17:11:31 2013 +0200
@@ -46,7 +46,7 @@
     private Collection<BasicInductionVariable> findBasic() {
         List<BasicInductionVariable> bivs = new LinkedList<>();
         LoopBeginNode loopBegin = loop.loopBegin();
-        EndNode forwardEnd = loopBegin.forwardEnd();
+        AbstractEndNode forwardEnd = loopBegin.forwardEnd();
         for (PhiNode phi : loopBegin.phis()) {
             ValueNode backValue = phi.singleBackValue();
             if (backValue == null) {
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopEx.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopEx.java	Mon May 13 17:11:31 2013 +0200
@@ -39,6 +39,7 @@
     private LoopFragmentWhole whole;
     private CountedLoopInfo counted; // TODO (gd) detect
     private LoopsData data;
+    private InductionVariables ivs;
 
     LoopEx(Loop lirLoop, LoopsData data) {
         this.lirLoop = lirLoop;
@@ -125,7 +126,7 @@
 
     public void reassociateInvariants() {
         InvariantPredicate invariant = new InvariantPredicate();
-        StructuredGraph graph = (StructuredGraph) loopBegin().graph();
+        StructuredGraph graph = loopBegin().graph();
         for (BinaryNode binary : whole().nodes().filter(BinaryNode.class)) {
             if (!BinaryNode.canTryReassociate(binary)) {
                 continue;
@@ -148,9 +149,9 @@
         return data;
     }
 
-    public NodeBitMap nodesInLoopFrom(BeginNode point, BeginNode until) {
-        Collection<BeginNode> blocks = new LinkedList<>();
-        Collection<BeginNode> exits = new LinkedList<>();
+    public NodeBitMap nodesInLoopFrom(AbstractBeginNode point, AbstractBeginNode until) {
+        Collection<AbstractBeginNode> blocks = new LinkedList<>();
+        Collection<AbstractBeginNode> exits = new LinkedList<>();
         Queue<Block> work = new LinkedList<>();
         ControlFlowGraph cfg = loopsData().controlFlowGraph();
         work.add(cfg.blockFor(point));
@@ -169,4 +170,11 @@
         }
         return LoopFragment.computeNodes(point.graph(), blocks, exits);
     }
+
+    public InductionVariables getInductionVariables() {
+        if (ivs == null) {
+            ivs = new InductionVariables(this);
+        }
+        return ivs;
+    }
 }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java	Mon May 13 17:11:31 2013 +0200
@@ -95,7 +95,7 @@
         } else {
             l = loop();
         }
-        return (StructuredGraph) l.loopBegin().graph();
+        return l.loopBegin().graph();
     }
 
     protected abstract DuplicationReplacement getDuplicationReplacement();
@@ -145,13 +145,13 @@
         }
     }
 
-    protected static NodeBitMap computeNodes(Graph graph, Collection<BeginNode> blocks) {
-        return computeNodes(graph, blocks, Collections.<BeginNode> emptyList());
+    protected static NodeBitMap computeNodes(Graph graph, Collection<AbstractBeginNode> blocks) {
+        return computeNodes(graph, blocks, Collections.<AbstractBeginNode> emptyList());
     }
 
-    protected static NodeBitMap computeNodes(Graph graph, Collection<BeginNode> blocks, Collection<BeginNode> earlyExits) {
+    protected static NodeBitMap computeNodes(Graph graph, Collection<AbstractBeginNode> blocks, Collection<AbstractBeginNode> earlyExits) {
         final NodeBitMap nodes = graph.createNodeBitMap(true);
-        for (BeginNode b : blocks) {
+        for (AbstractBeginNode b : blocks) {
             for (Node n : b.getBlockNodes()) {
                 if (n instanceof Invoke) {
                     nodes.mark(((Invoke) n).callTarget());
@@ -165,7 +165,7 @@
                 nodes.mark(n);
             }
         }
-        for (BeginNode earlyExit : earlyExits) {
+        for (AbstractBeginNode earlyExit : earlyExits) {
             FrameState stateAfter = earlyExit.stateAfter();
             if (stateAfter != null) {
                 nodes.mark(stateAfter);
@@ -183,10 +183,11 @@
             }
         }
 
-        for (BeginNode b : blocks) {
+        final NodeBitMap notloopNodes = graph.createNodeBitMap(true);
+        for (AbstractBeginNode b : blocks) {
             for (Node n : b.getBlockNodes()) {
                 for (Node usage : n.usages()) {
-                    markFloating(usage, nodes);
+                    markFloating(usage, nodes, notloopNodes);
                 }
             }
         }
@@ -194,10 +195,13 @@
         return nodes;
     }
 
-    private static boolean markFloating(Node n, NodeBitMap loopNodes) {
+    private static boolean markFloating(Node n, NodeBitMap loopNodes, NodeBitMap notloopNodes) {
         if (loopNodes.isMarked(n)) {
             return true;
         }
+        if (notloopNodes.isMarked(n)) {
+            return false;
+        }
         if (n instanceof FixedNode) {
             return false;
         }
@@ -208,11 +212,12 @@
             if (mark) {
                 loopNodes.mark(n);
             } else {
+                notloopNodes.mark(n);
                 return false;
             }
         }
         for (Node usage : n.usages()) {
-            if (markFloating(usage, loopNodes)) {
+            if (markFloating(usage, loopNodes, notloopNodes)) {
                 mark = true;
             }
         }
@@ -220,11 +225,12 @@
             loopNodes.mark(n);
             return true;
         }
+        notloopNodes.mark(n);
         return false;
     }
 
-    public static Collection<BeginNode> toHirBlocks(Collection<Block> blocks) {
-        List<BeginNode> hir = new ArrayList<>(blocks.size());
+    public static Collection<AbstractBeginNode> toHirBlocks(Collection<Block> blocks) {
+        List<AbstractBeginNode> hir = new ArrayList<>(blocks.size());
         for (Block b : blocks) {
             hir.add(b.getBeginNode());
         }
@@ -238,18 +244,18 @@
     protected void mergeEarlyExits() {
         assert isDuplicate();
         StructuredGraph graph = graph();
-        for (BeginNode earlyExit : LoopFragment.toHirBlocks(original().loop().lirLoop().exits)) {
+        for (AbstractBeginNode earlyExit : LoopFragment.toHirBlocks(original().loop().lirLoop().exits)) {
             FixedNode next = earlyExit.next();
             if (earlyExit.isDeleted() || !this.original().contains(earlyExit)) {
                 continue;
             }
-            BeginNode newEarlyExit = getDuplicatedNode(earlyExit);
+            AbstractBeginNode newEarlyExit = getDuplicatedNode(earlyExit);
             if (newEarlyExit == null) {
                 continue;
             }
             MergeNode merge = graph.add(new MergeNode());
-            EndNode originalEnd = graph.add(new EndNode());
-            EndNode newEnd = graph.add(new EndNode());
+            AbstractEndNode originalEnd = graph.add(new EndNode());
+            AbstractEndNode newEnd = graph.add(new EndNode());
             merge.addForwardEnd(originalEnd);
             merge.addForwardEnd(newEnd);
             earlyExit.setNext(originalEnd);
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInside.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInside.java	Mon May 13 17:11:31 2013 +0200
@@ -89,13 +89,13 @@
 
         patchNodes(dataFixBefore);
 
-        BeginNode end = mergeEnds();
+        AbstractBeginNode end = mergeEnds();
 
         original().patchPeeling(this);
 
         mergeEarlyExits();
 
-        BeginNode entry = getDuplicatedNode(loop.loopBegin());
+        AbstractBeginNode entry = getDuplicatedNode(loop.loopBegin());
         FrameState state = entry.stateAfter();
         if (state != null) {
             entry.setStateAfter(null);
@@ -148,7 +148,7 @@
 
     private void patchPeeling(LoopFragmentInside peel) {
         LoopBeginNode loopBegin = loop().loopBegin();
-        StructuredGraph graph = (StructuredGraph) loopBegin.graph();
+        StructuredGraph graph = loopBegin.graph();
         List<PhiNode> newPhis = new LinkedList<>();
         for (PhiNode phi : loopBegin.phis().snapshot()) {
             ValueNode first;
@@ -213,24 +213,24 @@
         }
     }
 
-    private BeginNode mergeEnds() {
+    private AbstractBeginNode mergeEnds() {
         assert isDuplicate();
-        List<EndNode> endsToMerge = new LinkedList<>();
-        Map<EndNode, LoopEndNode> reverseEnds = new HashMap<>(); // map peel's exit to the
-                                                                 // corresponding loop exits
+        List<AbstractEndNode> endsToMerge = new LinkedList<>();
+        Map<AbstractEndNode, LoopEndNode> reverseEnds = new HashMap<>(); // map peel's exit to the
+        // corresponding loop exits
         LoopBeginNode loopBegin = original().loop().loopBegin();
         for (LoopEndNode le : loopBegin.loopEnds()) {
-            EndNode duplicate = getDuplicatedNode(le);
+            AbstractEndNode duplicate = getDuplicatedNode(le);
             if (duplicate != null) {
                 endsToMerge.add(duplicate);
                 reverseEnds.put(duplicate, le);
             }
         }
         mergedInitializers = new IdentityHashMap<>();
-        BeginNode newExit;
+        AbstractBeginNode newExit;
         StructuredGraph graph = graph();
         if (endsToMerge.size() == 1) {
-            EndNode end = endsToMerge.get(0);
+            AbstractEndNode end = endsToMerge.get(0);
             assert end.usages().count() == 0;
             newExit = graph.add(new BeginNode());
             end.replaceAtPredecessor(newExit);
@@ -245,13 +245,13 @@
                 duplicateState = state.duplicateWithVirtualState();
                 newExitMerge.setStateAfter(duplicateState);
             }
-            for (EndNode end : endsToMerge) {
+            for (AbstractEndNode end : endsToMerge) {
                 newExitMerge.addForwardEnd(end);
             }
 
             for (final PhiNode phi : loopBegin.phis().snapshot()) {
                 final PhiNode firstPhi = graph.add(phi.type() == PhiType.Value ? new PhiNode(phi.kind(), newExitMerge) : new PhiNode(phi.type(), newExitMerge, phi.getIdentity()));
-                for (EndNode end : newExitMerge.forwardEnds()) {
+                for (AbstractEndNode end : newExitMerge.forwardEnds()) {
                     LoopEndNode loopEnd = reverseEnds.get(end);
                     ValueNode prim = prim(phi.valueAt(loopEnd));
                     assert prim != null;
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java	Mon May 13 17:11:31 2013 +0200
@@ -60,12 +60,12 @@
 
     public static boolean shouldUnswitch(LoopEx loop, ControlSplitNode controlSplit) {
         Block postDomBlock = loop.loopsData().controlFlowGraph().blockFor(controlSplit).getPostdominator();
-        BeginNode postDom = postDomBlock != null ? postDomBlock.getBeginNode() : null;
+        AbstractBeginNode postDom = postDomBlock != null ? postDomBlock.getBeginNode() : null;
         int loopTotal = loop.size();
         int inBranchTotal = 0;
         double maxProbability = 0;
         for (Node successor : controlSplit.successors()) {
-            BeginNode branch = (BeginNode) successor;
+            AbstractBeginNode branch = (AbstractBeginNode) successor;
             inBranchTotal += loop.nodesInLoopFrom(branch, postDom).cardinality(); // this may count
                                                                                   // twice because
                                                                                   // of fall-through
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java	Mon May 13 17:11:31 2013 +0200
@@ -56,7 +56,7 @@
         // assert loop.isCounted(); //TODO (gd) strenghten : counted with known trip count
         int iterations = 0;
         LoopBeginNode loopBegin = loop.loopBegin();
-        StructuredGraph graph = (StructuredGraph) loopBegin.graph();
+        StructuredGraph graph = loopBegin.graph();
         while (!loopBegin.isDeleted()) {
             int mark = graph.getMark();
             peel(loop);
@@ -78,19 +78,19 @@
         // original loop is used as first successor
         Position firstPosition = successors.nextPosition();
         NodeClass controlSplitClass = controlSplitNode.getNodeClass();
-        controlSplitClass.set(newControlSplit, firstPosition, BeginNode.begin(originalLoop.entryPoint()));
+        controlSplitClass.set(newControlSplit, firstPosition, AbstractBeginNode.begin(originalLoop.entryPoint()));
 
-        StructuredGraph graph = (StructuredGraph) controlSplitNode.graph();
+        StructuredGraph graph = controlSplitNode.graph();
         while (successors.hasNext()) {
             Position position = successors.nextPosition();
             // create a new loop duplicate, connect it and simplify it
             LoopFragmentWhole duplicateLoop = originalLoop.duplicate();
-            controlSplitClass.set(newControlSplit, position, BeginNode.begin(duplicateLoop.entryPoint()));
+            controlSplitClass.set(newControlSplit, position, AbstractBeginNode.begin(duplicateLoop.entryPoint()));
             ControlSplitNode duplicatedControlSplit = duplicateLoop.getDuplicatedNode(controlSplitNode);
-            graph.removeSplitPropagate(duplicatedControlSplit, (BeginNode) controlSplitClass.get(duplicatedControlSplit, position));
+            graph.removeSplitPropagate(duplicatedControlSplit, (AbstractBeginNode) controlSplitClass.get(duplicatedControlSplit, position));
         }
         // original loop is simplified last to avoid deleting controlSplitNode too early
-        graph.removeSplitPropagate(controlSplitNode, (BeginNode) controlSplitClass.get(controlSplitNode, firstPosition));
+        graph.removeSplitPropagate(controlSplitNode, (AbstractBeginNode) controlSplitClass.get(controlSplitNode, firstPosition));
         // TODO (gd) probabilities need some amount of fixup.. (probably also in other transforms)
     }
 
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopsData.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopsData.java	Mon May 13 17:11:31 2013 +0200
@@ -31,6 +31,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.cfg.*;
+import com.oracle.graal.nodes.extended.*;
 
 public class LoopsData {
 
@@ -92,6 +93,9 @@
             InductionVariables ivs = new InductionVariables(loop);
             LoopBeginNode loopBegin = loop.loopBegin();
             FixedNode next = loopBegin.next();
+            while (next instanceof FixedGuardNode || next instanceof ValueAnchorNode) {
+                next = ((FixedWithNextNode) next).next();
+            }
             if (next instanceof IfNode) {
                 IfNode ifNode = (IfNode) next;
                 boolean negated = false;
@@ -150,7 +154,7 @@
                     default:
                         throw GraalInternalError.shouldNotReachHere();
                 }
-                loop.setCounted(new CountedLoopInfo(loop, iv, limit, oneOff));
+                loop.setCounted(new CountedLoopInfo(loop, iv, limit, oneOff, negated ? ifNode.falseSuccessor() : ifNode.trueSuccessor()));
             }
         }
     }
@@ -158,4 +162,18 @@
     public ControlFlowGraph controlFlowGraph() {
         return cfg;
     }
+
+    public InductionVariable getInductionVariable(ValueNode value) {
+        InductionVariable match = null;
+        for (LoopEx loop : loops()) {
+            InductionVariable iv = loop.getInductionVariables().get(value);
+            if (iv != null) {
+                if (match != null) {
+                    return null;
+                }
+                match = iv;
+            }
+        }
+        return match;
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopSafepointEliminationPhase.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2011, 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.loop.phases;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.loop.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.cfg.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.tiers.*;
+
+public class LoopSafepointEliminationPhase extends BasePhase<MidTierContext> {
+
+    @Override
+    protected void run(StructuredGraph graph, MidTierContext context) {
+        LoopsData loops = new LoopsData(graph);
+        if (context.getOptimisticOptimizations().useLoopLimitChecks()) {
+            loops.detectedCountedLoops();
+            for (LoopEx loop : loops.countedLoops()) {
+                if (loop.lirLoop().children.isEmpty() && loop.counted().getKind() == Kind.Int) {
+                    loop.counted().createOverFlowGuard();
+                    for (LoopEndNode loopEnd : loop.loopBegin().loopEnds()) {
+                        loopEnd.disableSafepoint();
+                    }
+                }
+            }
+        }
+        for (LoopEx loop : loops.countedLoops()) {
+            for (LoopEndNode loopEnd : loop.loopBegin().loopEnds()) {
+                Block b = loops.controlFlowGraph().blockFor(loopEnd);
+                blocks: while (b != loop.lirLoop().header) {
+                    assert b != null;
+                    for (FixedNode node : b.getNodes()) {
+                        if (node instanceof Invoke || node instanceof RuntimeCallNode) {
+                            loopEnd.disableSafepoint();
+                            break blocks;
+                        }
+                    }
+                    b = b.getDominator();
+                }
+            }
+        }
+    }
+}
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformLowPhase.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformLowPhase.java	Mon May 13 17:11:31 2013 +0200
@@ -77,7 +77,7 @@
         sb.append(loop).append(" at ").append(controlSplit).append(" [");
         NodeClassIterator it = controlSplit.successors().iterator();
         while (it.hasNext()) {
-            sb.append(controlSplit.probability((BeginNode) it.next()));
+            sb.append(controlSplit.probability((AbstractBeginNode) it.next()));
             if (it.hasNext()) {
                 sb.append(", ");
             }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractBeginNode.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes;
+
+import static com.oracle.graal.graph.iterators.NodePredicates.*;
+
+import java.util.*;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.iterators.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+
+public abstract class AbstractBeginNode extends FixedWithNextNode implements StateSplit, LIRLowerable, Simplifiable, Node.IterableNodeType, GuardingNode {
+
+    @Input(notDataflow = true) private FrameState stateAfter;
+
+    public FrameState stateAfter() {
+        return stateAfter;
+    }
+
+    public void setStateAfter(FrameState x) {
+        assert x == null || x.isAlive() : "frame state must be in a graph";
+        updateUsages(stateAfter, x);
+        stateAfter = x;
+    }
+
+    public boolean hasSideEffect() {
+        return false;
+    }
+
+    protected AbstractBeginNode() {
+        super(StampFactory.dependency());
+    }
+
+    protected AbstractBeginNode(Stamp stamp) {
+        super(stamp);
+    }
+
+    public static AbstractBeginNode begin(FixedNode with) {
+        if (with instanceof AbstractBeginNode) {
+            return (AbstractBeginNode) with;
+        }
+        AbstractBeginNode begin = with.graph().add(new BeginNode());
+        begin.setNext(with);
+        return begin;
+    }
+
+    @Override
+    public void simplify(SimplifierTool tool) {
+        FixedNode prev = (FixedNode) this.predecessor();
+        if (prev == null) {
+            // This is the start node.
+        } else if (prev instanceof ControlSplitNode) {
+            // This begin node is necessary.
+        } else {
+            // This begin node can be removed and all guards moved up to the preceding begin node.
+            prepareDelete();
+            tool.addToWorkList(next());
+            graph().removeFixed(this);
+        }
+    }
+
+    public static AbstractBeginNode prevBegin(FixedNode from) {
+        Node prevBegin = from;
+        while (prevBegin != null) {
+            if (prevBegin instanceof AbstractBeginNode) {
+                return (AbstractBeginNode) prevBegin;
+            }
+            prevBegin = prevBegin.predecessor();
+        }
+        return null;
+    }
+
+    private void evacuateGuards(FixedNode evacuateFrom) {
+        if (!usages().isEmpty()) {
+            AbstractBeginNode prevBegin = prevBegin(evacuateFrom);
+            assert prevBegin != null;
+            for (Node anchored : anchored().snapshot()) {
+                anchored.replaceFirstInput(this, prevBegin);
+            }
+        }
+    }
+
+    public void prepareDelete() {
+        prepareDelete((FixedNode) predecessor());
+    }
+
+    public void prepareDelete(FixedNode evacuateFrom) {
+        removeProxies();
+        evacuateGuards(evacuateFrom);
+    }
+
+    public void removeProxies() {
+        for (ProxyNode vpn : proxies().snapshot()) {
+            // can not use graph.replaceFloating because vpn.value may be null during killCFG
+            vpn.replaceAtUsages(vpn.value());
+            vpn.safeDelete();
+        }
+    }
+
+    @Override
+    public boolean verify() {
+        assertTrue(predecessor() != null || this == graph().start() || this instanceof MergeNode, "begin nodes must be connected");
+        return super.verify();
+    }
+
+    @Override
+    public void generate(LIRGeneratorTool gen) {
+        // nop
+    }
+
+    public NodeIterable<GuardNode> guards() {
+        return usages().filter(GuardNode.class);
+    }
+
+    public NodeIterable<Node> anchored() {
+        return usages().filter(isNotA(ProxyNode.class));
+    }
+
+    public NodeIterable<ProxyNode> proxies() {
+        return usages().filter(ProxyNode.class);
+    }
+
+    public NodeIterable<FixedNode> getBlockNodes() {
+        return new AbstractNodeIterable<FixedNode>() {
+
+            @Override
+            public Iterator<FixedNode> iterator() {
+                return new BlockNodeIterator(AbstractBeginNode.this);
+            }
+        };
+    }
+
+    private class BlockNodeIterator implements Iterator<FixedNode> {
+
+        private FixedNode current;
+
+        public BlockNodeIterator(FixedNode next) {
+            this.current = next;
+        }
+
+        @Override
+        public boolean hasNext() {
+            return current != null;
+        }
+
+        @Override
+        public FixedNode next() {
+            FixedNode ret = current;
+            if (ret == null) {
+                throw new NoSuchElementException();
+            }
+            if (!(current instanceof FixedWithNextNode) || (current instanceof AbstractBeginNode && current != AbstractBeginNode.this)) {
+                current = null;
+            } else {
+                current = ((FixedWithNextNode) current).next();
+            }
+            return ret;
+        }
+
+        @Override
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    @Override
+    public AbstractBeginNode asNode() {
+        return this;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractEndNode.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes;
+
+import java.util.*;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+
+public abstract class AbstractEndNode extends FixedNode implements Node.IterableNodeType, LIRLowerable {
+
+    protected AbstractEndNode() {
+        super(StampFactory.forVoid());
+    }
+
+    @Override
+    public void generate(LIRGeneratorTool gen) {
+        gen.visitEndNode(this);
+    }
+
+    public MergeNode merge() {
+        return (MergeNode) usages().first();
+    }
+
+    @Override
+    public boolean verify() {
+        assertTrue(usages().count() <= 1, "at most one usage");
+        return super.verify();
+    }
+
+    @Override
+    public Iterable<? extends Node> cfgSuccessors() {
+        return Arrays.asList(merge());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractLocalNode.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,54 @@
+/*
+ * 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.nodes.calc.*;
+import com.oracle.graal.nodes.type.*;
+
+public abstract class AbstractLocalNode extends FloatingNode {
+
+    private final int index;
+
+    public AbstractLocalNode(int index, Stamp stamp) {
+        super(stamp);
+        this.index = index;
+    }
+
+    /**
+     * Gets the index of this local in the array of parameters. This is NOT the JVM local index.
+     * 
+     * @return the index
+     */
+    public int index() {
+        return index;
+    }
+
+    @Override
+    public String toString(Verbosity verbosity) {
+        if (verbosity == Verbosity.Name) {
+            return super.toString(Verbosity.Name) + "(" + index + ")";
+        } else {
+            return super.toString(verbosity);
+        }
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java	Mon May 13 17:11:31 2013 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -22,32 +22,9 @@
  */
 package com.oracle.graal.nodes;
 
-import static com.oracle.graal.graph.iterators.NodePredicates.*;
-
-import java.util.*;
-
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.iterators.*;
-import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
-public class BeginNode extends FixedWithNextNode implements StateSplit, LIRLowerable, Simplifiable, Node.IterableNodeType {
-
-    @Input(notDataflow = true) private FrameState stateAfter;
-
-    public FrameState stateAfter() {
-        return stateAfter;
-    }
-
-    public void setStateAfter(FrameState x) {
-        assert x == null || x.isAlive() : "frame state must be in a graph";
-        updateUsages(stateAfter, x);
-        stateAfter = x;
-    }
-
-    public boolean hasSideEffect() {
-        return false;
-    }
+public final class BeginNode extends AbstractBeginNode {
 
     public BeginNode() {
         super(StampFactory.dependency());
@@ -57,134 +34,6 @@
         super(stamp);
     }
 
-    public static BeginNode begin(FixedNode with) {
-        if (with instanceof BeginNode) {
-            return (BeginNode) with;
-        }
-        BeginNode begin = with.graph().add(new BeginNode());
-        begin.setNext(with);
-        return begin;
-    }
-
-    @Override
-    public void simplify(SimplifierTool tool) {
-        FixedNode prev = (FixedNode) this.predecessor();
-        if (prev == null) {
-            // This is the start node.
-        } else if (prev instanceof ControlSplitNode) {
-            // This begin node is necessary.
-        } else {
-            // This begin node can be removed and all guards moved up to the preceding begin node.
-            prepareDelete();
-            tool.addToWorkList(next());
-            ((StructuredGraph) graph()).removeFixed(this);
-        }
-    }
-
-    public static BeginNode prevBegin(FixedNode from) {
-        Node prevBegin = from;
-        while (prevBegin != null) {
-            if (prevBegin instanceof BeginNode) {
-                return (BeginNode) prevBegin;
-            }
-            prevBegin = prevBegin.predecessor();
-        }
-        return null;
-    }
-
-    private void evacuateGuards(FixedNode evacuateFrom) {
-        if (!usages().isEmpty()) {
-            BeginNode prevBegin = prevBegin(evacuateFrom);
-            assert prevBegin != null;
-            for (Node anchored : anchored().snapshot()) {
-                anchored.replaceFirstInput(this, prevBegin);
-            }
-        }
-    }
-
-    public void prepareDelete() {
-        prepareDelete((FixedNode) predecessor());
-    }
-
-    public void prepareDelete(FixedNode evacuateFrom) {
-        removeProxies();
-        evacuateGuards(evacuateFrom);
-    }
-
-    public void removeProxies() {
-        for (ProxyNode vpn : proxies().snapshot()) {
-            // can not use graph.replaceFloating because vpn.value may be null during killCFG
-            vpn.replaceAtUsages(vpn.value());
-            vpn.safeDelete();
-        }
-    }
-
-    @Override
-    public boolean verify() {
-        assertTrue(predecessor() != null || this == ((StructuredGraph) graph()).start() || this instanceof MergeNode, "begin nodes must be connected");
-        return super.verify();
-    }
-
-    @Override
-    public void generate(LIRGeneratorTool gen) {
-        // nop
-    }
-
-    public NodeIterable<GuardNode> guards() {
-        return usages().filter(GuardNode.class);
-    }
-
-    public NodeIterable<Node> anchored() {
-        return usages().filter(isNotA(ProxyNode.class));
-    }
-
-    public NodeIterable<ProxyNode> proxies() {
-        return usages().filter(ProxyNode.class);
-    }
-
-    public NodeIterable<FixedNode> getBlockNodes() {
-        return new AbstractNodeIterable<FixedNode>() {
-
-            @Override
-            public Iterator<FixedNode> iterator() {
-                return new BlockNodeIterator(BeginNode.this);
-            }
-        };
-    }
-
-    private class BlockNodeIterator implements Iterator<FixedNode> {
-
-        private FixedNode current;
-
-        public BlockNodeIterator(FixedNode next) {
-            this.current = next;
-        }
-
-        @Override
-        public boolean hasNext() {
-            return current != null;
-        }
-
-        @Override
-        public FixedNode next() {
-            FixedNode ret = current;
-            if (ret == null) {
-                throw new NoSuchElementException();
-            }
-            if (!(current instanceof FixedWithNextNode) || (current instanceof BeginNode && current != BeginNode.this)) {
-                current = null;
-            } else {
-                current = ((FixedWithNextNode) current).next();
-            }
-            return ret;
-        }
-
-        @Override
-        public void remove() {
-            throw new UnsupportedOperationException();
-        }
-    }
-
     @NodeIntrinsic
     public static native BeginNode anchor(@ConstantNodeParameter Stamp stamp);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginStateSplitNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginStateSplitNode.java	Mon May 13 17:11:31 2013 +0200
@@ -25,11 +25,11 @@
 import com.oracle.graal.nodes.type.*;
 
 /**
- * Base class for {@link BeginNode}s that are associated with a frame state. TODO (dnsimon) this not
- * needed until {@link BeginNode} no longer implements {@link StateSplit} which is not possible
+ * Base class for {@link AbstractBeginNode}s that are associated with a frame state. TODO (dnsimon) this not
+ * needed until {@link AbstractBeginNode} no longer implements {@link StateSplit} which is not possible
  * until loop peeling works without requiring begin nodes to have frames states
  */
-public abstract class BeginStateSplitNode extends BeginNode implements StateSplit {
+public abstract class BeginStateSplitNode extends AbstractBeginNode implements StateSplit {
 
     public BeginStateSplitNode() {
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ControlSinkNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ControlSinkNode.java	Mon May 13 17:11:31 2013 +0200
@@ -22,9 +22,10 @@
  */
 package com.oracle.graal.nodes;
 
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.type.*;
 
-public abstract class ControlSinkNode extends FixedNode {
+public abstract class ControlSinkNode extends FixedNode implements Node.IterableNodeType {
 
     public ControlSinkNode(Stamp stamp) {
         super(stamp);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ControlSplitNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ControlSplitNode.java	Mon May 13 17:11:31 2013 +0200
@@ -34,5 +34,5 @@
         super(stamp);
     }
 
-    public abstract double probability(BeginNode successor);
+    public abstract double probability(AbstractBeginNode successor);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizingFixedWithNextNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizingFixedWithNextNode.java	Mon May 13 17:11:31 2013 +0200
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.nodes;
 
-import java.util.*;
-
 import com.oracle.graal.nodes.type.*;
 
 public abstract class DeoptimizingFixedWithNextNode extends FixedWithNextNode implements DeoptimizingNode {
@@ -34,14 +32,6 @@
         super(stamp);
     }
 
-    public DeoptimizingFixedWithNextNode(Stamp stamp, List<ValueNode> dependencies) {
-        super(stamp, dependencies);
-    }
-
-    public DeoptimizingFixedWithNextNode(Stamp stamp, ValueNode... dependencies) {
-        super(stamp, dependencies);
-    }
-
     @Override
     public FrameState getDeoptimizationState() {
         return deoptState;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/EndNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/EndNode.java	Mon May 13 17:11:31 2013 +0200
@@ -22,35 +22,5 @@
  */
 package com.oracle.graal.nodes;
 
-import java.util.*;
-
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
-
-public class EndNode extends FixedNode implements Node.IterableNodeType, LIRLowerable {
-
-    public EndNode() {
-        super(StampFactory.forVoid());
-    }
-
-    @Override
-    public void generate(LIRGeneratorTool gen) {
-        gen.visitEndNode(this);
-    }
-
-    public MergeNode merge() {
-        return (MergeNode) usages().first();
-    }
-
-    @Override
-    public boolean verify() {
-        assertTrue(usages().count() <= 1, "at most one usage");
-        return super.verify();
-    }
-
-    @Override
-    public Iterable<? extends Node> cfgSuccessors() {
-        return Arrays.asList(merge());
-    }
+public final class EndNode extends AbstractEndNode {
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/EntryMarkerNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/EntryMarkerNode.java	Mon May 13 17:11:31 2013 +0200
@@ -29,7 +29,7 @@
  * This node will be inserted at point specified by {@link StructuredGraph#getEntryBCI()}, usually
  * by the graph builder.
  */
-public class EntryMarkerNode extends BeginNode implements Node.IterableNodeType, Simplifiable, LIRLowerable {
+public class EntryMarkerNode extends AbstractBeginNode implements Node.IterableNodeType, Simplifiable, LIRLowerable {
 
     @Override
     public void simplify(SimplifierTool tool) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java	Mon May 13 17:11:31 2013 +0200
@@ -27,6 +27,7 @@
 import com.oracle.graal.graph.*;
 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 FixedWithNextNode implements Simplifiable, Lowerable, Node.IterableNodeType, Negatable {
@@ -83,7 +84,7 @@
         if (condition instanceof LogicConstantNode) {
             LogicConstantNode c = (LogicConstantNode) condition;
             if (c.getValue() != negated) {
-                ((StructuredGraph) graph()).removeFixed(this);
+                graph().removeFixed(this);
             } else {
                 FixedNode next = this.next();
                 if (next != null) {
@@ -97,11 +98,26 @@
 
     @Override
     public void lower(LoweringTool tool, LoweringType loweringType) {
-        tool.getRuntime().lower(this, tool);
+        if (loweringType == LoweringType.BEFORE_GUARDS) {
+            tool.getRuntime().lower(this, tool);
+        } else {
+            FixedNode next = next();
+            setNext(null);
+            DeoptimizeNode deopt = graph().add(new DeoptimizeNode(action, reason));
+            IfNode ifNode;
+            if (negated) {
+                ifNode = graph().add(new IfNode(condition, deopt, next, 0));
+            } else {
+                ifNode = graph().add(new IfNode(condition, next, deopt, 1));
+            }
+            ((FixedWithNextNode) predecessor()).setNext(ifNode);
+            GraphUtil.killWithUnusedFloatingInputs(this);
+        }
     }
 
     @Override
-    public Negatable negate() {
+    public Negatable negate(LogicNode cond) {
+        assert cond == condition();
         negated = !negated;
         return this;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedNode.java	Mon May 13 17:11:31 2013 +0200
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.nodes;
 
-import java.util.*;
-
 import com.oracle.graal.nodes.type.*;
 
 public abstract class FixedNode extends ValueNode {
@@ -32,14 +30,6 @@
         super(stamp);
     }
 
-    public FixedNode(Stamp stamp, List<ValueNode> dependencies) {
-        super(stamp, dependencies);
-    }
-
-    public FixedNode(Stamp stamp, ValueNode... dependencies) {
-        super(stamp, dependencies);
-    }
-
     @Override
     public boolean verify() {
         assertTrue(this.successors().isNotEmpty() || this.predecessor() != null, "FixedNode should not float");
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedWithNextNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedWithNextNode.java	Mon May 13 17:11:31 2013 +0200
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.nodes;
 
-import java.util.*;
-
 import com.oracle.graal.nodes.type.*;
 
 /**
@@ -44,12 +42,4 @@
     public FixedWithNextNode(Stamp stamp) {
         super(stamp);
     }
-
-    public FixedWithNextNode(Stamp stamp, List<ValueNode> dependencies) {
-        super(stamp, dependencies);
-    }
-
-    public FixedWithNextNode(Stamp stamp, ValueNode... dependencies) {
-        super(stamp, dependencies);
-    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FloatingGuardedNode.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,58 @@
+/*
+ * 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.calc.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.type.*;
+
+public abstract class FloatingGuardedNode extends FloatingNode implements GuardedNode {
+
+    @Input private GuardingNode guard;
+
+    public FloatingGuardedNode(Stamp stamp) {
+        super(stamp);
+    }
+
+    public FloatingGuardedNode(Stamp stamp, GuardingNode guard) {
+        super(stamp);
+        this.guard = guard;
+    }
+
+    @Override
+    public GuardingNode getGuard() {
+        return guard;
+    }
+
+    @Override
+    public void setGuard(GuardingNode guard) {
+        updateUsages(this.guard == null ? null : this.guard.asNode(), guard == null ? null : guard.asNode());
+        this.guard = guard;
+    }
+
+    @Override
+    public FloatingNode asNode() {
+        return this;
+    }
+
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java	Mon May 13 17:11:31 2013 +0200
@@ -25,7 +25,7 @@
 import com.oracle.graal.api.code.*;
 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.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -42,14 +42,14 @@
  * 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 FloatingNode implements Canonicalizable, Node.IterableNodeType, Negatable {
+public final class GuardNode extends FloatingGuardedNode implements Canonicalizable, Node.IterableNodeType, Negatable, GuardingNode, GuardedNode {
 
     @Input private LogicNode condition;
     private final DeoptimizationReason reason;
     private final DeoptimizationAction action;
     private boolean negated;
 
-    public GuardNode(LogicNode condition, FixedNode anchor, DeoptimizationReason reason, DeoptimizationAction action, boolean negated) {
+    public GuardNode(LogicNode condition, GuardingNode anchor, DeoptimizationReason reason, DeoptimizationAction action, boolean negated) {
         super(StampFactory.dependency(), anchor);
         this.condition = condition;
         this.reason = reason;
@@ -95,16 +95,15 @@
         if (condition() instanceof LogicConstantNode) {
             LogicConstantNode c = (LogicConstantNode) condition();
             if (c.getValue() != negated) {
-                if (dependencies().size() == 1) {
-                    return dependencies().get(0);
-                }
+                return getGuard().asNode();
             }
         }
         return this;
     }
 
     @Override
-    public Negatable negate() {
+    public Negatable negate(LogicNode cond) {
+        assert cond == condition();
         negated = !negated;
         return this;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Mon May 13 17:11:31 2013 +0200
@@ -25,10 +25,14 @@
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.JavaTypeProfile.ProfiledType;
+import com.oracle.graal.api.meta.ProfilingInfo.TriState;
+import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.nodes.PhiNode.PhiType;
 import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
@@ -39,8 +43,8 @@
  */
 public final class IfNode extends ControlSplitNode implements Simplifiable, LIRLowerable, Negatable {
 
-    @Successor private BeginNode trueSuccessor;
-    @Successor private BeginNode falseSuccessor;
+    @Successor private AbstractBeginNode trueSuccessor;
+    @Successor private AbstractBeginNode falseSuccessor;
     @Input private LogicNode condition;
     private double trueSuccessorProbability;
 
@@ -54,15 +58,15 @@
     }
 
     public IfNode(LogicNode condition, FixedNode trueSuccessor, FixedNode falseSuccessor, double trueSuccessorProbability) {
-        this(condition, BeginNode.begin(trueSuccessor), BeginNode.begin(falseSuccessor), trueSuccessorProbability);
+        this(condition, AbstractBeginNode.begin(trueSuccessor), AbstractBeginNode.begin(falseSuccessor), trueSuccessorProbability);
     }
 
-    public IfNode(LogicNode condition, BeginNode trueSuccessor, BeginNode falseSuccessor, double trueSuccessorProbability) {
+    public IfNode(LogicNode condition, AbstractBeginNode trueSuccessor, AbstractBeginNode falseSuccessor, double trueSuccessorProbability) {
         super(StampFactory.forVoid());
         this.condition = condition;
         this.falseSuccessor = falseSuccessor;
-        this.trueSuccessorProbability = trueSuccessorProbability;
         this.trueSuccessor = trueSuccessor;
+        setTrueSuccessorProbability(trueSuccessorProbability);
 
     }
 
@@ -71,7 +75,7 @@
      * 
      * @return the true successor
      */
-    public BeginNode trueSuccessor() {
+    public AbstractBeginNode trueSuccessor() {
         return trueSuccessor;
     }
 
@@ -80,16 +84,16 @@
      * 
      * @return the false successor
      */
-    public BeginNode falseSuccessor() {
+    public AbstractBeginNode falseSuccessor() {
         return falseSuccessor;
     }
 
-    public void setTrueSuccessor(BeginNode node) {
+    public void setTrueSuccessor(AbstractBeginNode node) {
         updatePredecessor(trueSuccessor, node);
         trueSuccessor = node;
     }
 
-    public void setFalseSuccessor(BeginNode node) {
+    public void setFalseSuccessor(AbstractBeginNode node) {
         updatePredecessor(falseSuccessor, node);
         falseSuccessor = node;
     }
@@ -100,28 +104,30 @@
      * @param istrue {@code true} if the true successor is requested, {@code false} otherwise
      * @return the corresponding successor
      */
-    public BeginNode successor(boolean istrue) {
+    public AbstractBeginNode successor(boolean istrue) {
         return istrue ? trueSuccessor : falseSuccessor;
     }
 
     @Override
-    public Negatable negate() {
-        BeginNode trueSucc = trueSuccessor();
-        BeginNode falseSucc = falseSuccessor();
+    public Negatable negate(LogicNode cond) {
+        assert cond == condition();
+        AbstractBeginNode trueSucc = trueSuccessor();
+        AbstractBeginNode falseSucc = falseSuccessor();
         setTrueSuccessor(null);
         setFalseSuccessor(null);
         setTrueSuccessor(falseSucc);
         setFalseSuccessor(trueSucc);
-        trueSuccessorProbability = 1 - trueSuccessorProbability;
+        setTrueSuccessorProbability(1 - trueSuccessorProbability);
         return this;
     }
 
     public void setTrueSuccessorProbability(double prob) {
-        trueSuccessorProbability = prob;
+        assert prob >= -0.000000001 && prob <= 1.000000001 : "Probability out of bounds: " + prob;
+        trueSuccessorProbability = Math.min(1.0, Math.max(0.0, prob));
     }
 
     @Override
-    public double probability(BeginNode successor) {
+    public double probability(AbstractBeginNode successor) {
         return successor == trueSuccessor ? trueSuccessorProbability : 1 - trueSuccessorProbability;
     }
 
@@ -145,35 +151,193 @@
             if (c.getValue()) {
                 tool.deleteBranch(falseSuccessor());
                 tool.addToWorkList(trueSuccessor());
-                ((StructuredGraph) graph()).removeSplit(this, trueSuccessor());
+                graph().removeSplit(this, trueSuccessor());
+                return;
             } else {
                 tool.deleteBranch(trueSuccessor());
                 tool.addToWorkList(falseSuccessor());
-                ((StructuredGraph) graph()).removeSplit(this, falseSuccessor());
+                graph().removeSplit(this, falseSuccessor());
+                return;
+            }
+        } else if (trueSuccessor().usages().isEmpty() && falseSuccessor().usages().isEmpty()) {
+
+            if (removeOrMaterializeIf(tool)) {
+                return;
             }
-        } else if (trueSuccessor().guards().isEmpty() && falseSuccessor().guards().isEmpty()) {
-            if (!removeOrMaterializeIf(tool)) {
-                removeIntermediateMaterialization(tool);
+        }
+
+        if (removeIntermediateMaterialization(tool)) {
+            return;
+        }
+
+        if (falseSuccessor().usages().isEmpty() && (!(falseSuccessor() instanceof LoopExitNode)) && falseSuccessor().next() instanceof IfNode) {
+            AbstractBeginNode intermediateBegin = falseSuccessor();
+            IfNode nextIf = (IfNode) intermediateBegin.next();
+            double probabilityB = (1.0 - this.trueSuccessorProbability) * nextIf.trueSuccessorProbability;
+            if (this.trueSuccessorProbability < probabilityB) {
+                // Reordering of those two if statements is beneficial from the point of view of
+                // their probabilities.
+                if (prepareForSwap(tool.runtime(), condition(), nextIf.condition(), this.trueSuccessorProbability, probabilityB)) {
+                    // Reording is allowed from (if1 => begin => if2) to (if2 => begin => if1).
+                    assert intermediateBegin.next() == nextIf;
+                    AbstractBeginNode bothFalseBegin = nextIf.falseSuccessor();
+                    nextIf.setFalseSuccessor(null);
+                    intermediateBegin.setNext(null);
+                    this.setFalseSuccessor(null);
+
+                    this.replaceAtPredecessor(nextIf);
+                    nextIf.setFalseSuccessor(intermediateBegin);
+                    intermediateBegin.setNext(this);
+                    this.setFalseSuccessor(bothFalseBegin);
+                    nextIf.setTrueSuccessorProbability(probabilityB);
+                    if (probabilityB == 1.0) {
+                        this.setTrueSuccessorProbability(0.0);
+                    } else {
+                        double newProbability = this.trueSuccessorProbability / (1.0 - probabilityB);
+                        this.setTrueSuccessorProbability(Math.min(1.0, newProbability));
+                    }
+                    return;
+                }
             }
         }
     }
 
+    private static boolean prepareForSwap(MetaAccessProvider runtime, LogicNode a, LogicNode b, double probabilityA, double probabilityB) {
+        if (a instanceof InstanceOfNode) {
+            InstanceOfNode instanceOfA = (InstanceOfNode) a;
+            if (b instanceof IsNullNode) {
+                IsNullNode isNullNode = (IsNullNode) b;
+                if (isNullNode.object() == instanceOfA.object()) {
+                    if (instanceOfA.profile() != null && instanceOfA.profile().getNullSeen() != TriState.FALSE) {
+                        instanceOfA.setProfile(new JavaTypeProfile(TriState.FALSE, instanceOfA.profile().getNotRecordedProbability(), instanceOfA.profile().getTypes()));
+                    }
+                    Debug.log("Can swap instanceof and isnull if");
+                    return true;
+                }
+            } else if (b instanceof InstanceOfNode) {
+                InstanceOfNode instanceOfB = (InstanceOfNode) b;
+                if (instanceOfA.object() == instanceOfB.object() && !instanceOfA.type().isAssignableFrom(instanceOfB.type()) && !instanceOfB.type().isAssignableFrom(instanceOfA.type())) {
+                    // Two instanceof on the same value with mutually exclusive types.
+                    JavaTypeProfile profileA = instanceOfA.profile();
+                    JavaTypeProfile profileB = instanceOfB.profile();
+
+                    Debug.log("Can swap instanceof for types %s and %s", instanceOfA.type(), instanceOfB.type());
+                    JavaTypeProfile newProfile = null;
+                    if (profileA != null && profileB != null) {
+                        double remainder = 1.0;
+                        ArrayList<ProfiledType> profiledTypes = new ArrayList<>();
+                        for (ProfiledType type : profileB.getTypes()) {
+                            if (instanceOfB.type().isAssignableFrom(type.getType())) {
+                                // Do not add to profile.
+                            } else {
+                                ProfiledType newType = new ProfiledType(type.getType(), Math.min(1.0, type.getProbability() * (1.0 - probabilityA) / (1.0 - probabilityB)));
+                                profiledTypes.add(newType);
+                                remainder -= newType.getProbability();
+                            }
+                        }
+
+                        for (ProfiledType type : profileA.getTypes()) {
+                            if (instanceOfA.type().isAssignableFrom(type.getType())) {
+                                ProfiledType newType = new ProfiledType(type.getType(), Math.min(1.0, type.getProbability() / (1.0 - probabilityB)));
+                                profiledTypes.add(newType);
+                                remainder -= newType.getProbability();
+                            }
+                        }
+                        Collections.sort(profiledTypes);
+
+                        if (remainder < 0.0) {
+                            // Can happen due to round-off errors.
+                            remainder = 0.0;
+                        }
+                        newProfile = new JavaTypeProfile(profileB.getNullSeen(), remainder, profiledTypes.toArray(new ProfiledType[profiledTypes.size()]));
+                        Debug.log("First profile: %s", profileA);
+                        Debug.log("Original second profile: %s", profileB);
+                        Debug.log("New second profile: %s", newProfile);
+                    }
+                    instanceOfB.setProfile(profileA);
+                    instanceOfA.setProfile(newProfile);
+                    return true;
+                }
+            }
+        } else if (a instanceof CompareNode) {
+            CompareNode compareA = (CompareNode) a;
+            Condition conditionA = compareA.condition();
+            if (compareA.unorderedIsTrue()) {
+                return false;
+            }
+            if (b instanceof CompareNode) {
+                CompareNode compareB = (CompareNode) b;
+                if (compareA == compareB) {
+                    Debug.log("Same conditions => do not swap and leave the work for global value numbering.");
+                    return false;
+                }
+                if (compareB.unorderedIsTrue()) {
+                    return false;
+                }
+                Condition comparableCondition = null;
+                Condition conditionB = compareB.condition();
+                if (compareB.x() == compareA.x() && compareB.y() == compareA.y()) {
+                    comparableCondition = conditionB;
+                } else if (compareB.x() == compareA.y() && compareB.y() == compareA.x()) {
+                    comparableCondition = conditionB.mirror();
+                }
+
+                if (comparableCondition != null) {
+                    Condition combined = conditionA.join(comparableCondition);
+                    if (combined == null) {
+                        // The two conditions are disjoint => can reorder.
+                        Debug.log("Can swap disjoint coditions on same values: %s and %s", conditionA, comparableCondition);
+                        return true;
+                    }
+                } else if (conditionA == Condition.EQ && conditionB == Condition.EQ) {
+                    boolean canSwap = false;
+                    if ((compareA.x() == compareB.x() && valuesDistinct(runtime, compareA.y(), compareB.y()))) {
+                        canSwap = true;
+                    } else if ((compareA.x() == compareB.y() && valuesDistinct(runtime, compareA.y(), compareB.x()))) {
+                        canSwap = true;
+                    } else if ((compareA.y() == compareB.x() && valuesDistinct(runtime, compareA.x(), compareB.y()))) {
+                        canSwap = true;
+                    } else if ((compareA.y() == compareB.y() && valuesDistinct(runtime, compareA.x(), compareB.x()))) {
+                        canSwap = true;
+                    }
+
+                    if (canSwap) {
+                        Debug.log("Can swap equality condition with one shared and one disjoint value.");
+                        return true;
+                    }
+                }
+            }
+        }
+
+        return false;
+    }
+
+    private static boolean valuesDistinct(MetaAccessProvider runtime, ValueNode a, ValueNode b) {
+        if (a.isConstant() && b.isConstant()) {
+            return !runtime.constantEquals(a.asConstant(), b.asConstant());
+        }
+
+        Stamp stampA = a.stamp();
+        Stamp stampB = b.stamp();
+        return stampA.alwaysDistinct(stampB);
+    }
+
     /**
      * Tries to remove an empty if construct or replace an if construct with a materialization.
      * 
      * @return true if a transformation was made, false otherwise
      */
     private boolean removeOrMaterializeIf(SimplifierTool tool) {
-        if (trueSuccessor().next() instanceof EndNode && falseSuccessor().next() instanceof EndNode) {
-            EndNode trueEnd = (EndNode) trueSuccessor().next();
-            EndNode falseEnd = (EndNode) falseSuccessor().next();
+        if (trueSuccessor().next() instanceof AbstractEndNode && falseSuccessor().next() instanceof AbstractEndNode) {
+            AbstractEndNode trueEnd = (AbstractEndNode) trueSuccessor().next();
+            AbstractEndNode falseEnd = (AbstractEndNode) falseSuccessor().next();
             MergeNode merge = trueEnd.merge();
             if (merge == falseEnd.merge() && merge.forwardEndCount() == 2 && trueSuccessor().anchored().isEmpty() && falseSuccessor().anchored().isEmpty()) {
                 Iterator<PhiNode> phis = merge.phis().iterator();
                 if (!phis.hasNext()) {
                     // empty if construct with no phis: remove it
                     removeEmptyIf(tool);
-                    return false;
+                    return true;
                 } else {
                     PhiNode singlePhi = phis.next();
                     if (!phis.hasNext()) {
@@ -190,7 +354,7 @@
                         }
                         if (trueValue.isConstant() && falseValue.isConstant()) {
                             ConditionalNode materialize = graph().unique(new ConditionalNode(condition(), trueValue, falseValue));
-                            ((StructuredGraph) graph()).replaceFloating(singlePhi, materialize);
+                            graph().replaceFloating(singlePhi, materialize);
                             removeEmptyIf(tool);
                             return true;
                         }
@@ -260,11 +424,12 @@
             return false;
         }
 
-        MergeNode merge = (MergeNode) predecessor();
-        if (!merge.anchored().isEmpty()) {
+        if (predecessor() instanceof LoopBeginNode) {
             return false;
         }
 
+        MergeNode merge = (MergeNode) predecessor();
+
         // Only consider merges with a single usage that is both a phi and an operand of the
         // comparison
         NodeIterable<Node> mergeUsages = merge.usages();
@@ -288,11 +453,8 @@
             }
         }
 
-        List<EndNode> mergePredecessors = merge.cfgPredecessors().snapshot();
-        if (phi.valueCount() != merge.forwardEndCount()) {
-            // Handles a loop begin merge
-            return false;
-        }
+        List<AbstractEndNode> mergePredecessors = merge.cfgPredecessors().snapshot();
+        assert phi.valueCount() == merge.forwardEndCount();
 
         Constant[] xs = constantValues(compare.x(), merge);
         Constant[] ys = constantValues(compare.y(), merge);
@@ -300,19 +462,24 @@
             return false;
         }
 
-        List<EndNode> falseEnds = new ArrayList<>(mergePredecessors.size());
-        List<EndNode> trueEnds = new ArrayList<>(mergePredecessors.size());
-        Map<EndNode, ValueNode> phiValues = new HashMap<>(mergePredecessors.size());
+        // Sanity check that both ends are not followed by a merge without frame state.
+        if (!checkFrameState(trueSuccessor()) && !checkFrameState(falseSuccessor())) {
+            return false;
+        }
 
-        BeginNode oldFalseSuccessor = falseSuccessor();
-        BeginNode oldTrueSuccessor = trueSuccessor();
+        List<AbstractEndNode> falseEnds = new ArrayList<>(mergePredecessors.size());
+        List<AbstractEndNode> trueEnds = new ArrayList<>(mergePredecessors.size());
+        Map<AbstractEndNode, ValueNode> phiValues = new HashMap<>(mergePredecessors.size());
+
+        AbstractBeginNode oldFalseSuccessor = falseSuccessor();
+        AbstractBeginNode oldTrueSuccessor = trueSuccessor();
 
         setFalseSuccessor(null);
         setTrueSuccessor(null);
 
-        Iterator<EndNode> ends = mergePredecessors.iterator();
+        Iterator<AbstractEndNode> ends = mergePredecessors.iterator();
         for (int i = 0; i < xs.length; i++) {
-            EndNode end = ends.next();
+            AbstractEndNode end = ends.next();
             phiValues.put(end, phi.valueAt(end));
             if (compare.condition().foldCondition(xs[i], ys[i], tool.runtime(), compare.unorderedIsTrue())) {
                 trueEnds.add(end);
@@ -336,6 +503,45 @@
         return true;
     }
 
+    private static boolean checkFrameState(FixedNode start) {
+        FixedNode node = start;
+        while (true) {
+            if (node instanceof MergeNode) {
+                MergeNode mergeNode = (MergeNode) node;
+                if (mergeNode.stateAfter() == null) {
+                    return false;
+                } else {
+                    return true;
+                }
+            } else if (node instanceof StateSplit) {
+                StateSplit stateSplitNode = (StateSplit) node;
+                if (stateSplitNode.stateAfter() != null) {
+                    return true;
+                }
+            }
+
+            if (node instanceof ControlSplitNode) {
+                ControlSplitNode controlSplitNode = (ControlSplitNode) node;
+                for (Node succ : controlSplitNode.cfgSuccessors()) {
+                    if (checkFrameState((FixedNode) succ)) {
+                        return true;
+                    }
+                }
+                return false;
+            } else if (node instanceof FixedWithNextNode) {
+                FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) node;
+                node = fixedWithNextNode.next();
+            } else if (node instanceof AbstractEndNode) {
+                AbstractEndNode endNode = (AbstractEndNode) node;
+                node = endNode.merge();
+            } else if (node instanceof ControlSinkNode) {
+                return true;
+            } else {
+                return false;
+            }
+        }
+    }
+
     /**
      * Connects a set of ends to a given successor, inserting a merge node if there is more than one
      * end. If {@code ends} is empty, then {@code successor} is
@@ -345,12 +551,12 @@
      * @param oldMerge the merge being removed
      * @param phiValues the values of the phi at the merge, keyed by the merge ends
      */
-    private void connectEnds(List<EndNode> ends, Map<EndNode, ValueNode> phiValues, BeginNode successor, MergeNode oldMerge, SimplifierTool tool) {
+    private void connectEnds(List<AbstractEndNode> ends, Map<AbstractEndNode, ValueNode> phiValues, AbstractBeginNode successor, MergeNode oldMerge, SimplifierTool tool) {
         if (ends.isEmpty()) {
             GraphUtil.killCFG(successor);
         } else {
             if (ends.size() == 1) {
-                EndNode end = ends.get(0);
+                AbstractEndNode end = ends.get(0);
                 ((FixedWithNextNode) end.predecessor()).setNext(successor);
                 oldMerge.removeEnd(end);
                 GraphUtil.killCFG(end);
@@ -361,7 +567,7 @@
                 PhiNode oldPhi = (PhiNode) oldMerge.usages().first();
                 PhiNode newPhi = graph().add(new PhiNode(oldPhi.stamp(), newMerge));
 
-                for (EndNode end : ends) {
+                for (AbstractEndNode end : ends) {
                     newPhi.addInput(phiValues.get(end));
                     newMerge.addForwardEnd(end);
                 }
@@ -413,12 +619,12 @@
     }
 
     private void removeEmptyIf(SimplifierTool tool) {
-        BeginNode originalTrueSuccessor = trueSuccessor();
-        BeginNode originalFalseSuccessor = falseSuccessor();
-        assert originalTrueSuccessor.next() instanceof EndNode && originalFalseSuccessor.next() instanceof EndNode;
+        AbstractBeginNode originalTrueSuccessor = trueSuccessor();
+        AbstractBeginNode originalFalseSuccessor = falseSuccessor();
+        assert originalTrueSuccessor.next() instanceof AbstractEndNode && originalFalseSuccessor.next() instanceof AbstractEndNode;
 
-        EndNode trueEnd = (EndNode) originalTrueSuccessor.next();
-        EndNode falseEnd = (EndNode) originalFalseSuccessor.next();
+        AbstractEndNode trueEnd = (AbstractEndNode) originalTrueSuccessor.next();
+        AbstractEndNode falseEnd = (AbstractEndNode) originalFalseSuccessor.next();
         assert trueEnd.merge() == falseEnd.merge();
 
         FixedWithNextNode pred = (FixedWithNextNode) predecessor();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/Invoke.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/Invoke.java	Mon May 13 17:11:31 2013 +0200
@@ -23,9 +23,10 @@
 package com.oracle.graal.nodes;
 
 import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 
-public interface Invoke extends StateSplit, Lowerable, DeoptimizingNode {
+public interface Invoke extends StateSplit, Lowerable, DeoptimizingNode, GuardedNode {
 
     FixedNode next();
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java	Mon May 13 17:11:31 2013 +0200
@@ -27,6 +27,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.util.*;
 
@@ -38,6 +39,7 @@
 
     @Input private final CallTargetNode callTarget;
     @Input private FrameState deoptState;
+    @Input private GuardingNode guard;
     private final int bci;
     private boolean polymorphic;
     private boolean useForInlining;
@@ -90,8 +92,8 @@
     }
 
     @Override
-    public Object[] getLocationIdentities() {
-        return new Object[]{LocationNode.ANY_LOCATION};
+    public LocationIdentity[] getLocationIdentities() {
+        return new LocationIdentity[]{LocationNode.ANY_LOCATION};
     }
 
     @Override
@@ -145,14 +147,14 @@
             stateSplit.setStateAfter(stateAfter);
         }
         if (node instanceof FixedWithNextNode) {
-            ((StructuredGraph) graph()).replaceFixedWithFixed(this, (FixedWithNextNode) node);
-        } else if (node instanceof DeoptimizeNode) {
+            graph().replaceFixedWithFixed(this, (FixedWithNextNode) node);
+        } else if (node instanceof ControlSinkNode) {
             this.replaceAtPredecessor(node);
             this.replaceAtUsages(null);
             GraphUtil.killCFG(this);
             return;
         } else {
-            ((StructuredGraph) graph()).replaceFixed(this, node);
+            graph().replaceFixed(this, node);
         }
         call.safeDelete();
         if (stateAfter.usages().isEmpty()) {
@@ -189,4 +191,15 @@
     public boolean isCallSiteDeoptimization() {
         return true;
     }
+
+    @Override
+    public GuardingNode getGuard() {
+        return guard;
+    }
+
+    @Override
+    public void setGuard(GuardingNode guard) {
+        updateUsages(this.guard == null ? null : this.guard.asNode(), guard == null ? null : guard.asNode());
+        this.guard = guard;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Mon May 13 17:11:31 2013 +0200
@@ -27,6 +27,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.util.*;
@@ -34,11 +35,12 @@
 @NodeInfo(nameTemplate = "Invoke!#{p#targetMethod/s}")
 public class InvokeWithExceptionNode extends ControlSplitNode implements Node.IterableNodeType, Invoke, MemoryCheckpoint, LIRLowerable {
 
-    @Successor private BeginNode next;
+    @Successor private AbstractBeginNode next;
     @Successor private DispatchBeginNode exceptionEdge;
     @Input private final CallTargetNode callTarget;
     @Input private FrameState deoptState;
     @Input private FrameState stateAfter;
+    @Input private GuardingNode guard;
     private final int bci;
     private boolean polymorphic;
     private boolean useForInlining;
@@ -61,11 +63,11 @@
         exceptionEdge = x;
     }
 
-    public BeginNode next() {
+    public AbstractBeginNode next() {
         return next;
     }
 
-    public void setNext(BeginNode x) {
+    public void setNext(AbstractBeginNode x) {
         updatePredecessor(next, x);
         next = x;
     }
@@ -121,7 +123,7 @@
     @Override
     public void setNext(FixedNode x) {
         if (x != null) {
-            this.setNext(BeginNode.begin(x));
+            this.setNext(AbstractBeginNode.begin(x));
         } else {
             this.setNext(null);
         }
@@ -151,8 +153,8 @@
     }
 
     @Override
-    public Object[] getLocationIdentities() {
-        return new Object[]{LocationNode.ANY_LOCATION};
+    public LocationIdentity[] getLocationIdentities() {
+        return new LocationIdentity[]{LocationNode.ANY_LOCATION};
     }
 
     public FrameState stateDuring() {
@@ -170,7 +172,7 @@
     }
 
     public void killExceptionEdge() {
-        BeginNode edge = exceptionEdge();
+        AbstractBeginNode edge = exceptionEdge();
         setExceptionEdge(null);
         GraphUtil.killCFG(edge);
     }
@@ -187,14 +189,14 @@
         }
         if (node == null) {
             assert kind() == Kind.Void && usages().isEmpty();
-            ((StructuredGraph) graph()).removeSplit(this, next());
-        } else if (node instanceof DeoptimizeNode) {
+            graph().removeSplit(this, next());
+        } else if (node instanceof ControlSinkNode) {
             this.replaceAtPredecessor(node);
             this.replaceAtUsages(null);
             GraphUtil.killCFG(this);
             return;
         } else {
-            ((StructuredGraph) graph()).replaceSplit(this, node, next());
+            graph().replaceSplit(this, node, next());
         }
         call.safeDelete();
         if (state.usages().isEmpty()) {
@@ -205,7 +207,7 @@
     private static final double EXCEPTION_PROBA = 1e-5;
 
     @Override
-    public double probability(BeginNode successor) {
+    public double probability(AbstractBeginNode successor) {
         return successor == next ? 1 - EXCEPTION_PROBA : EXCEPTION_PROBA;
     }
 
@@ -238,4 +240,15 @@
     public boolean isCallSiteDeoptimization() {
         return true;
     }
+
+    @Override
+    public GuardingNode getGuard() {
+        return guard;
+    }
+
+    @Override
+    public void setGuard(GuardingNode guard) {
+        updateUsages(this.guard == null ? null : this.guard.asNode(), guard == null ? null : guard.asNode());
+        this.guard = guard;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LocalNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LocalNode.java	Mon May 13 17:11:31 2013 +0200
@@ -23,37 +23,15 @@
 package com.oracle.graal.nodes;
 
 import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.type.*;
 
 /**
  * The {@code Local} instruction is a placeholder for an incoming argument to a function call.
  */
 @NodeInfo(nameTemplate = "Local({p#index})")
-public final class LocalNode extends FloatingNode implements Node.IterableNodeType {
-
-    private final int index;
+public final class LocalNode extends AbstractLocalNode implements Node.IterableNodeType {
 
     public LocalNode(int index, Stamp stamp) {
-        super(stamp);
-        this.index = index;
-    }
-
-    /**
-     * Gets the index of this local in the array of parameters. This is NOT the JVM local index.
-     * 
-     * @return the index
-     */
-    public int index() {
-        return index;
-    }
-
-    @Override
-    public String toString(Verbosity verbosity) {
-        if (verbosity == Verbosity.Name) {
-            return super.toString(Verbosity.Name) + "(" + index + ")";
-        } else {
-            return super.toString(verbosity);
-        }
+        super(index, stamp);
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicBinaryNode.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,72 @@
+/*
+ * 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.nodes;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.spi.*;
+
+public abstract class LogicBinaryNode extends LogicNode implements Negatable, Node.IterableNodeType {
+
+    @Input private LogicNode x;
+    @Input private LogicNode y;
+    private boolean xNegated;
+    private boolean yNegated;
+
+    public LogicBinaryNode(LogicNode x, LogicNode y) {
+        this(x, false, y, false);
+    }
+
+    public LogicBinaryNode(LogicNode x, boolean xNegated, LogicNode y, boolean yNegated) {
+        this.x = x;
+        this.xNegated = xNegated;
+        this.y = y;
+        this.yNegated = yNegated;
+    }
+
+    public LogicNode getX() {
+        return x;
+    }
+
+    public LogicNode getY() {
+        return y;
+    }
+
+    public boolean isXNegated() {
+        return xNegated;
+    }
+
+    public boolean isYNegated() {
+        return yNegated;
+    }
+
+    @Override
+    public Negatable negate(LogicNode condition) {
+        if (condition == x) {
+            xNegated = !xNegated;
+        }
+        if (condition == y) {
+            yNegated = !yNegated;
+        }
+        return this;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicConjunctionNode.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,70 @@
+/*
+ * 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.nodes;
+
+import com.oracle.graal.nodes.spi.*;
+
+/**
+ * This node is true if {@link #getX() x} <b>and</b> {@link #getY() y} are true.
+ * 
+ */
+public class LogicConjunctionNode extends LogicBinaryNode implements Canonicalizable {
+
+    public LogicConjunctionNode(LogicNode x, LogicNode y) {
+        this(x, false, y, false);
+    }
+
+    public LogicConjunctionNode(LogicNode x, boolean xNegated, LogicNode y, boolean yNegated) {
+        super(x, xNegated, y, yNegated);
+    }
+
+    @Override
+    public LogicNode canonical(CanonicalizerTool tool) {
+        LogicNode x = getX();
+        LogicNode y = getY();
+        if (x == y) {
+            return x;
+        }
+        if (x instanceof LogicConstantNode) {
+            if (((LogicConstantNode) x).getValue() ^ isXNegated()) {
+                if (isYNegated()) {
+                    negateUsages();
+                }
+                return y;
+            } else {
+                return LogicConstantNode.contradiction(graph());
+            }
+        }
+        if (y instanceof LogicConstantNode) {
+            if (((LogicConstantNode) y).getValue() ^ isYNegated()) {
+                if (isXNegated()) {
+                    negateUsages();
+                }
+                return x;
+            } else {
+                return LogicConstantNode.contradiction(graph());
+            }
+        }
+        return this;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicDisjunctionNode.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,71 @@
+/*
+ * 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.nodes;
+
+import com.oracle.graal.nodes.spi.*;
+
+/**
+ * This node is true if {@link #getX() x} <b>or</b> {@link #getY() y} are true.
+ * 
+ */
+public class LogicDisjunctionNode extends LogicBinaryNode implements Canonicalizable {
+
+    public LogicDisjunctionNode(LogicNode x, LogicNode y) {
+        this(x, false, y, false);
+    }
+
+    public LogicDisjunctionNode(LogicNode x, boolean xNegated, LogicNode y, boolean yNegated) {
+        super(x, xNegated, y, yNegated);
+    }
+
+    @Override
+    public LogicNode canonical(CanonicalizerTool tool) {
+        LogicNode x = getX();
+        LogicNode y = getY();
+        if (x == y) {
+            return x;
+        }
+        if (x instanceof LogicConstantNode) {
+            if (((LogicConstantNode) x).getValue() ^ isXNegated()) {
+                return LogicConstantNode.tautology(graph());
+            } else {
+                if (isYNegated()) {
+                    negateUsages();
+                }
+                return y;
+            }
+        }
+        if (y instanceof LogicConstantNode) {
+            if (((LogicConstantNode) y).getValue() ^ isYNegated()) {
+                return LogicConstantNode.tautology(graph());
+            } else {
+                if (isXNegated()) {
+                    negateUsages();
+                }
+                return x;
+            }
+        }
+        return this;
+    }
+
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicNode.java	Mon May 13 17:11:31 2013 +0200
@@ -29,8 +29,8 @@
 
 public abstract class LogicNode extends FloatingNode {
 
-    public LogicNode(ValueNode... dependencies) {
-        super(StampFactory.condition(), dependencies);
+    public LogicNode() {
+        super(StampFactory.condition());
     }
 
     /**
@@ -40,7 +40,7 @@
     public void negateUsages() {
         for (Node n : usages().snapshot()) {
             assert n instanceof Negatable;
-            ((Negatable) n).negate();
+            ((Negatable) n).negate(this);
         }
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java	Mon May 13 17:11:31 2013 +0200
@@ -28,6 +28,7 @@
 
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.iterators.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 
 public class LoopBeginNode extends MergeNode implements Node.IterableNodeType, LIRLowerable {
@@ -35,6 +36,7 @@
     private double loopFrequency;
     private int nextEndIndex;
     private int unswitches;
+    @Input private GuardingNode overflowGuard;
 
     public LoopBeginNode() {
         loopFrequency = 1;
@@ -87,7 +89,7 @@
         return snapshot;
     }
 
-    public EndNode forwardEnd() {
+    public AbstractEndNode forwardEnd() {
         assert forwardEndCount() == 1;
         return forwardEndAt(0);
     }
@@ -98,7 +100,7 @@
     }
 
     @Override
-    protected void deleteEnd(EndNode end) {
+    protected void deleteEnd(AbstractEndNode end) {
         if (end instanceof LoopEndNode) {
             LoopEndNode loopEnd = (LoopEndNode) end;
             loopEnd.setLoopBegin(null);
@@ -122,7 +124,7 @@
     }
 
     @Override
-    public int phiPredecessorIndex(EndNode pred) {
+    public int phiPredecessorIndex(AbstractEndNode pred) {
         if (pred instanceof LoopEndNode) {
             LoopEndNode loopEnd = (LoopEndNode) pred;
             if (loopEnd.loopBegin() == this) {
@@ -136,7 +138,7 @@
     }
 
     @Override
-    public EndNode phiPredecessorAt(int index) {
+    public AbstractEndNode phiPredecessorAt(int index) {
         if (index < forwardEndCount()) {
             return forwardEndAt(index);
         }
@@ -173,15 +175,23 @@
         // nothing yet
     }
 
-    public boolean isLoopExit(BeginNode begin) {
+    public boolean isLoopExit(AbstractBeginNode begin) {
         return begin instanceof LoopExitNode && ((LoopExitNode) begin).loopBegin() == this;
     }
 
     public void removeExits() {
-        StructuredGraph graph = (StructuredGraph) graph();
         for (LoopExitNode loopexit : loopExits().snapshot()) {
             loopexit.removeProxies();
-            graph.replaceFixedWithFixed(loopexit, graph.add(new BeginNode()));
+            graph().replaceFixedWithFixed(loopexit, graph().add(new BeginNode()));
         }
     }
+
+    public GuardingNode getOverflowGuard() {
+        return overflowGuard;
+    }
+
+    public void setOverflowGuard(GuardingNode overflowGuard) {
+        updateUsages(this.overflowGuard == null ? null : this.overflowGuard.asNode(), overflowGuard == null ? null : overflowGuard.asNode());
+        this.overflowGuard = overflowGuard;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopEndNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopEndNode.java	Mon May 13 17:11:31 2013 +0200
@@ -27,7 +27,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.spi.*;
 
-public final class LoopEndNode extends EndNode {
+public final class LoopEndNode extends AbstractEndNode {
 
     @Input(notDataflow = true) private LoopBeginNode loopBegin;
     private boolean canSafepoint;
@@ -60,9 +60,6 @@
     }
 
     public boolean canSafepoint() {
-        if (!canSafepoint) {
-            return canSafepoint;
-        }
         return canSafepoint;
     }
 
@@ -81,7 +78,7 @@
 
     /**
      * Returns the 0-based index of this loop end. This is <b>not</b> the index into {@link PhiNode}
-     * values at the loop begin. Use {@link MergeNode#phiPredecessorIndex(EndNode)} for this
+     * values at the loop begin. Use {@link MergeNode#phiPredecessorIndex(AbstractEndNode)} for this
      * purpose.
      * 
      * @return The 0-based index of this loop end.
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java	Mon May 13 17:11:31 2013 +0200
@@ -35,18 +35,18 @@
  */
 public class MergeNode extends BeginStateSplitNode implements Node.IterableNodeType, LIRLowerable {
 
-    @Input(notDataflow = true) private final NodeInputList<EndNode> ends = new NodeInputList<>(this);
+    @Input(notDataflow = true) private final NodeInputList<AbstractEndNode> ends = new NodeInputList<>(this);
 
     @Override
     public void generate(LIRGeneratorTool gen) {
         gen.visitMerge(this);
     }
 
-    public int forwardEndIndex(EndNode end) {
+    public int forwardEndIndex(AbstractEndNode end) {
         return ends.indexOf(end);
     }
 
-    public void addForwardEnd(EndNode end) {
+    public void addForwardEnd(AbstractEndNode end) {
         ends.add(end);
     }
 
@@ -54,12 +54,12 @@
         return ends.size();
     }
 
-    public EndNode forwardEndAt(int index) {
+    public AbstractEndNode forwardEndAt(int index) {
         return ends.get(index);
     }
 
     @Override
-    public NodeIterable<EndNode> cfgPredecessors() {
+    public NodeIterable<AbstractEndNode> cfgPredecessors() {
         return ends;
     }
 
@@ -79,7 +79,7 @@
      * 
      * @param pred the end to remove
      */
-    public void removeEnd(EndNode pred) {
+    public void removeEnd(AbstractEndNode pred) {
         int predIndex = phiPredecessorIndex(pred);
         assert predIndex != -1;
         deleteEnd(pred);
@@ -95,7 +95,7 @@
         }
     }
 
-    protected void deleteEnd(EndNode end) {
+    protected void deleteEnd(AbstractEndNode end) {
         ends.remove(end);
     }
 
@@ -103,7 +103,7 @@
         ends.clear();
     }
 
-    public NodeIterable<EndNode> forwardEnds() {
+    public NodeIterable<AbstractEndNode> forwardEnds() {
         return ends;
     }
 
@@ -111,11 +111,11 @@
         return forwardEndCount();
     }
 
-    public int phiPredecessorIndex(EndNode pred) {
+    public int phiPredecessorIndex(AbstractEndNode pred) {
         return forwardEndIndex(pred);
     }
 
-    public EndNode phiPredecessorAt(int index) {
+    public AbstractEndNode phiPredecessorAt(int index) {
         return forwardEndAt(index);
     }
 
@@ -143,8 +143,8 @@
     @Override
     public void simplify(SimplifierTool tool) {
         FixedNode next = next();
-        if (next instanceof EndNode) {
-            EndNode origLoopEnd = (EndNode) next;
+        if (next instanceof AbstractEndNode) {
+            AbstractEndNode origLoopEnd = (AbstractEndNode) next;
             MergeNode merge = origLoopEnd.merge();
             if (merge instanceof LoopBeginNode && !(origLoopEnd instanceof LoopEndNode)) {
                 return;
@@ -154,6 +154,10 @@
             if (this.anchored().isNotEmpty()) {
                 return;
             }
+            if (merge.stateAfter() == null && this.stateAfter() != null) {
+                // We hold a state, but the succeeding merge does not => do not combine.
+                return;
+            }
             for (PhiNode phi : phis()) {
                 for (Node usage : phi.usages().filter(isNotA(FrameState.class))) {
                     if (!merge.isPhiAtMerge(usage)) {
@@ -163,14 +167,13 @@
             }
             Debug.log("Split %s into ends for %s.", this, merge);
             int numEnds = this.forwardEndCount();
-            StructuredGraph graph = (StructuredGraph) graph();
             for (int i = 0; i < numEnds - 1; i++) {
-                EndNode end = forwardEndAt(numEnds - 1 - i);
-                EndNode newEnd;
+                AbstractEndNode end = forwardEndAt(numEnds - 1 - i);
+                AbstractEndNode newEnd;
                 if (merge instanceof LoopBeginNode) {
-                    newEnd = graph.add(new LoopEndNode((LoopBeginNode) merge));
+                    newEnd = graph().add(new LoopEndNode((LoopBeginNode) merge));
                 } else {
-                    newEnd = graph.add(new EndNode());
+                    newEnd = graph().add(new EndNode());
                     merge.addForwardEnd(newEnd);
                 }
                 for (PhiNode phi : merge.phis()) {
@@ -189,7 +192,7 @@
                 end.safeDelete();
                 tool.addToWorkList(newEnd.predecessor()); // ?
             }
-            graph.reduceTrivialMerge(this);
+            graph().reduceTrivialMerge(this);
         }
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java	Mon May 13 17:11:31 2013 +0200
@@ -25,6 +25,7 @@
 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.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -33,7 +34,7 @@
  * variable.
  */
 @NodeInfo(nameTemplate = "{p#type/s}Phi({i#values})")
-public final class PhiNode extends FloatingNode implements Canonicalizable, Node.IterableNodeType {
+public final class PhiNode extends FloatingNode implements Canonicalizable, Node.IterableNodeType, GuardingNode {
 
     public static enum PhiType {
         Value(null), // normal value phis
@@ -159,7 +160,7 @@
         values.set(i, x);
     }
 
-    public ValueNode valueAt(EndNode pred) {
+    public ValueNode valueAt(AbstractEndNode pred) {
         return valueAt(merge().phiPredecessorIndex(pred));
     }
 
@@ -251,4 +252,9 @@
     public boolean isLoopPhi() {
         return merge() instanceof LoopBeginNode;
     }
+
+    @Override
+    public PhiNode asNode() {
+        return this;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java	Mon May 13 17:11:31 2013 +0200
@@ -22,8 +22,9 @@
  */
 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.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -31,9 +32,10 @@
  * A node that changes the type of its input, usually narrowing it. For example, a PI node refines
  * the type of a receiver during type-guarded inlining to be the type tested by the guard.
  */
-public class PiNode extends FloatingNode implements LIRLowerable, Virtualizable, Node.IterableNodeType {
+public class PiNode extends FloatingGuardedNode implements LIRLowerable, Virtualizable, Node.IterableNodeType, GuardingNode {
 
     @Input private ValueNode object;
+    @Input private FixedNode anchor;
 
     public ValueNode object() {
         return object;
@@ -44,20 +46,22 @@
         this.object = object;
     }
 
-    public PiNode(ValueNode object, Stamp stamp, ValueNode anchor) {
-        super(stamp, anchor);
-        assert anchor instanceof FixedNode;
+    public PiNode(ValueNode object, Stamp stamp, FixedNode anchor) {
+        super(stamp);
         this.object = object;
+        this.anchor = anchor;
     }
 
     @Override
     public void generate(LIRGeneratorTool generator) {
-        generator.setResult(this, generator.operand(object));
+        if (object.kind() != Kind.Void && object.kind() != Kind.Illegal) {
+            generator.setResult(this, generator.operand(object));
+        }
     }
 
     @Override
     public boolean inferStamp() {
-        if (object().objectStamp().alwaysNull() && objectStamp().nonNull()) {
+        if (stamp() instanceof ObjectStamp && object().objectStamp().alwaysNull() && objectStamp().nonNull()) {
             // a null value flowing into a nonNull PiNode should be guarded by a type/isNull guard,
             // but the
             // compiler might see this situation before the branch is deleted
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ProxyNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ProxyNode.java	Mon May 13 17:11:31 2013 +0200
@@ -37,12 +37,12 @@
 @NodeInfo(nameTemplate = "{p#type/s}Proxy")
 public class ProxyNode extends FloatingNode implements Node.IterableNodeType, ValueNumberable, Canonicalizable, Virtualizable, LIRLowerable {
 
-    @Input(notDataflow = true) private BeginNode proxyPoint;
+    @Input(notDataflow = true) private AbstractBeginNode proxyPoint;
     @Input private ValueNode value;
     private final PhiType type;
     private final Object identity;
 
-    public ProxyNode(ValueNode value, BeginNode exit, PhiType type, Object identity) {
+    public ProxyNode(ValueNode value, AbstractBeginNode exit, PhiType type, Object identity) {
         super(type == PhiType.Value ? value.stamp() : type.stamp);
         this.type = type;
         this.identity = identity;
@@ -65,7 +65,7 @@
         return value().stamp();
     }
 
-    public BeginNode proxyPoint() {
+    public AbstractBeginNode proxyPoint() {
         return proxyPoint;
     }
 
@@ -108,11 +108,11 @@
         }
     }
 
-    public static ProxyNode forValue(ValueNode value, BeginNode exit, StructuredGraph graph) {
+    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, BeginNode exit, Object location, StructuredGraph graph) {
+    public static ProxyNode forMemory(ValueNode value, AbstractBeginNode exit, Object location, StructuredGraph graph) {
         return graph.unique(new ProxyNode(value, exit, PhiType.Memory, location));
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ScheduledNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ScheduledNode.java	Mon May 13 17:11:31 2013 +0200
@@ -36,4 +36,9 @@
         updatePredecessor(scheduledNext, x);
         scheduledNext = x;
     }
+
+    @Override
+    public StructuredGraph graph() {
+        return (StructuredGraph) super.graph();
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StartNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StartNode.java	Mon May 13 17:11:31 2013 +0200
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes;
 
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity;
 
 /**
  * The start node of a graph.
@@ -30,7 +31,7 @@
 public class StartNode extends BeginStateSplitNode implements MemoryCheckpoint {
 
     @Override
-    public Object[] getLocationIdentities() {
-        return new Object[]{LocationNode.ANY_LOCATION};
+    public LocationIdentity[] getLocationIdentities() {
+        return new LocationIdentity[]{LocationNode.ANY_LOCATION};
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Mon May 13 17:11:31 2013 +0200
@@ -44,20 +44,22 @@
 
     private final Set<Long> leafGraphIds = new HashSet<>(4);
 
-    private final StartNode start;
+    private StartNode start;
     private final ResolvedJavaMethod method;
     private final long graphId;
     private final int entryBCI;
 
     /**
-     * Creates a new Graph containing a single {@link BeginNode} as the {@link #start() start} node.
+     * Creates a new Graph containing a single {@link AbstractBeginNode} as the {@link #start()
+     * start} node.
      */
     public StructuredGraph() {
         this(null, null);
     }
 
     /**
-     * Creates a new Graph containing a single {@link BeginNode} as the {@link #start() start} node.
+     * Creates a new Graph containing a single {@link AbstractBeginNode} as the {@link #start()
+     * start} node.
      */
     public StructuredGraph(String name, ResolvedJavaMethod method) {
         this(name, method, uniqueGraphIds.incrementAndGet(), INVOCATION_ENTRY_BCI);
@@ -73,7 +75,7 @@
 
     private StructuredGraph(String name, ResolvedJavaMethod method, long graphId, int entryBCI) {
         super(name);
-        this.start = add(new StartNode());
+        this.setStart(add(new StartNode()));
         this.method = method;
         this.graphId = graphId;
         this.entryBCI = entryBCI;
@@ -104,6 +106,11 @@
         return start;
     }
 
+    /**
+     * Gets the method from which this graph was built.
+     * 
+     * @return null if this method was not built from a method or the method is not available
+     */
     public ResolvedJavaMethod method() {
         return method;
     }
@@ -116,6 +123,10 @@
         return graphId;
     }
 
+    public void setStart(StartNode start) {
+        this.start = start;
+    }
+
     /**
      * @return the {@link Set} that contains the {@link #graphId()} of all graphs that were
      *         incorporated into this one (e.g. by inlining).
@@ -214,8 +225,8 @@
      */
     public void removeFixed(FixedWithNextNode node) {
         assert node != null;
-        if (node instanceof BeginNode) {
-            ((BeginNode) node).prepareDelete();
+        if (node instanceof AbstractBeginNode) {
+            ((AbstractBeginNode) node).prepareDelete();
         }
         assert node.usages().isEmpty() : node + " " + node.usages();
         FixedNode next = node.next();
@@ -240,6 +251,9 @@
         node.setNext(null);
         replacement.setNext(next);
         node.replaceAndDelete(replacement);
+        if (node == start) {
+            setStart((StartNode) replacement);
+        }
     }
 
     public void replaceFixedWithFloating(FixedWithNextNode node, FloatingNode replacement) {
@@ -251,7 +265,7 @@
         node.safeDelete();
     }
 
-    public void removeSplit(ControlSplitNode node, BeginNode survivingSuccessor) {
+    public void removeSplit(ControlSplitNode node, AbstractBeginNode survivingSuccessor) {
         assert node != null;
         assert node.usages().isEmpty();
         assert survivingSuccessor != null;
@@ -260,7 +274,7 @@
         node.safeDelete();
     }
 
-    public void removeSplitPropagate(ControlSplitNode node, BeginNode survivingSuccessor) {
+    public void removeSplitPropagate(ControlSplitNode node, AbstractBeginNode survivingSuccessor) {
         assert node != null;
         assert node.usages().isEmpty();
         assert survivingSuccessor != null;
@@ -271,13 +285,13 @@
         for (Node successor : snapshot) {
             if (successor != null && successor.isAlive()) {
                 if (successor != survivingSuccessor) {
-                    GraphUtil.killCFG((BeginNode) successor);
+                    GraphUtil.killCFG((AbstractBeginNode) successor);
                 }
             }
         }
     }
 
-    public void replaceSplit(ControlSplitNode node, Node replacement, BeginNode survivingSuccessor) {
+    public void replaceSplit(ControlSplitNode node, Node replacement, AbstractBeginNode survivingSuccessor) {
         if (replacement instanceof FixedWithNextNode) {
             replaceSplitWithFixed(node, (FixedWithNextNode) replacement, survivingSuccessor);
         } else {
@@ -287,7 +301,7 @@
         }
     }
 
-    public void replaceSplitWithFixed(ControlSplitNode node, FixedWithNextNode replacement, BeginNode survivingSuccessor) {
+    public void replaceSplitWithFixed(ControlSplitNode node, FixedWithNextNode replacement, AbstractBeginNode survivingSuccessor) {
         assert node != null && replacement != null && node.isAlive() && replacement.isAlive() : "cannot replace " + node + " with " + replacement;
         assert survivingSuccessor != null;
         node.clearSuccessors();
@@ -295,7 +309,7 @@
         node.replaceAndDelete(replacement);
     }
 
-    public void replaceSplitWithFloating(ControlSplitNode node, FloatingNode replacement, BeginNode survivingSuccessor) {
+    public void replaceSplitWithFloating(ControlSplitNode node, FloatingNode replacement, AbstractBeginNode survivingSuccessor) {
         assert node != null && replacement != null && node.isAlive() && replacement.isAlive() : "cannot replace " + node + " with " + replacement;
         assert survivingSuccessor != null;
         node.clearSuccessors();
@@ -348,7 +362,7 @@
         if (merge instanceof LoopBeginNode) {
             ((LoopBeginNode) merge).removeExits();
         }
-        EndNode singleEnd = merge.forwardEndAt(0);
+        AbstractEndNode singleEnd = merge.forwardEndAt(0);
         FixedNode sux = merge.next();
         FrameState stateAfter = merge.stateAfter();
         // evacuateGuards
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/TypeProfileProxyNode.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,133 @@
+/*
+ * 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.nodes;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+
+/**
+ * A node that attached a type profile to a proxied input node.
+ */
+public final class TypeProfileProxyNode extends FloatingNode implements Canonicalizable, Node.IterableNodeType {
+
+    @Input private ValueNode object;
+    private final JavaTypeProfile profile;
+    private transient ResolvedJavaType lastCheckedType;
+    private transient JavaTypeProfile lastCheckedProfile;
+
+    public ValueNode getObject() {
+        return object;
+    }
+
+    public static ValueNode create(ValueNode object, JavaTypeProfile profile) {
+        if (profile == null) {
+            // No profile, so create no node.
+            return object;
+        }
+        if (profile.getTypes().length == 0) {
+            // Only null profiling is not beneficial enough to keep the node around.
+            return object;
+        }
+        return object.graph().add(new TypeProfileProxyNode(object, profile));
+    }
+
+    private TypeProfileProxyNode(ValueNode object, JavaTypeProfile profile) {
+        super(object.stamp());
+        this.object = object;
+        this.profile = profile;
+    }
+
+    public JavaTypeProfile getProfile() {
+        return profile;
+    }
+
+    @Override
+    public boolean inferStamp() {
+        return object.inferStamp();
+    }
+
+    @Override
+    public Stamp stamp() {
+        return object.stamp();
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool) {
+        if (object.objectStamp().isExactType()) {
+            // The profile is useless - we know the type!
+            return object;
+        } else if (object instanceof TypeProfileProxyNode) {
+            TypeProfileProxyNode other = (TypeProfileProxyNode) object;
+            JavaTypeProfile otherProfile = other.getProfile();
+            if (otherProfile == lastCheckedProfile) {
+                // We have already incorporated the knowledge about this profile => abort.
+                return this;
+            }
+            lastCheckedProfile = otherProfile;
+            JavaTypeProfile newProfile = this.profile.restrict(otherProfile);
+            if (newProfile.equals(otherProfile)) {
+                // We are useless - just use the other proxy node.
+                Debug.log("Canonicalize with other proxy node.");
+                return object;
+            }
+            if (newProfile != this.profile) {
+                Debug.log("Improved profile via other profile.");
+                return TypeProfileProxyNode.create(object, newProfile);
+            }
+        } else if (object.objectStamp().type() != null) {
+            ResolvedJavaType type = object.objectStamp().type();
+            ResolvedJavaType uniqueConcrete = type.findUniqueConcreteSubtype();
+            if (uniqueConcrete != null) {
+                // Profile is useless => remove.
+                Debug.log("Profile useless, there is enough static type information available.");
+                return object;
+            }
+            if (type == lastCheckedType) {
+                // We have already incorporate the knowledge about this type => abort.
+                return this;
+            }
+            lastCheckedType = type;
+            JavaTypeProfile newProfile = this.profile.restrict(type, object.objectStamp().nonNull());
+            if (newProfile != this.profile) {
+                Debug.log("Improved profile via static type information.");
+                if (newProfile.getTypes().length == 0) {
+                    // Only null profiling is not beneficial enough to keep the node around.
+                    return object;
+                }
+                return TypeProfileProxyNode.create(object, newProfile);
+            }
+        }
+        return this;
+    }
+
+    public static void cleanFromGraph(StructuredGraph graph) {
+        for (TypeProfileProxyNode proxy : graph.getNodes(TypeProfileProxyNode.class)) {
+            graph.replaceFloating(proxy, proxy.getObject());
+        }
+        assert graph.getNodes(TypeProfileProxyNode.class).count() == 0;
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/UnwindNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/UnwindNode.java	Mon May 13 17:11:31 2013 +0200
@@ -28,8 +28,7 @@
 import com.oracle.graal.nodes.type.*;
 
 /**
- * Unwind takes an exception object, destroys the current stack frame and passes the exception
- * object to the system's exception dispatch code.
+ * Unwinds the current frame to an exception handler in the caller frame.
  */
 public final class UnwindNode extends ControlSinkNode implements Lowerable, LIRLowerable, Node.IterableNodeType {
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNode.java	Mon May 13 17:11:31 2013 +0200
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.nodes;
 
-import java.util.*;
-
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.iterators.*;
@@ -42,28 +40,8 @@
      */
     private Stamp stamp;
 
-    @Input(notDataflow = true) private final NodeInputList<ValueNode> dependencies;
-
-    /**
-     * This collection keeps dependencies that should be observed while scheduling (guards, etc.).
-     */
-    public NodeInputList<ValueNode> dependencies() {
-        return dependencies;
-    }
-
     public ValueNode(Stamp stamp) {
         this.stamp = stamp;
-        this.dependencies = new NodeInputList<>(this);
-    }
-
-    public ValueNode(Stamp stamp, ValueNode... dependencies) {
-        this.stamp = stamp;
-        this.dependencies = new NodeInputList<>(this, dependencies);
-    }
-
-    public ValueNode(Stamp stamp, List<ValueNode> dependencies) {
-        this.stamp = stamp;
-        this.dependencies = new NodeInputList<>(this, dependencies);
     }
 
     public Stamp stamp() {
@@ -177,17 +155,4 @@
         assertTrue(kind() == kind().getStackKind(), "Should have a stack kind : %s", kind());
         return super.verify();
     }
-
-    @Override
-    public Map<Object, Object> getDebugProperties(Map<Object, Object> map) {
-        Map<Object, Object> properties = super.getDebugProperties(map);
-        if (!dependencies.isEmpty()) {
-            StringBuilder str = new StringBuilder();
-            for (int i = 0; i < dependencies.size(); i++) {
-                str.append(i == 0 ? "" : ", ").append(dependencies.get(i) == null ? "null" : dependencies.get(i).toString(Verbosity.Id));
-            }
-            properties.put("dependencies", str.toString());
-        }
-        return properties;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java	Mon May 13 17:11:31 2013 +0200
@@ -101,6 +101,16 @@
         return this;
     }
 
+    protected void setX(ValueNode x) {
+        updateUsages(this.x, x);
+        this.x = x;
+    }
+
+    protected void setY(ValueNode y) {
+        updateUsages(this.y, y);
+        this.y = y;
+    }
+
     protected LogicNode optimizeNormalizeCmp(Constant constant, NormalizeCompareNode normalizeNode, boolean mirrored) {
         throw new GraalInternalError("NormalizeCompareNode connected to %s (%s %s %s)", this, constant, normalizeNode, mirrored);
     }
@@ -123,6 +133,14 @@
                 return optimizeNormalizeCmp(y().asConstant(), (NormalizeCompareNode) x(), false);
             }
         }
+        if (x() instanceof ConvertNode && y() instanceof ConvertNode) {
+            ConvertNode convertX = (ConvertNode) x();
+            ConvertNode convertY = (ConvertNode) y();
+            if (convertX.opcode.isLossless() && convertY.opcode.isLossless()) {
+                setX(convertX.value());
+                setY(convertY.value());
+            }
+        }
         return this;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java	Mon May 13 17:11:31 2013 +0200
@@ -94,9 +94,10 @@
     }
 
     @Override
-    public Negatable negate() {
+    public Negatable negate(LogicNode cond) {
+        assert condition() == cond;
         ConditionalNode replacement = graph().unique(new ConditionalNode(condition, falseValue(), trueValue()));
-        ((StructuredGraph) graph()).replaceFloating(this, replacement);
+        graph().replaceFloating(this, replacement);
         return replacement;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java	Mon May 13 17:11:31 2013 +0200
@@ -25,6 +25,7 @@
 import static com.oracle.graal.api.meta.Kind.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
@@ -34,34 +35,97 @@
  */
 public final class ConvertNode extends FloatingNode implements Canonicalizable, LIRLowerable, Lowerable {
 
-    public enum Op {
-        I2L(Int, Long),
-        L2I(Long, Int),
-        I2B(Int, Byte),
-        I2C(Int, Char),
-        I2S(Int, Short),
-        F2D(Float, Double),
-        D2F(Double, Float),
-        I2F(Int, Float),
-        I2D(Int, Double),
-        F2I(Float, Int),
-        D2I(Double, Int),
-        L2F(Long, Float),
-        L2D(Long, Double),
-        F2L(Float, Long),
-        D2L(Double, Long),
-        UNSIGNED_I2L(Int, Long),
-        MOV_I2F(Int, Float),
-        MOV_L2D(Long, Double),
-        MOV_F2I(Float, Int),
-        MOV_D2L(Double, Long);
+    public static enum Op {
+        I2L(Int, Long, true),
+        L2I(Long, Int, false),
+        I2B(Int, Byte, false),
+        I2C(Int, Char, false),
+        I2S(Int, Short, false),
+        F2D(Float, Double, true),
+        D2F(Double, Float, false),
+        I2F(Int, Float, false),
+        I2D(Int, Double, true),
+        F2I(Float, Int, false),
+        D2I(Double, Int, false),
+        L2F(Long, Float, false),
+        L2D(Long, Double, false),
+        F2L(Float, Long, false),
+        D2L(Double, Long, false),
+        UNSIGNED_I2L(Int, Long, true),
+        MOV_I2F(Int, Float, false),
+        MOV_L2D(Long, Double, false),
+        MOV_F2I(Float, Int, false),
+        MOV_D2L(Double, Long, false);
 
         public final Kind from;
         public final Kind to;
+        public final boolean lossless;
 
-        private Op(Kind from, Kind to) {
+        private Op(Kind from, Kind to, boolean lossless) {
             this.from = from;
             this.to = to;
+            this.lossless = lossless;
+        }
+
+        public boolean isLossless() {
+            return lossless;
+        }
+
+        public static Op getOp(Kind from, Kind to) {
+            switch (from) {
+                case Int:
+                    switch (to) {
+                        case Byte:
+                            return I2B;
+                        case Char:
+                            return I2C;
+                        case Short:
+                            return I2S;
+                        case Long:
+                            return I2L;
+                        case Float:
+                            return I2F;
+                        case Double:
+                            return I2D;
+                        default:
+                            throw GraalInternalError.shouldNotReachHere();
+                    }
+                case Long:
+                    switch (to) {
+                        case Int:
+                            return L2I;
+                        case Float:
+                            return L2F;
+                        case Double:
+                            return L2D;
+                        default:
+                            throw GraalInternalError.shouldNotReachHere();
+                    }
+                case Float:
+                    switch (to) {
+                        case Int:
+                            return F2I;
+                        case Long:
+                            return F2L;
+                        case Double:
+                            return F2D;
+                        default:
+                            throw GraalInternalError.shouldNotReachHere();
+                    }
+                case Double:
+                    switch (to) {
+                        case Int:
+                            return D2I;
+                        case Long:
+                            return D2L;
+                        case Float:
+                            return D2F;
+                        default:
+                            throw GraalInternalError.shouldNotReachHere();
+                    }
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
+            }
         }
     }
 
@@ -171,6 +235,14 @@
         gen.setResult(this, gen.emitConvert(opcode, gen.operand(value())));
     }
 
+    public static ValueNode convert(Kind toKind, ValueNode value) {
+        Kind fromKind = value.kind();
+        if (fromKind == toKind) {
+            return value;
+        }
+        return value.graph().unique(new ConvertNode(Op.getOp(fromKind, toKind), value));
+    }
+
     @NodeIntrinsic
     public static native float convert(@ConstantNodeParameter Op op, int value);
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatingNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatingNode.java	Mon May 13 17:11:31 2013 +0200
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.nodes.calc;
 
-import java.util.*;
-
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.type.*;
@@ -33,12 +31,4 @@
     public FloatingNode(Stamp stamp) {
         super(stamp);
     }
-
-    public FloatingNode(Stamp stamp, ValueNode... dependencies) {
-        super(stamp, dependencies);
-    }
-
-    public FloatingNode(Stamp stamp, List<ValueNode> dependencies) {
-        super(stamp, dependencies);
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java	Mon May 13 17:11:31 2013 +0200
@@ -99,6 +99,13 @@
             }
         }
 
+        if (next() instanceof IntegerDivNode) {
+            NodeClass nodeClass = NodeClass.get(this.getClass());
+            if (next().getClass() == this.getClass() && nodeClass.inputsEqual(this, next()) && nodeClass.valueEqual(this, next())) {
+                return next();
+            }
+        }
+
         return this;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IsNullNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IsNullNode.java	Mon May 13 17:11:31 2013 +0200
@@ -83,12 +83,13 @@
     @Override
     public boolean push(PiNode parent) {
         ObjectStamp piStamp = parent.objectStamp();
-        ObjectStamp piValueStamp = parent.object().objectStamp();
-        if (piStamp.nonNull() == piValueStamp.nonNull() && piStamp.alwaysNull() == piValueStamp.alwaysNull()) {
-            replaceFirstInput(parent, parent.object());
-            return true;
-        } else {
-            return false;
+        if (parent.object().kind() == Kind.Object) {
+            ObjectStamp piValueStamp = parent.object().objectStamp();
+            if (piStamp.nonNull() == piValueStamp.nonNull() && piStamp.alwaysNull() == piValueStamp.alwaysNull()) {
+                replaceFirstInput(parent, parent.object());
+                return true;
+            }
         }
+        return false;
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java	Mon May 13 17:11:31 2013 +0200
@@ -69,6 +69,10 @@
         if (x() instanceof NegateNode) {
             return ((NegateNode) x()).x();
         }
+        if (x() instanceof IntegerSubNode) {
+            IntegerSubNode sub = (IntegerSubNode) x;
+            return IntegerArithmeticNode.sub(sub.y(), sub.x());
+        }
         return this;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NormalizeCompareNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NormalizeCompareNode.java	Mon May 13 17:11:31 2013 +0200
@@ -49,21 +49,19 @@
 
     @Override
     public void lower(LoweringTool tool, LoweringType loweringType) {
-        StructuredGraph graph = (StructuredGraph) graph();
-
         LogicNode equalComp;
         LogicNode lessComp;
         if (x().kind() == Kind.Double || x().kind() == Kind.Float) {
-            equalComp = graph.unique(new FloatEqualsNode(x(), y()));
-            lessComp = graph.unique(new FloatLessThanNode(x(), y(), isUnorderedLess));
+            equalComp = graph().unique(new FloatEqualsNode(x(), y()));
+            lessComp = graph().unique(new FloatLessThanNode(x(), y(), isUnorderedLess));
         } else {
-            equalComp = graph.unique(new IntegerEqualsNode(x(), y()));
-            lessComp = graph.unique(new IntegerLessThanNode(x(), y()));
+            equalComp = graph().unique(new IntegerEqualsNode(x(), y()));
+            lessComp = graph().unique(new IntegerLessThanNode(x(), y()));
         }
 
-        ConditionalNode equalValue = graph.unique(new ConditionalNode(equalComp, ConstantNode.forInt(0, graph), ConstantNode.forInt(1, graph)));
-        ConditionalNode value = graph.unique(new ConditionalNode(lessComp, ConstantNode.forInt(-1, graph), equalValue));
+        ConditionalNode equalValue = graph().unique(new ConditionalNode(equalComp, ConstantNode.forInt(0, graph()), ConstantNode.forInt(1, graph())));
+        ConditionalNode value = graph().unique(new ConditionalNode(lessComp, ConstantNode.forInt(-1, graph()), equalValue));
 
-        graph.replaceFloating(this, value);
+        graph().replaceFloating(this, value);
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java	Mon May 13 17:11:31 2013 +0200
@@ -70,6 +70,20 @@
         return super.canonical(tool);
     }
 
+    private void virtualizeNonVirtualComparison(State state, ValueNode other, VirtualizerTool tool) {
+        if (!state.getVirtualObject().hasIdentity() && state.getVirtualObject().entryKind(0) == Kind.Boolean) {
+            if (other.isConstant()) {
+                int expectedValue = ((Boolean) other.asConstant().asObject()) ? 1 : 0;
+                IntegerEqualsNode equals = new IntegerEqualsNode(state.getEntry(0), ConstantNode.forInt(expectedValue, graph()));
+                tool.addNode(equals);
+                tool.replaceWithValue(equals);
+            }
+        } else {
+            // one of them is virtual: they can never be the same objects
+            tool.replaceWithValue(LogicConstantNode.contradiction(graph()));
+        }
+    }
+
     @Override
     public void virtualize(VirtualizerTool tool) {
         State stateX = tool.getObjectState(x());
@@ -77,9 +91,10 @@
         boolean xVirtual = stateX != null && stateX.getState() == EscapeState.Virtual;
         boolean yVirtual = stateY != null && stateY.getState() == EscapeState.Virtual;
 
-        if (xVirtual ^ yVirtual) {
-            // one of them is virtual: they can never be the same objects
-            tool.replaceWithValue(LogicConstantNode.contradiction(graph()));
+        if (xVirtual && !yVirtual) {
+            virtualizeNonVirtualComparison(stateX, stateY != null ? stateY.getMaterializedValue() : y(), tool);
+        } else if (!xVirtual && yVirtual) {
+            virtualizeNonVirtualComparison(stateY, stateX != null ? stateX.getMaterializedValue() : x(), tool);
         } else if (xVirtual && yVirtual) {
             boolean xIdentity = stateX.getVirtualObject().hasIdentity();
             boolean yIdentity = stateY.getVirtualObject().hasIdentity();
@@ -97,14 +112,8 @@
                 assert stateX.getVirtualObject().entryCount() == 1 && stateY.getVirtualObject().entryCount() == 1;
                 assert stateX.getVirtualObject().type() == stateY.getVirtualObject().type();
                 assert stateX.getVirtualObject().entryKind(0) == Kind.Int || stateX.getVirtualObject().entryKind(0) == Kind.Long;
-                final IntegerEqualsNode equals = new IntegerEqualsNode(stateX.getEntry(0), stateY.getEntry(0));
-                tool.customAction(new Runnable() {
-
-                    @Override
-                    public void run() {
-                        graph().add(equals);
-                    }
-                });
+                IntegerEqualsNode equals = new IntegerEqualsNode(stateX.getEntry(0), stateY.getEntry(0));
+                tool.addNode(equals);
                 tool.replaceWithValue(equals);
             } else {
                 // both are virtual with identity: check if they refer to the same object
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java	Mon May 13 17:11:31 2013 +0200
@@ -29,7 +29,7 @@
 
 public final class Block {
 
-    protected final BeginNode beginNode;
+    protected final AbstractBeginNode beginNode;
 
     protected int id;
 
@@ -46,7 +46,7 @@
     private boolean align;
     private int linearScanNumber;
 
-    protected Block(BeginNode node) {
+    protected Block(AbstractBeginNode node) {
         this.beginNode = node;
 
         this.id = ControlFlowGraph.BLOCK_ID_INITIAL;
@@ -57,7 +57,7 @@
         return id;
     }
 
-    public BeginNode getBeginNode() {
+    public AbstractBeginNode getBeginNode() {
         return beginNode;
     }
 
@@ -150,7 +150,7 @@
             } else {
                 cur = ((FixedWithNextNode) cur).next();
             }
-            assert !(cur instanceof BeginNode);
+            assert !(cur instanceof AbstractBeginNode);
             return result;
         }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/CFGVerifier.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/CFGVerifier.java	Mon May 13 17:11:31 2013 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.nodes.cfg;
 
+import java.util.*;
+
 public class CFGVerifier {
 
     public static boolean verify(ControlFlowGraph cfg) {
@@ -48,6 +50,36 @@
                 assert dominated.getDominator() == block;
             }
 
+            Block postDominatorBlock = block.getPostdominator();
+            if (postDominatorBlock != null) {
+                assert block.getSuccessorCount() > 0 : "block has post-dominator block, but no successors";
+
+                BlockMap<Boolean> visitedBlocks = new BlockMap<>(cfg);
+                visitedBlocks.put(block, true);
+
+                Deque<Block> stack = new ArrayDeque<>();
+                for (Block sux : block.getSuccessors()) {
+                    visitedBlocks.put(sux, true);
+                    stack.push(sux);
+                }
+
+                while (stack.size() > 0) {
+                    Block tos = stack.pop();
+                    assert tos.getId() <= postDominatorBlock.getId();
+                    if (tos == postDominatorBlock) {
+                        continue; // found a valid path
+                    }
+                    assert tos.getSuccessorCount() > 0 : "no path found";
+
+                    for (Block sux : tos.getSuccessors()) {
+                        if (visitedBlocks.get(sux) == null) {
+                            visitedBlocks.put(sux, true);
+                            stack.push(sux);
+                        }
+                    }
+                }
+            }
+
             assert cfg.getLoops() == null || !block.isLoopHeader() || block.getLoop().header == block : block.beginNode;
         }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java	Mon May 13 17:11:31 2013 +0200
@@ -52,13 +52,14 @@
         if (computePostdominators) {
             cfg.computePostdominators();
         }
-        assert CFGVerifier.verify(cfg);
+        // there's not much to verify when connectBlocks == false
+        assert !(connectBlocks || computeLoops || computeDominators || computePostdominators) || CFGVerifier.verify(cfg);
         return cfg;
     }
 
     protected ControlFlowGraph(StructuredGraph graph) {
         this.graph = graph;
-        this.nodeToBlock = graph.createNodeMap();
+        this.nodeToBlock = graph.createNodeMap(true);
     }
 
     public Block[] getBlocks() {
@@ -135,7 +136,7 @@
 
             last = cur;
             cur = cur.successors().first();
-        } while (cur != null && !(cur instanceof BeginNode));
+        } while (cur != null && !(cur instanceof AbstractBeginNode));
 
         block.endNode = (FixedNode) last;
     }
@@ -144,8 +145,8 @@
         // Find all block headers
         int numBlocks = 0;
         for (Node node : graph.getNodes()) {
-            if (node instanceof BeginNode) {
-                Block block = new Block((BeginNode) node);
+            if (node instanceof AbstractBeginNode) {
+                Block block = new Block((AbstractBeginNode) node);
                 numBlocks++;
                 identifyBlock(block);
             }
@@ -247,7 +248,7 @@
                 for (Block b : loop.blocks) {
                     for (Block sux : b.getSuccessors()) {
                         if (sux.loop != loop) {
-                            BeginNode begin = sux.getBeginNode();
+                            AbstractBeginNode begin = sux.getBeginNode();
                             if (!(begin instanceof LoopExitNode && ((LoopExitNode) begin).loopBegin() == loopBegin)) {
                                 Debug.log("Unexpected loop exit with %s, including whole branch in the loop", sux);
                                 unexpected.add(sux);
@@ -335,21 +336,29 @@
     }
 
     private void computePostdominators() {
-        for (Block block : postOrder()) {
+        outer: for (Block block : postOrder()) {
             if (block.isLoopEnd()) {
                 // We do not want the loop header registered as the postdominator of the loop end.
                 continue;
             }
-            Block postdominator = null;
+            if (block.getSuccessorCount() == 0) {
+                // No successors => no postdominator.
+                continue;
+            }
+            Block firstSucc = block.getSuccessors().get(0);
+            if (block.getSuccessorCount() == 1) {
+                block.postdominator = firstSucc;
+                continue;
+            }
+            Block postdominator = firstSucc;
             for (Block sux : block.getSuccessors()) {
-                if (sux.isExceptionEntry()) {
-                    // We ignore exception handlers.
-                } else if (postdominator == null) {
-                    postdominator = sux;
-                } else {
-                    postdominator = commonPostdominator(postdominator, sux);
+                postdominator = commonPostdominator(postdominator, sux);
+                if (postdominator == null) {
+                    // There is a dead end => no postdominator available.
+                    continue outer;
                 }
             }
+            assert !block.getSuccessors().contains(postdominator) : "Block " + block + " has a wrong post dominator: " + postdominator;
             block.postdominator = postdominator;
         }
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java	Mon May 13 17:11:31 2013 +0200
@@ -150,27 +150,26 @@
         if (!enabled) {
             throw new GraalInternalError("counter nodes shouldn't exist when not enabled");
         }
-        StructuredGraph graph = (StructuredGraph) graph();
-        if (excludedClassPrefix == null || !graph.method().getDeclaringClass().getName().startsWith(excludedClassPrefix)) {
-            int index = addContext ? getIndex(name + " @ " + MetaUtil.format("%h.%n", ((StructuredGraph) graph()).method())) : getIndex(name);
+        if (excludedClassPrefix == null || !graph().method().getDeclaringClass().getName().startsWith(excludedClassPrefix)) {
+            int index = addContext ? getIndex(name + " @ " + MetaUtil.format("%h.%n", graph().method())) : getIndex(name);
             STATIC_COUNTERS[index] += increment;
             GROUPS[index] = group;
 
-            ConstantNode arrayConstant = ConstantNode.forObject(COUNTERS, tool.getRuntime(), graph);
-            ConstantNode indexConstant = ConstantNode.forInt(index, graph);
-            LoadIndexedNode load = graph.add(new LoadIndexedNode(arrayConstant, indexConstant, Kind.Long));
-            IntegerAddNode add = graph.add(new IntegerAddNode(Kind.Long, load, ConstantNode.forLong(increment, graph)));
-            StoreIndexedNode store = graph.add(new StoreIndexedNode(arrayConstant, indexConstant, Kind.Long, add));
+            ConstantNode arrayConstant = ConstantNode.forObject(COUNTERS, tool.getRuntime(), graph());
+            ConstantNode indexConstant = ConstantNode.forInt(index, graph());
+            LoadIndexedNode load = graph().add(new LoadIndexedNode(arrayConstant, indexConstant, Kind.Long));
+            IntegerAddNode add = graph().add(new IntegerAddNode(Kind.Long, load, ConstantNode.forLong(increment, graph())));
+            StoreIndexedNode store = graph().add(new StoreIndexedNode(arrayConstant, indexConstant, Kind.Long, add));
 
-            graph.addBeforeFixed(this, load);
-            graph.addBeforeFixed(this, store);
+            graph().addBeforeFixed(this, load);
+            graph().addBeforeFixed(this, store);
         }
-        graph.removeFixed(this);
+        graph().removeFixed(this);
     }
 
     public static void addCounterBefore(String group, String name, long increment, boolean addContext, FixedNode position) {
         if (enabled) {
-            StructuredGraph graph = (StructuredGraph) position.graph();
+            StructuredGraph graph = position.graph();
             DynamicCounterNode counter = graph.add(new DynamicCounterNode(name, group, increment, addContext));
             graph.addBeforeFixed(position, counter);
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/SurvivingCounterNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/SurvivingCounterNode.java	Mon May 13 17:11:31 2013 +0200
@@ -44,9 +44,7 @@
     public void simplify(SimplifierTool tool) {
         if (checkedValue instanceof FloatingNode && checkedValue.usages().count() == 1) {
             tool.addToWorkList(checkedValue);
-            ((StructuredGraph) graph()).removeFixed(this);
-            // ((StructuredGraph) graph()).replaceFixedWithFixed(this, graph().add(new
-            // DynamicCounterNode("non-surviving " + getName(), getIncrement(), isAddContext())));
+            graph().removeFixed(this);
         }
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/Access.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/Access.java	Mon May 13 17:11:31 2013 +0200
@@ -22,10 +22,9 @@
  */
 package com.oracle.graal.nodes.extended;
 
-import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 
-public interface Access extends DeoptimizingNode {
+public interface Access extends DeoptimizingNode, GuardedNode {
 
     ValueNode object();
 
@@ -33,5 +32,4 @@
 
     void setNullCheck(boolean check);
 
-    Node asNode();
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AccessNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AccessNode.java	Mon May 13 17:11:31 2013 +0200
@@ -22,10 +22,7 @@
  */
 package com.oracle.graal.nodes.extended;
 
-import java.util.*;
-
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -34,8 +31,9 @@
  * {@linkplain #nullCheckLocation() location}. The access does not include a null check on the
  * object.
  */
-public abstract class AccessNode extends DeoptimizingFixedWithNextNode implements Access {
+public abstract class AccessNode extends DeoptimizingFixedWithNextNode implements Access, GuardingNode {
 
+    @Input private GuardingNode guard;
     @Input private ValueNode object;
     @Input private ValueNode location;
     private boolean nullCheck;
@@ -61,25 +59,18 @@
     }
 
     public AccessNode(ValueNode object, ValueNode location, Stamp stamp) {
+        this(object, location, stamp, null);
+    }
+
+    public AccessNode(ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard) {
         super(stamp);
         this.object = object;
         this.location = location;
-    }
-
-    public AccessNode(ValueNode object, ValueNode location, Stamp stamp, List<ValueNode> dependencies) {
-        super(stamp, dependencies);
-        this.object = object;
-        this.location = location;
-    }
-
-    public AccessNode(ValueNode object, ValueNode location, Stamp stamp, ValueNode... dependencies) {
-        super(stamp, dependencies);
-        this.object = object;
-        this.location = location;
+        this.guard = guard;
     }
 
     @Override
-    public Node asNode() {
+    public AccessNode asNode() {
         return this;
     }
 
@@ -92,4 +83,15 @@
     public DeoptimizationReason getDeoptimizationReason() {
         return DeoptimizationReason.NullCheckException;
     }
+
+    @Override
+    public GuardingNode getGuard() {
+        return guard;
+    }
+
+    @Override
+    public void setGuard(GuardingNode guard) {
+        updateUsages(this.guard == null ? null : this.guard.asNode(), guard == null ? null : guard.asNode());
+        this.guard = guard;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java	Mon May 13 17:11:31 2013 +0200
@@ -27,6 +27,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
 
 /**
  * Location node that is the sum of two other location nodes. Can represent locations in the form of
@@ -38,50 +39,69 @@
     @Input private ValueNode x;
     @Input private ValueNode y;
 
-    public LocationNode getX() {
+    protected LocationNode getX() {
         return (LocationNode) x;
     }
 
-    public LocationNode getY() {
+    protected LocationNode getY() {
         return (LocationNode) y;
     }
 
     public static AddLocationNode create(LocationNode x, LocationNode y, Graph graph) {
-        assert x.getValueKind().equals(y.getValueKind()) && x.locationIdentity() == y.locationIdentity();
-        return graph.unique(new AddLocationNode(x.locationIdentity(), x.getValueKind(), x, y));
+        assert x.getValueKind().equals(y.getValueKind()) && x.getLocationIdentity() == y.getLocationIdentity();
+        return graph.unique(new AddLocationNode(x, y));
     }
 
-    private AddLocationNode(Object identity, Kind kind, ValueNode x, ValueNode y) {
-        super(identity, kind);
+    private AddLocationNode(ValueNode x, ValueNode y) {
+        super(StampFactory.extension());
         this.x = x;
         this.y = y;
     }
 
     @Override
-    protected LocationNode addDisplacement(long displacement) {
-        LocationNode added = getX().addDisplacement(displacement);
-        return graph().unique(new AddLocationNode(locationIdentity(), getValueKind(), added, getY()));
+    public Kind getValueKind() {
+        return getX().getValueKind();
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        return getX().getLocationIdentity();
     }
 
     @Override
     public ValueNode canonical(CanonicalizerTool tool) {
         if (x instanceof ConstantLocationNode) {
-            return getY().addDisplacement(((ConstantLocationNode) x).displacement());
+            return canonical((ConstantLocationNode) x, getY());
         }
         if (y instanceof ConstantLocationNode) {
-            return getX().addDisplacement(((ConstantLocationNode) y).displacement());
+            return canonical((ConstantLocationNode) y, getX());
         }
-
         if (x instanceof IndexedLocationNode && y instanceof IndexedLocationNode) {
             IndexedLocationNode xIdx = (IndexedLocationNode) x;
             IndexedLocationNode yIdx = (IndexedLocationNode) y;
-            if (xIdx.indexScaling() == yIdx.indexScaling()) {
-                long displacement = xIdx.displacement() + yIdx.displacement();
-                ValueNode index = IntegerArithmeticNode.add(xIdx.index(), yIdx.index());
-                return IndexedLocationNode.create(locationIdentity(), getValueKind(), displacement, index, graph(), xIdx.indexScaling());
+            if (xIdx.getIndexScaling() == yIdx.getIndexScaling()) {
+                long displacement = xIdx.getDisplacement() + yIdx.getDisplacement();
+                ValueNode index = IntegerArithmeticNode.add(xIdx.getIndex(), yIdx.getIndex());
+                return IndexedLocationNode.create(getLocationIdentity(), getValueKind(), displacement, index, graph(), xIdx.getIndexScaling());
             }
         }
+        return this;
+    }
 
+    private LocationNode canonical(ConstantLocationNode constant, LocationNode other) {
+        if (other instanceof ConstantLocationNode) {
+            ConstantLocationNode otherConst = (ConstantLocationNode) other;
+            return ConstantLocationNode.create(getLocationIdentity(), getValueKind(), otherConst.getDisplacement() + constant.getDisplacement(), graph());
+        } else if (other instanceof IndexedLocationNode) {
+            IndexedLocationNode otherIdx = (IndexedLocationNode) other;
+            return IndexedLocationNode.create(getLocationIdentity(), getValueKind(), otherIdx.getDisplacement() + constant.getDisplacement(), otherIdx.getIndex(), graph(), otherIdx.getIndexScaling());
+        } else if (other instanceof AddLocationNode) {
+            AddLocationNode otherAdd = (AddLocationNode) other;
+            LocationNode newInner = otherAdd.canonical(constant, otherAdd.getX());
+            if (newInner != otherAdd) {
+                return AddLocationNode.create(newInner, otherAdd.getY(), graph());
+            }
+        }
         return this;
     }
 
@@ -92,5 +112,5 @@
     }
 
     @NodeIntrinsic
-    public static native Location addLocation(@ConstantNodeParameter Object identity, @ConstantNodeParameter Kind kind, Location x, Location y);
+    public static native Location addLocation(Location x, Location y);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java	Mon May 13 17:11:31 2013 +0200
@@ -76,7 +76,7 @@
         VirtualBoxingNode newVirtual = new VirtualBoxingNode(type, boxingKind);
         assert newVirtual.getFields().length == 1;
 
-        tool.createVirtualObject(newVirtual, new ValueNode[]{v}, 0);
+        tool.createVirtualObject(newVirtual, new ValueNode[]{v}, null);
         tool.replaceWithVirtual(newVirtual);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ConstantLocationNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ConstantLocationNode.java	Mon May 13 17:11:31 2013 +0200
@@ -25,36 +25,47 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
 
 /**
  * Location node that has a constant displacement. Can represent addresses of the form [base + disp]
  * where base is a node and disp is a constant.
  */
 @NodeInfo(nameTemplate = "Loc {p#locationIdentity/s}")
-public class ConstantLocationNode extends LocationNode {
+public final class ConstantLocationNode extends LocationNode {
 
+    private final Kind valueKind;
+    private final LocationIdentity locationIdentity;
     private final long displacement;
 
-    public long displacement() {
-        return displacement;
-    }
-
-    public static ConstantLocationNode create(Object identity, Kind kind, long displacement, Graph graph) {
+    public static ConstantLocationNode create(LocationIdentity identity, Kind kind, long displacement, Graph graph) {
         return graph.unique(new ConstantLocationNode(identity, kind, displacement));
     }
 
-    protected ConstantLocationNode(Object identity, Kind kind, long displacement) {
-        super(identity, kind);
+    private ConstantLocationNode(LocationIdentity identity, Kind kind, long displacement) {
+        super(StampFactory.extension());
+        assert kind != Kind.Illegal && kind != Kind.Void;
+        this.valueKind = kind;
+        this.locationIdentity = identity;
         this.displacement = displacement;
     }
 
     @Override
-    protected ConstantLocationNode addDisplacement(long x) {
-        return create(locationIdentity(), getValueKind(), displacement + x, graph());
+    public Kind getValueKind() {
+        return valueKind;
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        return locationIdentity;
+    }
+
+    public long getDisplacement() {
+        return displacement;
     }
 
     @Override
     public Value generateAddress(LIRGeneratorTool gen, Value base) {
-        return gen.emitAddress(base, displacement(), Value.ILLEGAL, 0);
+        return gen.emitAddress(base, getDisplacement(), Value.ILLEGAL, 0);
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatableAccessNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatableAccessNode.java	Mon May 13 17:11:31 2013 +0200
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.nodes.extended;
 
-import java.util.*;
-
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -36,12 +34,8 @@
         super(object, location, stamp);
     }
 
-    public FloatableAccessNode(ValueNode object, ValueNode location, Stamp stamp, List<ValueNode> dependencies) {
-        super(object, location, stamp, dependencies);
-    }
-
-    public FloatableAccessNode(ValueNode object, ValueNode location, Stamp stamp, ValueNode... dependencies) {
-        super(object, location, stamp, dependencies);
+    public FloatableAccessNode(ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard) {
+        super(object, location, stamp, guard);
     }
 
     public abstract FloatingAccessNode asFloatingNode(ValueNode lastLocationAccess);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingAccessNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingAccessNode.java	Mon May 13 17:11:31 2013 +0200
@@ -22,15 +22,11 @@
  */
 package com.oracle.graal.nodes.extended;
 
-import java.util.*;
-
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.type.*;
 
-public abstract class FloatingAccessNode extends FloatingNode implements Access {
+public abstract class FloatingAccessNode extends FloatingGuardedNode implements Access {
 
     @Input private ValueNode object;
     @Input private LocationNode location;
@@ -63,20 +59,14 @@
         this.location = location;
     }
 
-    public FloatingAccessNode(ValueNode object, LocationNode location, Stamp stamp, ValueNode... dependencies) {
-        super(stamp, dependencies);
-        this.object = object;
-        this.location = location;
-    }
-
-    public FloatingAccessNode(ValueNode object, LocationNode location, Stamp stamp, List<ValueNode> dependencies) {
-        super(stamp, dependencies);
+    public FloatingAccessNode(ValueNode object, LocationNode location, Stamp stamp, GuardingNode guard) {
+        super(stamp, guard);
         this.object = object;
         this.location = location;
     }
 
     @Override
-    public Node asNode() {
+    public FloatingAccessNode asNode() {
         return this;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java	Mon May 13 17:11:31 2013 +0200
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.nodes.extended;
 
-import java.util.*;
-
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
@@ -38,13 +36,12 @@
 
     @Input private Node lastLocationAccess;
 
-    public FloatingReadNode(ValueNode object, LocationNode location, Node lastLocationAccess, Stamp stamp, ValueNode... dependencies) {
-        super(object, location, stamp, dependencies);
-        this.lastLocationAccess = lastLocationAccess;
+    public FloatingReadNode(ValueNode object, LocationNode location, Node lastLocationAccess, Stamp stamp) {
+        this(object, location, lastLocationAccess, stamp, null);
     }
 
-    public FloatingReadNode(ValueNode object, LocationNode location, Node lastLocationAccess, Stamp stamp, List<ValueNode> dependencies) {
-        super(object, location, stamp, dependencies);
+    public FloatingReadNode(ValueNode object, LocationNode location, Node lastLocationAccess, Stamp stamp, GuardingNode guard) {
+        super(object, location, stamp, guard);
         this.lastLocationAccess = lastLocationAccess;
     }
 
@@ -65,6 +62,6 @@
 
     @Override
     public Access asFixedNode() {
-        return graph().add(new ReadNode(object(), nullCheckLocation(), stamp(), dependencies()));
+        return graph().add(new ReadNode(object(), nullCheckLocation(), stamp(), getGuard()));
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/GuardedNode.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,34 @@
+/*
+ * 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.*;
+
+public interface GuardedNode {
+
+    GuardingNode getGuard();
+
+    void setGuard(GuardingNode guard);
+
+    ValueNode asNode();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/GuardingNode.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,30 @@
+/*
+ * 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.*;
+
+public interface GuardingNode {
+
+    ValueNode asNode();
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java	Mon May 13 17:11:31 2013 +0200
@@ -26,6 +26,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
 
 /**
  * Location node that has a displacement and a scaled index. Can represent locations in the form of
@@ -35,65 +36,66 @@
 @NodeInfo(nameTemplate = "IdxLoc {p#locationIdentity/s}")
 public final class IndexedLocationNode extends LocationNode implements Canonicalizable {
 
+    private final Kind valueKind;
+    private final LocationIdentity locationIdentity;
+    private final long displacement;
     @Input private ValueNode index;
-    private final long displacement;
     private final int indexScaling;
 
     /**
      * Gets the index or offset of this location.
      */
-    public ValueNode index() {
+    public ValueNode getIndex() {
         return index;
     }
 
-    public long displacement() {
+    public long getDisplacement() {
         return displacement;
     }
 
     /**
      * @return Constant that is used to scale the index.
      */
-    public int indexScaling() {
+    public int getIndexScaling() {
         return indexScaling;
     }
 
-    public static IndexedLocationNode create(Object identity, Kind kind, long displacement, ValueNode index, Graph graph, int indexScaling) {
+    public static IndexedLocationNode create(LocationIdentity identity, Kind kind, long displacement, ValueNode index, Graph graph, int indexScaling) {
         return graph.unique(new IndexedLocationNode(identity, kind, displacement, index, indexScaling));
     }
 
-    private IndexedLocationNode(Object identity, Kind kind, ValueNode index, int indexScaling) {
-        this(identity, kind, 0, index, indexScaling);
-    }
-
-    private IndexedLocationNode(Object identity, Kind kind, long displacement, ValueNode index, int indexScaling) {
-        super(identity, kind);
+    private IndexedLocationNode(LocationIdentity identity, Kind kind, long displacement, ValueNode index, int indexScaling) {
+        super(StampFactory.extension());
+        assert kind != Kind.Illegal && kind != Kind.Void;
+        this.valueKind = kind;
+        this.locationIdentity = identity;
         this.index = index;
         this.displacement = displacement;
         this.indexScaling = indexScaling;
     }
 
     @Override
-    protected LocationNode addDisplacement(long x) {
-        return create(locationIdentity(), getValueKind(), displacement + x, index, graph(), indexScaling);
+    public Kind getValueKind() {
+        return valueKind;
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        return locationIdentity;
     }
 
     @Override
     public ValueNode canonical(CanonicalizerTool tool) {
-        Constant constantIndex = index.asConstant();
-        if (constantIndex != null) {
-            long constantIndexLong = constantIndex.asLong();
-            constantIndexLong *= indexScaling;
-            constantIndexLong += displacement;
-            return ConstantLocationNode.create(locationIdentity(), getValueKind(), constantIndexLong, graph());
+        if (index == null || indexScaling == 0) {
+            return ConstantLocationNode.create(getLocationIdentity(), getValueKind(), displacement, graph());
+        } else if (index.isConstant()) {
+            return ConstantLocationNode.create(getLocationIdentity(), getValueKind(), index.asConstant().asLong() * indexScaling + displacement, graph());
         }
         return this;
     }
 
     @Override
     public Value generateAddress(LIRGeneratorTool gen, Value base) {
-        return gen.emitAddress(base, displacement, gen.operand(index()), indexScaling());
+        return gen.emitAddress(base, displacement, gen.operand(getIndex()), getIndexScaling());
     }
-
-    @NodeIntrinsic
-    public static native Location indexedLocation(@ConstantNodeParameter Object identity, @ConstantNodeParameter Kind kind, int index, @ConstantNodeParameter int indexScaling);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IntegerSwitchNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IntegerSwitchNode.java	Mon May 13 17:11:31 2013 +0200
@@ -48,7 +48,7 @@
      * @param keyProbabilities the probabilities of the keys
      * @param keySuccessors the successor index for each key
      */
-    public IntegerSwitchNode(ValueNode value, BeginNode[] successors, int[] keys, double[] keyProbabilities, int[] keySuccessors) {
+    public IntegerSwitchNode(ValueNode value, AbstractBeginNode[] successors, int[] keys, double[] keyProbabilities, int[] keySuccessors) {
         super(value, successors, keySuccessors, keyProbabilities);
         assert keySuccessors.length == keys.length + 1;
         assert keySuccessors.length == keyProbabilities.length;
@@ -66,7 +66,7 @@
      * @param keySuccessors the successor index for each key
      */
     public IntegerSwitchNode(ValueNode value, int successorCount, int[] keys, double[] keyProbabilities, int[] keySuccessors) {
-        this(value, new BeginNode[successorCount], keys, keyProbabilities, keySuccessors);
+        this(value, new AbstractBeginNode[successorCount], keys, keyProbabilities, keySuccessors);
     }
 
     /**
@@ -94,7 +94,7 @@
     public void simplify(SimplifierTool tool) {
         if (blockSuccessorCount() == 1) {
             tool.addToWorkList(defaultSuccessor());
-            ((StructuredGraph) graph()).removeSplitPropagate(this, defaultSuccessor());
+            graph().removeSplitPropagate(this, defaultSuccessor());
         } else if (value() instanceof ConstantNode) {
             int constant = value().asConstant().asInt();
 
@@ -110,7 +110,7 @@
                 }
             }
             tool.addToWorkList(blockSuccessor(survivingEdge));
-            ((StructuredGraph) graph()).removeSplit(this, blockSuccessor(survivingEdge));
+            graph().removeSplit(this, blockSuccessor(survivingEdge));
         } else if (value() != null) {
             IntegerStamp stamp = value().integerStamp();
             if (!stamp.isUnrestricted()) {
@@ -122,9 +122,9 @@
                 }
                 if (validKeys == 0) {
                     tool.addToWorkList(defaultSuccessor());
-                    ((StructuredGraph) graph()).removeSplitPropagate(this, defaultSuccessor());
+                    graph().removeSplitPropagate(this, defaultSuccessor());
                 } else if (validKeys != keys.length) {
-                    ArrayList<BeginNode> newSuccessors = new ArrayList<>(blockSuccessorCount());
+                    ArrayList<AbstractBeginNode> newSuccessors = new ArrayList<>(blockSuccessorCount());
                     int[] newKeys = new int[validKeys];
                     int[] newKeySuccessors = new int[validKeys + 1];
                     double[] newKeyProbabilities = new double[validKeys + 1];
@@ -153,14 +153,14 @@
                     }
 
                     for (int i = 0; i < blockSuccessorCount(); i++) {
-                        BeginNode successor = blockSuccessor(i);
+                        AbstractBeginNode successor = blockSuccessor(i);
                         if (!newSuccessors.contains(successor)) {
                             tool.deleteBranch(successor);
                         }
                         setBlockSuccessor(i, null);
                     }
 
-                    BeginNode[] successorsArray = newSuccessors.toArray(new BeginNode[newSuccessors.size()]);
+                    AbstractBeginNode[] successorsArray = newSuccessors.toArray(new AbstractBeginNode[newSuccessors.size()]);
                     IntegerSwitchNode newSwitch = graph().add(new IntegerSwitchNode(value(), successorsArray, newKeys, newKeyProbabilities, newKeySuccessors));
                     ((FixedWithNextNode) predecessor()).setNext(newSwitch);
                     GraphUtil.killWithUnusedFloatingInputs(this);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadMethodNode.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,61 @@
+/*
+ * 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 java.lang.reflect.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+
+/**
+ * Loads a method from the virtual method table of a given hub.
+ */
+public final class LoadMethodNode extends FixedWithNextNode implements Lowerable {
+
+    @Input private ValueNode hub;
+    private final ResolvedJavaMethod method;
+
+    public ValueNode getHub() {
+        return hub;
+    }
+
+    public LoadMethodNode(ResolvedJavaMethod method, ValueNode hub, Kind kind) {
+        super(kind == Kind.Object ? StampFactory.objectNonNull() : StampFactory.forKind(kind));
+        this.hub = hub;
+        this.method = method;
+        assert !Modifier.isAbstract(method.getModifiers()) : "Cannot load abstract method from a hub";
+        assert !Modifier.isStatic(method.getModifiers()) : "Cannot load a static method from a hub";
+        assert method.isInVirtualMethodTable();
+    }
+
+    @Override
+    public void lower(LoweringTool tool, LoweringType loweringType) {
+        tool.getRuntime().lower(this, tool);
+    }
+
+    public ResolvedJavaMethod getMethod() {
+        return method;
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LocationNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LocationNode.java	Mon May 13 17:11:31 2013 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.nodes.extended;
 
+import java.util.*;
+
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.Node.ValueNumberable;
 import com.oracle.graal.nodes.calc.*;
@@ -35,8 +37,25 @@
  */
 public abstract class LocationNode extends FloatingNode implements LIRLowerable, ValueNumberable {
 
-    private Kind valueKind;
-    private Object locationIdentity;
+    /**
+     * Marker interface for location identities. Apart from the special values {@link #ANY_LOCATION}
+     * and {@link #FINAL_LOCATION}, a different location identity of two memory accesses guarantees
+     * that the two accesses do not interfere.
+     */
+    public interface LocationIdentity {
+    }
+
+    /**
+     * Denotes any location. A write to such a location kills all values in a memory map during an
+     * analysis of memory accesses in a graph. A read from this location cannot be moved or
+     * coalesced with other reads because its interaction with other reads is not known.
+     */
+    public static final LocationIdentity ANY_LOCATION = createLocation("ANY_LOCATION");
+
+    /**
+     * Denotes the location of a value that is guaranteed to be final.
+     */
+    public static final LocationIdentity FINAL_LOCATION = createLocation("FINAL_LOCATION");
 
     /**
      * Creates a new unique location identity for read and write operations.
@@ -44,8 +63,8 @@
      * @param name the name of the new location identity, for debugging purposes
      * @return the new location identity
      */
-    public static Object createLocation(final String name) {
-        return new Object() {
+    public static LocationIdentity createLocation(final String name) {
+        return new LocationIdentity() {
 
             @Override
             public String toString() {
@@ -55,16 +74,23 @@
     }
 
     /**
-     * Denotes any location. A write to such a location kills all values in a memory map during an
-     * analysis of memory accesses in a graph. A read from this location cannot be moved or
-     * coalesced with other reads because its interaction with other reads is not known.
+     * Returns the location identity for an array of the given element kind. Array accesses of the
+     * same kind must have the same location identity unless an alias analysis guarantees that two
+     * distinct arrays are accessed.
      */
-    public static final Object ANY_LOCATION = createLocation("ANY_LOCATION");
+    public static LocationIdentity getArrayLocation(Kind elementKind) {
+        return ARRAY_LOCATIONS.get(elementKind);
+    }
+
+    private static final EnumMap<Kind, LocationIdentity> ARRAY_LOCATIONS = initArrayLocations();
 
-    /**
-     * Denotes the location of a value that is guaranteed to be final.
-     */
-    public static final Object FINAL_LOCATION = createLocation("FINAL_LOCATION");
+    private static EnumMap<Kind, LocationIdentity> initArrayLocations() {
+        EnumMap<Kind, LocationIdentity> result = new EnumMap<>(Kind.class);
+        for (Kind kind : Kind.values()) {
+            result.put(kind, createLocation("Array: " + kind.getJavaName()));
+        }
+        return result;
+    }
 
     /**
      * Marker interface for locations in snippets.
@@ -72,29 +98,22 @@
     public interface Location {
     }
 
-    public static Object getArrayLocation(Kind elementKind) {
-        return elementKind;
-    }
-
-    protected LocationNode(Object identity, Kind kind) {
-        super(StampFactory.extension());
-        assert kind != Kind.Illegal && kind != Kind.Void;
-        this.valueKind = kind;
-        this.locationIdentity = identity;
+    protected LocationNode(Stamp stamp) {
+        super(stamp);
     }
 
-    public Kind getValueKind() {
-        return valueKind;
-    }
+    /**
+     * Returns the kind of the accessed memory value.
+     */
+    public abstract Kind getValueKind();
 
-    public Object locationIdentity() {
-        return locationIdentity;
-    }
-
-    protected abstract LocationNode addDisplacement(long displacement);
+    /**
+     * Returns the identity of the accessed memory location.
+     */
+    public abstract LocationIdentity getLocationIdentity();
 
     @Override
-    public void generate(LIRGeneratorTool generator) {
+    public final void generate(LIRGeneratorTool generator) {
         // nothing to do...
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MembarNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MembarNode.java	Mon May 13 17:11:31 2013 +0200
@@ -31,6 +31,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -50,8 +51,8 @@
     }
 
     @Override
-    public Object[] getLocationIdentities() {
-        return new Object[]{LocationNode.ANY_LOCATION};
+    public LocationIdentity[] getLocationIdentities() {
+        return new LocationIdentity[]{LocationNode.ANY_LOCATION};
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryCheckpoint.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryCheckpoint.java	Mon May 13 17:11:31 2013 +0200
@@ -23,11 +23,12 @@
 package com.oracle.graal.nodes.extended;
 
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity;
 
 /**
- * This interface marks is used for subclasses of {@link FixedNode} that kill a set of memory
- * locations represented by location identities (i.e. change a value at one or more locations that
- * belong to these location identities).
+ * This interface marks subclasses of {@link FixedNode} that kill a set of memory locations
+ * represented by location identities (i.e. change a value at one or more locations that belong to
+ * these location identities).
  */
 public interface MemoryCheckpoint {
 
@@ -37,6 +38,6 @@
      * 
      * @return the identities of all locations killed by this node.
      */
-    Object[] getLocationIdentities();
+    LocationIdentity[] getLocationIdentities();
 
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/NullCheckNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/NullCheckNode.java	Mon May 13 17:11:31 2013 +0200
@@ -27,7 +27,7 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
-public class NullCheckNode extends DeoptimizingFixedWithNextNode implements LIRLowerable {
+public class NullCheckNode extends DeoptimizingFixedWithNextNode implements LIRLowerable, GuardingNode {
 
     @Input public ValueNode object;
 
@@ -54,4 +54,9 @@
     public DeoptimizationReason getDeoptimizationReason() {
         return DeoptimizationReason.NullCheckException;
     }
+
+    @Override
+    public ValueNode asNode() {
+        return this;
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/OSRLocalNode.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,36 @@
+/*
+ * 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.extended;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.type.*;
+
+@NodeInfo(nameTemplate = "OSRLocal({p#index})")
+public class OSRLocalNode extends AbstractLocalNode implements Node.IterableNodeType {
+
+    public OSRLocalNode(int index, Stamp stamp) {
+        super(index, stamp);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/OSRStartNode.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,41 @@
+/*
+ * 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.nodes.extended;
+
+import com.oracle.graal.graph.iterators.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+
+public class OSRStartNode extends StartNode implements Lowerable {
+
+    @Override
+    public void lower(LoweringTool tool, LoweringType loweringType) {
+        if (loweringType == LoweringType.AFTER_GUARDS) {
+            tool.getRuntime().lower(this, tool);
+        }
+    }
+
+    public NodeIterable<OSRLocalNode> getOSRLocals() {
+        return usages().filter(OSRLocalNode.class);
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java	Mon May 13 17:11:31 2013 +0200
@@ -22,11 +22,10 @@
  */
 package com.oracle.graal.nodes.extended;
 
-import java.util.*;
-
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -39,20 +38,20 @@
         super(object, location, stamp);
     }
 
-    public ReadNode(ValueNode object, ValueNode location, Stamp stamp, List<ValueNode> dependencies) {
-        super(object, location, stamp, dependencies);
+    public ReadNode(ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard) {
+        super(object, location, stamp, guard);
     }
 
-    private ReadNode(ValueNode object, int displacement, Object locationIdentity, Kind kind) {
+    private ReadNode(ValueNode object, int displacement, LocationIdentity locationIdentity, Kind kind) {
         super(object, ConstantLocationNode.create(locationIdentity, kind, displacement, object.graph()), StampFactory.forKind(kind));
     }
 
-    private ReadNode(ValueNode object, ValueNode location, ValueNode dependency) {
+    private ReadNode(ValueNode object, ValueNode location, GuardingNode guard) {
         /*
          * Used by node intrinsics. 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(), dependency);
+        super(object, location, StampFactory.forNodeIntrinsic(), guard);
     }
 
     @Override
@@ -68,14 +67,14 @@
 
     @Override
     public FloatingAccessNode asFloatingNode(ValueNode lastLocationAccess) {
-        return graph().unique(new FloatingReadNode(object(), location(), lastLocationAccess, stamp(), dependencies()));
+        return graph().unique(new FloatingReadNode(object(), location(), lastLocationAccess, stamp(), getGuard()));
     }
 
     public static ValueNode canonicalizeRead(ValueNode read, LocationNode location, ValueNode object, CanonicalizerTool tool) {
         MetaAccessProvider runtime = tool.runtime();
         if (runtime != null && object != null && object.isConstant()) {
-            if (location.locationIdentity() == LocationNode.FINAL_LOCATION && location instanceof ConstantLocationNode) {
-                long displacement = ((ConstantLocationNode) location).displacement();
+            if (location.getLocationIdentity() == LocationNode.FINAL_LOCATION && location instanceof ConstantLocationNode) {
+                long displacement = ((ConstantLocationNode) location).getDisplacement();
                 Kind kind = location.getValueKind();
                 if (object.kind() == Kind.Object) {
                     Object base = object.asConstant().asObject();
@@ -101,19 +100,27 @@
 
     @Override
     public boolean push(PiNode parent) {
-        Object locId = location().locationIdentity();
-        if (locId instanceof ResolvedJavaField) {
-            ResolvedJavaType fieldType = ((ResolvedJavaField) locId).getDeclaringClass();
-            ValueNode piValueStamp = parent.object();
-            ResolvedJavaType beforePiType = piValueStamp.objectStamp().type();
+        if (location() instanceof ConstantLocationNode) {
+            long displacement = ((ConstantLocationNode) location()).getDisplacement();
+            if (parent.stamp() instanceof ObjectStamp) {
+                ObjectStamp piStamp = parent.objectStamp();
+                ResolvedJavaType receiverType = piStamp.type();
+                if (receiverType != null) {
+                    ResolvedJavaField field = receiverType.findInstanceFieldWithOffset(displacement);
 
-            if (beforePiType != null && fieldType.isAssignableFrom(beforePiType)) {
-                ObjectStamp piStamp = parent.objectStamp();
-                if (piStamp.nonNull() == piValueStamp.objectStamp().nonNull() && piStamp.alwaysNull() == piValueStamp.objectStamp().alwaysNull()) {
-                    replaceFirstInput(parent, piValueStamp);
-                    return true;
+                    if (field != null) {
+                        ResolvedJavaType declaringClass = field.getDeclaringClass();
+                        if (declaringClass.isAssignableFrom(receiverType) && declaringClass != receiverType) {
+                            ObjectStamp piValueStamp = parent.object().objectStamp();
+                            if (piStamp.nonNull() == piValueStamp.nonNull() && piStamp.alwaysNull() == piValueStamp.alwaysNull()) {
+                                replaceFirstInput(parent, parent.object());
+                                return true;
+                            }
+                        }
+                    }
                 }
             }
+
         }
         return false;
     }
@@ -128,5 +135,5 @@
      * @return the value read from memory
      */
     @NodeIntrinsic(setStampFromReturnType = true)
-    public static native <T> T read(Object base, @ConstantNodeParameter int displacement, @ConstantNodeParameter Object locationIdentity, @ConstantNodeParameter Kind kind);
+    public static native <T> T read(Object base, @ConstantNodeParameter int displacement, @ConstantNodeParameter LocationIdentity locationIdentity, @ConstantNodeParameter Kind kind);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/RuntimeCallNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/RuntimeCallNode.java	Mon May 13 17:11:31 2013 +0200
@@ -26,6 +26,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -50,8 +51,8 @@
     }
 
     @Override
-    public Object[] getLocationIdentities() {
-        return new Object[]{LocationNode.ANY_LOCATION};
+    public LocationIdentity[] getLocationIdentities() {
+        return new LocationIdentity[]{LocationNode.ANY_LOCATION};
     }
 
     @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SnippetLocationNode.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,109 @@
+/*
+ * 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.nodes.extended;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+
+/**
+ * Location node that can be used inside a snippet without having the elements (including the
+ * location identity and kind) as a snippet constant. Can represent locations in the form of [base +
+ * index * scale + disp]. When the location is created, all elements (base, index, scale, disp) are
+ * nodes. Both scale and disp must eventually canonicalize to {@link ConstantNode constants} so that
+ * this node can be canonicalized to a {@link IndexedLocationNode} or {@link ConstantLocationNode}.
+ */
+public final class SnippetLocationNode extends LocationNode implements Canonicalizable {
+
+    @Input private ValueNode valueKind;
+    @Input private ValueNode locationIdentity;
+    @Input private ValueNode displacement;
+    @Input private ValueNode index;
+    @Input private ValueNode indexScaling;
+
+    public static SnippetLocationNode create(ValueNode identity, ValueNode kind, ValueNode displacement, ValueNode index, ValueNode indexScaling, Graph graph) {
+        return graph.unique(new SnippetLocationNode(identity, kind, displacement, index, indexScaling));
+    }
+
+    private SnippetLocationNode(ValueNode locationIdentity, ValueNode kind, ValueNode displacement) {
+        this(locationIdentity, kind, displacement, null, null);
+    }
+
+    private SnippetLocationNode(ValueNode locationIdentity, ValueNode kind, ValueNode displacement, ValueNode index, ValueNode indexScaling) {
+        super(StampFactory.object());
+        this.valueKind = kind;
+        this.locationIdentity = locationIdentity;
+        this.displacement = displacement;
+        this.index = index;
+        this.indexScaling = indexScaling;
+    }
+
+    @Override
+    public Kind getValueKind() {
+        if (valueKind.isConstant()) {
+            return (Kind) valueKind.asConstant().asObject();
+        }
+        throw new GraalInternalError("Cannot access kind yet because it is not constant: " + valueKind);
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        if (locationIdentity.isConstant()) {
+            return (LocationIdentity) locationIdentity.asConstant().asObject();
+        }
+        // We do not know our actual location identity yet, so be conservative.
+        return LocationNode.ANY_LOCATION;
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool) {
+        if (valueKind.isConstant() && locationIdentity.isConstant() && displacement.isConstant() && (indexScaling == null || indexScaling.isConstant())) {
+            Kind constKind = (Kind) valueKind.asConstant().asObject();
+            LocationIdentity constLocation = (LocationIdentity) locationIdentity.asConstant().asObject();
+            long constDisplacement = displacement.asConstant().asLong();
+            int constIndexScaling = indexScaling == null ? 0 : indexScaling.asConstant().asInt();
+
+            if (index == null || constIndexScaling == 0) {
+                return ConstantLocationNode.create(constLocation, constKind, constDisplacement, graph());
+            } else if (index.isConstant()) {
+                return ConstantLocationNode.create(constLocation, constKind, index.asConstant().asLong() * constIndexScaling + constDisplacement, graph());
+            } else {
+                return IndexedLocationNode.create(constLocation, constKind, constDisplacement, index, graph(), constIndexScaling);
+            }
+        }
+        return this;
+    }
+
+    @Override
+    public Value generateAddress(LIRGeneratorTool gen, Value base) {
+        throw new GraalInternalError("locationIdentity must be a constant so that this node can be canonicalized: " + locationIdentity);
+    }
+
+    @NodeIntrinsic
+    public static native Location constantLocation(LocationIdentity identity, Kind kind, long displacement);
+
+    @NodeIntrinsic
+    public static native Location indexedLocation(LocationIdentity identity, Kind kind, long displacement, int index, int indexScaling);
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SwitchNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SwitchNode.java	Mon May 13 17:11:31 2013 +0200
@@ -34,7 +34,7 @@
  */
 public abstract class SwitchNode extends ControlSplitNode {
 
-    @Successor protected final NodeSuccessorList<BeginNode> successors;
+    @Successor protected final NodeSuccessorList<AbstractBeginNode> successors;
     @Input private ValueNode value;
     private double[] keyProbabilities;
     private int[] keySuccessors;
@@ -45,17 +45,25 @@
      * @param value the instruction that provides the value to be switched over
      * @param successors the list of successors of this switch
      */
-    public SwitchNode(ValueNode value, BeginNode[] successors, int[] keySuccessors, double[] keyProbabilities) {
+    public SwitchNode(ValueNode value, AbstractBeginNode[] successors, int[] keySuccessors, double[] keyProbabilities) {
         super(StampFactory.forVoid());
         assert keySuccessors.length == keyProbabilities.length;
         this.successors = new NodeSuccessorList<>(this, successors);
         this.value = value;
         this.keySuccessors = keySuccessors;
         this.keyProbabilities = keyProbabilities;
+        assert assertProbabilities();
+    }
+
+    private boolean assertProbabilities() {
+        for (double d : keyProbabilities) {
+            assert d >= 0.0 : "Cannot have negative probabilities in switch node: " + d;
+        }
+        return true;
     }
 
     @Override
-    public double probability(BeginNode successor) {
+    public double probability(AbstractBeginNode successor) {
         double sum = 0;
         for (int i = 0; i < keySuccessors.length; i++) {
             if (successors.get(keySuccessors[i]) == successor) {
@@ -89,7 +97,7 @@
     /**
      * Returns the successor for the key at the given index.
      */
-    public BeginNode keySuccessor(int i) {
+    public AbstractBeginNode keySuccessor(int i) {
         return successors.get(keySuccessors[i]);
     }
 
@@ -107,11 +115,11 @@
         return keySuccessors[keySuccessors.length - 1];
     }
 
-    public BeginNode blockSuccessor(int i) {
+    public AbstractBeginNode blockSuccessor(int i) {
         return successors.get(i);
     }
 
-    public void setBlockSuccessor(int i, BeginNode s) {
+    public void setBlockSuccessor(int i, AbstractBeginNode s) {
         successors.set(i, s);
     }
 
@@ -124,7 +132,7 @@
      * 
      * @return the default successor
      */
-    public BeginNode defaultSuccessor() {
+    public AbstractBeginNode defaultSuccessor() {
         if (defaultSuccessorIndex() == -1) {
             throw new GraalInternalError("unexpected");
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java	Mon May 13 17:11:31 2013 +0200
@@ -79,9 +79,9 @@
                     case Long:
                         return ConstantNode.forLong((Long) o, graph());
                     case Float:
-                        return ConstantNode.forFloat((Long) o, graph());
+                        return ConstantNode.forFloat((Float) o, graph());
                     case Double:
-                        return ConstantNode.forDouble((Long) o, graph());
+                        return ConstantNode.forDouble((Double) o, graph());
                     default:
                         ValueNodeUtil.shouldNotReachHere();
                 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeArrayCastNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeArrayCastNode.java	Mon May 13 17:11:31 2013 +0200
@@ -37,6 +37,11 @@
         return length;
     }
 
+    public UnsafeArrayCastNode(ValueNode object, ValueNode length, Stamp stamp) {
+        super(object, stamp);
+        this.length = length;
+    }
+
     public UnsafeArrayCastNode(ValueNode object, ValueNode length, Stamp stamp, ValueNode anchor) {
         super(object, stamp, anchor);
         this.length = length;
@@ -51,5 +56,8 @@
     }
 
     @NodeIntrinsic
+    public static native <T> T unsafeArrayCast(Object object, int length, @ConstantNodeParameter Stamp stamp);
+
+    @NodeIntrinsic
     public static native <T> T unsafeArrayCast(Object object, int length, @ConstantNodeParameter Stamp stamp, Object anchor);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java	Mon May 13 17:11:31 2013 +0200
@@ -37,7 +37,7 @@
     }
 
     public UnsafeCastNode(ValueNode object, Stamp stamp, ValueNode anchor) {
-        super(object, stamp, anchor);
+        super(object, stamp, (FixedNode) anchor);
     }
 
     public UnsafeCastNode(ValueNode object, ResolvedJavaType toType, boolean exactType, boolean nonNull) {
@@ -90,7 +90,7 @@
     @Override
     public void generate(LIRGeneratorTool generator) {
         if (kind() != object().kind()) {
-            assert generator.target().sizeInBytes(kind()) == generator.target().sizeInBytes(object().kind()) : "unsafe cast cannot be used to change the size of a value";
+            assert generator.target().arch.getSizeInBytes(kind()) == generator.target().arch.getSizeInBytes(object().kind()) : "unsafe cast cannot be used to change the size of a value";
             AllocatableValue result = generator.newVariable(kind());
             generator.emitMove(result, generator.operand(object()));
             generator.setResult(this, result);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java	Mon May 13 17:11:31 2013 +0200
@@ -27,6 +27,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
@@ -74,8 +75,8 @@
     }
 
     @Override
-    public Object[] getLocationIdentities() {
-        return new Object[]{LocationNode.ANY_LOCATION};
+    public LocationIdentity[] getLocationIdentities() {
+        return new LocationIdentity[]{LocationNode.ANY_LOCATION};
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java	Mon May 13 17:11:31 2013 +0200
@@ -34,15 +34,18 @@
 /**
  * The ValueAnchor instruction keeps non-CFG (floating) nodes above a certain point in the graph.
  */
-public final class ValueAnchorNode extends FixedWithNextNode implements Canonicalizable, LIRLowerable, Node.IterableNodeType, Virtualizable {
+public final class ValueAnchorNode extends FixedWithNextNode implements Canonicalizable, LIRLowerable, Node.IterableNodeType, Virtualizable, GuardingNode {
+
+    @Input private NodeInputList<ValueNode> anchored;
 
     public ValueAnchorNode(ValueNode... values) {
         this(false, values);
     }
 
     public ValueAnchorNode(boolean permanent, ValueNode... values) {
-        super(StampFactory.dependency(), values);
+        super(StampFactory.dependency());
         this.permanent = permanent;
+        this.anchored = new NodeInputList<>(this, values);
     }
 
     private final boolean permanent;
@@ -53,8 +56,8 @@
     }
 
     public void addAnchoredNode(ValueNode value) {
-        if (!this.dependencies().contains(value)) {
-            this.dependencies().add(value);
+        if (!anchored.contains(value)) {
+            this.anchored.add(value);
         }
     }
 
@@ -67,13 +70,13 @@
             ValueAnchorNode previousAnchor = (ValueAnchorNode) this.predecessor();
             if (previousAnchor.usages().isEmpty()) { // avoid creating cycles
                 // transfer values and remove
-                for (ValueNode node : dependencies().nonNull().distinct()) {
+                for (ValueNode node : anchored.nonNull().distinct()) {
                     previousAnchor.addAnchoredNode(node);
                 }
                 return previousAnchor;
             }
         }
-        for (Node node : dependencies().nonNull().and(isNotA(FixedNode.class))) {
+        for (Node node : anchored.nonNull().and(isNotA(FixedNode.class))) {
             if (node instanceof ConstantNode) {
                 continue;
             }
@@ -100,7 +103,7 @@
         if (permanent) {
             return;
         }
-        for (ValueNode node : dependencies().nonNull().and(isNotA(BeginNode.class))) {
+        for (ValueNode node : anchored.nonNull().and(isNotA(AbstractBeginNode.class))) {
             State state = tool.getObjectState(node);
             if (state == null || state.getState() != EscapeState.Virtual) {
                 return;
@@ -108,4 +111,9 @@
         }
         tool.delete();
     }
+
+    @Override
+    public ValueNode asNode() {
+        return this;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteMemoryCheckpointNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteMemoryCheckpointNode.java	Mon May 13 17:11:31 2013 +0200
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes.extended;
 
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -37,8 +38,8 @@
     }
 
     @Override
-    public Object[] getLocationIdentities() {
-        return new Object[]{LocationNode.ANY_LOCATION};
+    public LocationIdentity[] getLocationIdentities() {
+        return new LocationIdentity[]{LocationNode.ANY_LOCATION};
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java	Mon May 13 17:11:31 2013 +0200
@@ -25,6 +25,8 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.LocationNode.Location;
+import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -90,10 +92,10 @@
     }
 
     @NodeIntrinsic
-    public static native void writeMemory(Object object, Object value, Object location, @ConstantNodeParameter boolean usePreciseWriteBarriers);
+    public static native void writeMemory(Object object, Object value, Location location, @ConstantNodeParameter WriteBarrierType barrierType);
 
     @Override
-    public Object[] getLocationIdentities() {
-        return new Object[]{location().locationIdentity()};
+    public LocationIdentity[] getLocationIdentities() {
+        return new LocationIdentity[]{location().getLocationIdentity()};
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessIndexedNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessIndexedNode.java	Mon May 13 17:11:31 2013 +0200
@@ -34,7 +34,7 @@
 public abstract class AccessIndexedNode extends AccessArrayNode implements Lowerable {
 
     @Input private ValueNode index;
-    private final Kind elementType;
+    private final Kind elementKind;
 
     public ValueNode index() {
         return index;
@@ -46,12 +46,12 @@
      * @param stamp the result kind of the access
      * @param array the instruction producing the array
      * @param index the instruction producing the index
-     * @param elementKind the type of the elements of the array
+     * @param elementKind the kind of the elements of the array
      */
     protected AccessIndexedNode(Stamp stamp, ValueNode array, ValueNode index, Kind elementKind) {
         super(stamp, array);
         this.index = index;
-        this.elementType = elementKind;
+        this.elementKind = elementKind;
     }
 
     /**
@@ -60,7 +60,7 @@
      * @return the element type
      */
     public Kind elementKind() {
-        return elementType;
+        return elementKind;
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java	Mon May 13 17:11:31 2013 +0200
@@ -23,43 +23,24 @@
 package com.oracle.graal.nodes.java;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.debug.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.nodes.virtual.*;
 
 /**
  * The {@code AccessMonitorNode} is the base class of both monitor acquisition and release.
  * <p>
- * The VM needs information about monitors in the debug information. This information is built from
- * the nesting level of {@link MonitorEnterNode} when the LIR is constructed. Therefore, monitor
- * nodes must not be removed from the graph unless it is guaranteed that the nesting level does not
- * change. For example, you must not remove a {@link MonitorEnterNode} for a thread-local object or
- * for a recursive locking. Instead, mark the node as {@link #eliminated}. This makes sure that the
- * meta data still contains the complete locking hierarchy.
- * <p>
  * 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 StateSplit, MemoryCheckpoint, Virtualizable {
+public abstract class AccessMonitorNode extends AbstractStateSplit implements StateSplit, MemoryCheckpoint {
 
     @Input private ValueNode object;
-    private boolean eliminated;
 
     public ValueNode object() {
         return object;
     }
 
-    public boolean eliminated() {
-        return eliminated;
-    }
-
-    public void eliminate() {
-        eliminated = true;
-    }
-
     /**
      * Creates a new AccessMonitor instruction.
      * 
@@ -69,22 +50,4 @@
         super(StampFactory.forVoid());
         this.object = object;
     }
-
-    @Override
-    public void virtualize(VirtualizerTool tool) {
-        State state = tool.getObjectState(object);
-        if (state != null && state.getState() == EscapeState.Virtual && state.getVirtualObject().getClass() == VirtualInstanceNode.class) {
-            Debug.log("monitor operation %s on %s\n", this, state);
-            int newLockCount = state.getLockCount() + (this instanceof MonitorEnterNode ? 1 : -1);
-            state.setLockCount(newLockCount);
-            tool.replaceFirstInput(object(), state.getVirtualObject());
-            tool.customAction(new Runnable() {
-
-                @Override
-                public void run() {
-                    eliminate();
-                }
-            });
-        }
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastDynamicNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastDynamicNode.java	Mon May 13 17:11:31 2013 +0200
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.nodes.java;
 
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
@@ -37,13 +38,24 @@
     @Input private ValueNode type;
 
     /**
+     * Determines the exception thrown by this node if the check fails: {@link ClassCastException}
+     * if false; {@link ArrayStoreException} if true.
+     */
+    private final boolean forStoreCheck;
+
+    /**
      * @param type the type being cast to
      * @param object the instruction producing the object
      */
-    public CheckCastDynamicNode(ValueNode type, ValueNode object) {
+    public CheckCastDynamicNode(ValueNode type, ValueNode object, boolean forStoreCheck) {
         super(object.stamp());
         this.type = type;
         this.object = object;
+        this.forStoreCheck = forStoreCheck;
+    }
+
+    public boolean isForStoreCheck() {
+        return forStoreCheck;
     }
 
     @Override
@@ -67,6 +79,11 @@
         if (object().objectStamp().alwaysNull()) {
             return object();
         }
+        if (type().isConstant() && type().kind() == Kind.Object && type().asConstant().asObject() instanceof Class) {
+            Class clazz = (Class) type().asConstant().asObject();
+            ResolvedJavaType t = tool.runtime().lookupJavaType(clazz);
+            return graph().add(new CheckCastNode(t, object(), null, forStoreCheck));
+        }
         return this;
     }
 
@@ -80,4 +97,7 @@
     public ValueNode type() {
         return type;
     }
+
+    @NodeIntrinsic
+    public static native <T> T checkCastDynamic(Class<T> type, Object object, @ConstantNodeParameter boolean forStoreCheck);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java	Mon May 13 17:11:31 2013 +0200
@@ -38,17 +38,28 @@
     private final JavaTypeProfile profile;
 
     /**
+     * Determines the exception thrown by this node if the check fails: {@link ClassCastException}
+     * if false; {@link ArrayStoreException} if true.
+     */
+    private final boolean forStoreCheck;
+
+    /**
      * Creates a new CheckCast instruction.
      * 
      * @param type the type being cast to
      * @param object the instruction producing the object
      */
-    public CheckCastNode(ResolvedJavaType type, ValueNode object, JavaTypeProfile profile) {
+    public CheckCastNode(ResolvedJavaType type, ValueNode object, JavaTypeProfile profile, boolean forStoreCheck) {
         super(StampFactory.declared(type));
         assert type != null;
         this.type = type;
         this.object = object;
         this.profile = profile;
+        this.forStoreCheck = forStoreCheck;
+    }
+
+    public boolean isForStoreCheck() {
+        return forStoreCheck;
     }
 
     @Override
@@ -68,26 +79,35 @@
     public ValueNode canonical(CanonicalizerTool tool) {
         assert object() != null : this;
 
-        if (type != null) {
-            ResolvedJavaType objectType = object().objectStamp().type();
-            if (objectType != null && type.isAssignableFrom(objectType)) {
-                // we don't have to check for null types here because they will also pass the
-                // checkcast.
-                return object();
-            }
+        ResolvedJavaType objectType = object().objectStamp().type();
+        if (objectType != null && type.isAssignableFrom(objectType)) {
+            // we don't have to check for null types here because they will also pass the
+            // checkcast.
+            return object();
+        }
 
-            // remove checkcast if the only usage is a more specific checkcast
-            if (usages().count() == 1) {
-                CheckCastNode ccn = usages().filter(CheckCastNode.class).first();
-                if (ccn != null && ccn.type() != null && type.isAssignableFrom(ccn.type())) {
-                    return object();
-                }
+        // remove checkcast if next node is a more specific checkcast
+        if (predecessor() instanceof CheckCastNode) {
+            CheckCastNode ccn = (CheckCastNode) predecessor();
+            if (ccn != null && ccn.type != null && ccn == object && ccn.forStoreCheck == forStoreCheck && ccn.type.isAssignableFrom(type)) {
+                StructuredGraph graph = ccn.graph();
+                CheckCastNode newccn = graph.add(new CheckCastNode(type, ccn.object, ccn.profile, ccn.forStoreCheck));
+                graph.replaceFixedWithFixed(ccn, newccn);
+                return newccn;
             }
         }
 
         if (object().objectStamp().alwaysNull()) {
             return object();
         }
+        if (tool.assumptions().useOptimisticAssumptions()) {
+            ResolvedJavaType exactType = type.findUniqueConcreteSubtype();
+            if (exactType != null && exactType != type) {
+                // Propagate more precise type information to usages of the checkcast.
+                tool.assumptions().recordConcreteSubtype(type, exactType);
+                return graph().add(new CheckCastNode(exactType, object, profile, forStoreCheck));
+            }
+        }
 
         return this;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java	Mon May 13 17:11:31 2013 +0200
@@ -28,7 +28,8 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.extended.WriteNode.*;
+import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity;
+import com.oracle.graal.nodes.extended.WriteNode.WriteBarrierType;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -95,8 +96,8 @@
     }
 
     @Override
-    public Object[] getLocationIdentities() {
-        return new Object[]{LocationNode.ANY_LOCATION};
+    public LocationIdentity[] getLocationIdentities() {
+        return new LocationIdentity[]{LocationNode.ANY_LOCATION};
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java	Mon May 13 17:11:31 2013 +0200
@@ -25,6 +25,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -39,8 +40,8 @@
     }
 
     @Override
-    public Object[] getLocationIdentities() {
-        return new Object[]{LocationNode.ANY_LOCATION};
+    public LocationIdentity[] getLocationIdentities() {
+        return new LocationIdentity[]{LocationNode.ANY_LOCATION};
     }
 
     @Override
@@ -57,11 +58,10 @@
         if (isLowered()) {
             return;
         }
-        StructuredGraph graph = (StructuredGraph) graph();
-        LoadExceptionObjectNode loadException = graph.add(new LoadExceptionObjectNode(stamp()));
+        LoadExceptionObjectNode loadException = graph().add(new LoadExceptionObjectNode(stamp()));
         loadException.setStateAfter(stateAfter());
         replaceAtUsages(loadException);
-        graph.addAfterFixed(this, loadException);
+        graph().addAfterFixed(this, loadException);
         tool.setLastFixedNode(loadException);
         setStateAfter(null);
         setStamp(StampFactory.forVoid());
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java	Mon May 13 17:11:31 2013 +0200
@@ -80,7 +80,7 @@
     @Override
     public boolean verify() {
         for (Node usage : usages()) {
-            assertTrue(usage instanceof IfNode || usage instanceof ConditionalNode, "unsupported usage: %s", usage);
+            assertTrue(usage instanceof IfNode || usage instanceof FixedGuardNode || usage instanceof ConditionalNode, "unsupported usage: %s", usage);
         }
         return super.verify();
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java	Mon May 13 17:11:31 2013 +0200
@@ -36,7 +36,7 @@
 
     @Input private ValueNode object;
     private final ResolvedJavaType type;
-    private final JavaTypeProfile profile;
+    private JavaTypeProfile profile;
 
     /**
      * Constructs a new InstanceOfNode.
@@ -109,10 +109,14 @@
         return profile;
     }
 
+    public void setProfile(JavaTypeProfile profile) {
+        this.profile = profile;
+    }
+
     @Override
     public boolean verify() {
         for (Node usage : usages()) {
-            assertTrue(usage instanceof IfNode || usage instanceof ConditionalNode, "unsupported usage: ", usage);
+            assertTrue(usage instanceof IfNode || usage instanceof FixedGuardNode || usage instanceof ConditionalNode, "unsupported usage: ", usage);
         }
         return super.verify();
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java	Mon May 13 17:11:31 2013 +0200
@@ -53,6 +53,11 @@
     }
 
     @Override
+    public boolean inferStamp() {
+        return updateStamp(createStamp(array(), elementKind()));
+    }
+
+    @Override
     public void virtualize(VirtualizerTool tool) {
         State arrayState = tool.getObjectState(array());
         if (arrayState != null && arrayState.getState() == EscapeState.Virtual) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java	Mon May 13 17:11:31 2013 +0200
@@ -24,12 +24,13 @@
 
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity;
 import com.oracle.graal.nodes.spi.*;
 
 /**
  * The {@code MonitorEnterNode} represents the acquisition of a monitor.
  */
-public final class MonitorEnterNode extends AccessMonitorNode implements Lowerable, MonitorEnter, MonitorReference {
+public final class MonitorEnterNode extends AccessMonitorNode implements Virtualizable, Lowerable, MonitorEnter, MonitorReference {
 
     private int lockDepth;
 
@@ -44,10 +45,11 @@
     }
 
     @Override
-    public Object[] getLocationIdentities() {
-        return new Object[]{LocationNode.ANY_LOCATION};
+    public LocationIdentity[] getLocationIdentities() {
+        return new LocationIdentity[]{LocationNode.ANY_LOCATION};
     }
 
+    @Override
     public void lower(LoweringTool tool, LoweringType loweringType) {
         tool.getRuntime().lower(this, tool);
     }
@@ -59,4 +61,13 @@
     public void setLockDepth(int lockDepth) {
         this.lockDepth = lockDepth;
     }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        State state = tool.getObjectState(object());
+        if (state != null && state.getState() == EscapeState.Virtual && state.getVirtualObject().hasIdentity()) {
+            state.addLock(getLockDepth());
+            tool.delete();
+        }
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java	Mon May 13 17:11:31 2013 +0200
@@ -22,15 +22,16 @@
  */
 package com.oracle.graal.nodes.java;
 
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.graph.*;
 
 /**
  * The {@code MonitorEnterNode} represents a monitor release.
  */
-public final class MonitorExitNode extends AccessMonitorNode implements Lowerable, Node.IterableNodeType, MonitorExit, MonitorReference {
+public final class MonitorExitNode extends AccessMonitorNode implements Virtualizable, Lowerable, Node.IterableNodeType, MonitorExit, MonitorReference {
 
     private int lockDepth;
 
@@ -45,10 +46,11 @@
     }
 
     @Override
-    public Object[] getLocationIdentities() {
-        return new Object[]{LocationNode.ANY_LOCATION};
+    public LocationIdentity[] getLocationIdentities() {
+        return new LocationIdentity[]{LocationNode.ANY_LOCATION};
     }
 
+    @Override
     public void lower(LoweringTool tool, LoweringType loweringType) {
         tool.getRuntime().lower(this, tool);
     }
@@ -60,4 +62,14 @@
     public void setLockDepth(int lockDepth) {
         this.lockDepth = lockDepth;
     }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        State state = tool.getObjectState(object());
+        if (state != null && state.getState() == EscapeState.Virtual && state.getVirtualObject().hasIdentity()) {
+            int removedLock = state.removeLock();
+            assert removedLock == getLockDepth();
+            tool.delete();
+        }
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java	Mon May 13 17:11:31 2013 +0200
@@ -38,8 +38,6 @@
     private final ResolvedJavaType elementType;
     private final boolean fillContents;
 
-    private final boolean locked;
-
     @Override
     public ValueNode length() {
         return length;
@@ -52,14 +50,12 @@
      *            the array itself).
      * @param length the node that produces the length for this allocation.
      * @param fillContents determines whether the array elements should be initialized to zero/null.
-     * @param locked determines whether the array should be locked immediately.
      */
-    public NewArrayNode(ResolvedJavaType elementType, ValueNode length, boolean fillContents, boolean locked) {
+    public NewArrayNode(ResolvedJavaType elementType, ValueNode length, boolean fillContents) {
         super(StampFactory.exactNonNull(elementType.getArrayClass()));
         this.length = length;
         this.elementType = elementType;
         this.fillContents = fillContents;
-        this.locked = locked;
     }
 
     /**
@@ -70,13 +66,6 @@
     }
 
     /**
-     * @return <code>true</code> if the array will be locked immediately.
-     */
-    public boolean locked() {
-        return locked;
-    }
-
-    /**
      * The list of node which produce input for this instruction.
      */
     public ValueNode dimension(int index) {
@@ -111,7 +100,9 @@
 
     @Override
     public void lower(LoweringTool tool, LoweringType loweringType) {
-        tool.getRuntime().lower(this, tool);
+        if (loweringType == LoweringType.AFTER_GUARDS) {
+            tool.getRuntime().lower(this, tool);
+        }
     }
 
     @Override
@@ -125,7 +116,7 @@
                     state[i] = defaultForKind;
                 }
                 VirtualObjectNode virtualObject = new VirtualArrayNode(elementType, constantLength);
-                tool.createVirtualObject(virtualObject, state, 0);
+                tool.createVirtualObject(virtualObject, state, null);
                 tool.replaceWithVirtual(virtualObject);
             }
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java	Mon May 13 17:11:31 2013 +0200
@@ -37,7 +37,6 @@
 
     private final ResolvedJavaType instanceClass;
     private final boolean fillContents;
-    private final boolean locked;
 
     /**
      * Constructs a NewInstanceNode.
@@ -45,13 +44,11 @@
      * @param type the class being allocated
      * @param fillContents determines whether the new object's fields should be initialized to
      *            zero/null.
-     * @param locked determines whether the new object should be locked immediately.
      */
-    public NewInstanceNode(ResolvedJavaType type, boolean fillContents, boolean locked) {
+    public NewInstanceNode(ResolvedJavaType type, boolean fillContents) {
         super(StampFactory.exactNonNull(type));
         this.instanceClass = type;
         this.fillContents = fillContents;
-        this.locked = locked;
     }
 
     /**
@@ -70,13 +67,6 @@
         return fillContents;
     }
 
-    /**
-     * @return <code>true</code> if the new object will be locked immediately.
-     */
-    public boolean locked() {
-        return locked;
-    }
-
     @Override
     public ValueNode canonical(CanonicalizerTool tool) {
         if (usages().isEmpty()) {
@@ -88,7 +78,9 @@
 
     @Override
     public void lower(LoweringTool tool, LoweringType loweringType) {
-        tool.getRuntime().lower(this, tool);
+        if (loweringType == LoweringType.AFTER_GUARDS) {
+            tool.getRuntime().lower(this, tool);
+        }
     }
 
     @Override
@@ -101,7 +93,7 @@
             for (int i = 0; i < state.length; i++) {
                 state[i] = ConstantNode.defaultForKind(fields[i].getType().getKind(), graph());
             }
-            tool.createVirtualObject(virtualObject, state, 0);
+            tool.createVirtualObject(virtualObject, state, null);
             tool.replaceWithVirtual(virtualObject);
         }
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewMultiArrayNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewMultiArrayNode.java	Mon May 13 17:11:31 2013 +0200
@@ -63,7 +63,9 @@
 
     @Override
     public void lower(LoweringTool tool, LoweringType loweringType) {
-        tool.getRuntime().lower(this, tool);
+        if (loweringType == LoweringType.AFTER_GUARDS) {
+            tool.getRuntime().lower(this, tool);
+        }
     }
 
     public ResolvedJavaType type() {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreIndexedNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreIndexedNode.java	Mon May 13 17:11:31 2013 +0200
@@ -73,8 +73,11 @@
             ValueNode indexValue = tool.getReplacedValue(index());
             int index = indexValue.isConstant() ? indexValue.asConstant().asInt() : -1;
             if (index >= 0 && index < arrayState.getVirtualObject().entryCount()) {
-                tool.setVirtualEntry(arrayState, index, value());
-                tool.delete();
+                ResolvedJavaType componentType = arrayState.getVirtualObject().type().getComponentType();
+                if (componentType.isPrimitive() || value.objectStamp().alwaysNull() || componentType.isAssignableFrom(value.objectStamp().type())) {
+                    tool.setVirtualEntry(arrayState, index, value());
+                    tool.delete();
+                }
             }
         }
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeSwitchNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeSwitchNode.java	Mon May 13 17:11:31 2013 +0200
@@ -50,7 +50,7 @@
      * @param keyProbabilities the probabilities of the keys
      * @param keySuccessors the successor index for each key
      */
-    public TypeSwitchNode(ValueNode value, BeginNode[] successors, ResolvedJavaType[] keys, double[] keyProbabilities, int[] keySuccessors) {
+    public TypeSwitchNode(ValueNode value, AbstractBeginNode[] successors, ResolvedJavaType[] keys, double[] keyProbabilities, int[] keySuccessors) {
         super(value, successors, keySuccessors, keyProbabilities);
         assert successors.length <= keys.length + 1;
         assert keySuccessors.length == keyProbabilities.length;
@@ -95,7 +95,7 @@
                 }
             }
             tool.addToWorkList(blockSuccessor(survivingEdge));
-            ((StructuredGraph) graph()).removeSplit(this, blockSuccessor(survivingEdge));
+            graph().removeSplit(this, blockSuccessor(survivingEdge));
         }
         if (value() instanceof LoadHubNode) {
             ObjectStamp stamp = ((LoadHubNode) value()).object().objectStamp();
@@ -108,9 +108,9 @@
                 }
                 if (validKeys == 0) {
                     tool.addToWorkList(defaultSuccessor());
-                    ((StructuredGraph) graph()).removeSplitPropagate(this, defaultSuccessor());
+                    graph().removeSplitPropagate(this, defaultSuccessor());
                 } else if (validKeys != keys.length) {
-                    ArrayList<BeginNode> newSuccessors = new ArrayList<>(blockSuccessorCount());
+                    ArrayList<AbstractBeginNode> newSuccessors = new ArrayList<>(blockSuccessorCount());
                     ResolvedJavaType[] newKeys = new ResolvedJavaType[validKeys];
                     int[] newKeySuccessors = new int[validKeys + 1];
                     double[] newKeyProbabilities = new double[validKeys + 1];
@@ -139,14 +139,14 @@
                     }
 
                     for (int i = 0; i < blockSuccessorCount(); i++) {
-                        BeginNode successor = blockSuccessor(i);
+                        AbstractBeginNode successor = blockSuccessor(i);
                         if (!newSuccessors.contains(successor)) {
                             tool.deleteBranch(successor);
                         }
                         setBlockSuccessor(i, null);
                     }
 
-                    BeginNode[] successorsArray = newSuccessors.toArray(new BeginNode[newSuccessors.size()]);
+                    AbstractBeginNode[] successorsArray = newSuccessors.toArray(new AbstractBeginNode[newSuccessors.size()]);
                     TypeSwitchNode newSwitch = graph().add(new TypeSwitchNode(value(), successorsArray, newKeys, newKeyProbabilities, newKeySuccessors));
                     ((FixedWithNextNode) predecessor()).setNext(newSwitch);
                     GraphUtil.killWithUnusedFloatingInputs(this);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java	Mon May 13 17:11:31 2013 +0200
@@ -49,7 +49,7 @@
 
     Value operand(ValueNode object);
 
-    AllocatableValue newVariable(Kind kind);
+    AllocatableValue newVariable(PlatformKind kind);
 
     Value setResult(ValueNode x, Value operand);
 
@@ -116,7 +116,7 @@
     // Handling of block-end nodes still needs to be unified in the LIRGenerator.
     void visitMerge(MergeNode i);
 
-    void visitEndNode(EndNode i);
+    void visitEndNode(AbstractEndNode i);
 
     void visitLoopEnd(LoopEndNode i);
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LoweringTool.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LoweringTool.java	Mon May 13 17:11:31 2013 +0200
@@ -27,6 +27,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.cfg.*;
+import com.oracle.graal.nodes.extended.*;
 
 public interface LoweringTool {
 
@@ -34,11 +35,11 @@
 
     Replacements getReplacements();
 
-    ValueNode createNullCheckGuard(ValueNode object);
+    GuardingNode createNullCheckGuard(GuardedNode guardedNode, ValueNode object);
 
-    ValueNode createGuard(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action);
+    GuardingNode createGuard(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action);
 
-    ValueNode createGuard(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, boolean negated);
+    GuardingNode createGuard(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, boolean negated);
 
     Assumptions assumptions();
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Negatable.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Negatable.java	Mon May 13 17:11:31 2013 +0200
@@ -28,15 +28,15 @@
  * This interface marks a node as being able to negate its effect, this is intended for nodes that
  * depend on a BooleanNode condition. The canonical representation of has, for example, no way to
  * represent a != b. If such an expression appears during canonicalization the negated expression
- * will be created (a == b) and the usages will be negated, using this interface's {@link #negate()}
- * method.
+ * will be created (a == b) and the usages will be negated, using this interface's
+ * {@link #negate(LogicNode)} method.
  */
 public interface Negatable {
 
     /**
      * Tells this node that a condition it depends has been negated, and that it thus needs to
-     * invert its own effect. For example, an {@link IfNode} would switch its true and false
-     * successors.
+     * invert the effects of this condition. For example, an {@link IfNode} would switch its true
+     * and false successors.
      */
-    Negatable negate();
+    Negatable negate(LogicNode condition);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Virtualizable.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Virtualizable.java	Mon May 13 17:11:31 2013 +0200
@@ -47,9 +47,9 @@
 
         public abstract ValueNode getEntry(int index);
 
-        public abstract int getLockCount();
+        public abstract void addLock(int depth);
 
-        public abstract void setLockCount(int lockCount);
+        public abstract int removeLock();
 
         public abstract ValueNode getMaterializedValue();
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java	Mon May 13 17:11:31 2013 +0200
@@ -64,9 +64,9 @@
      * 
      * @param virtualObject the new virtual object.
      * @param entryState the initial state of the virtual object's fields.
-     * @param lockCount the initial locking depth.
+     * @param locks the initial locking depths.
      */
-    void createVirtualObject(VirtualObjectNode virtualObject, ValueNode[] entryState, int lockCount);
+    void createVirtualObject(VirtualObjectNode virtualObject, ValueNode[] entryState, int[] locks);
 
     /**
      * Queries the current state of the given value: if it is virtualized (thread-local and the
@@ -138,12 +138,12 @@
     void replaceFirstInput(Node oldInput, Node replacement);
 
     /**
-     * Performs a custom action on the current node. This action will only be performed when, and
-     * if, the changes are committed. Custom actions must not modify inputs of nodes.
+     * Adds the given node to the graph.This action will only be performed when, and if, the changes
+     * are committed.
      * 
-     * @param action the custom action.
+     * @param node the node to add.
      */
-    void customAction(Runnable action);
+    void addNode(ValueNode node);
 
     /**
      * This method performs either {@link #replaceWithValue(ValueNode)} or
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/ComputeImmediateDominator.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/ComputeImmediateDominator.java	Mon May 13 17:11:31 2013 +0200
@@ -147,7 +147,7 @@
 
     private void processMerge(MergeNode merge, DominatorInfo info) {
         // TTY.println("processMerge(" + merge + ", " + info + ")");
-        for (EndNode end : merge.cfgPredecessors()) {
+        for (AbstractEndNode end : merge.cfgPredecessors()) {
             toExplore.add(end);
             infoMap.set(end, info.createChild(end));
             // TTY.println("  Enqueue end : " + end + " with " + infoMap.get(end));
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Mon May 13 17:11:31 2013 +0200
@@ -44,9 +44,9 @@
 
     public static void killCFG(FixedNode node) {
         assert node.isAlive();
-        if (node instanceof EndNode) {
+        if (node instanceof AbstractEndNode) {
             // We reached a control flow end.
-            EndNode end = (EndNode) node;
+            AbstractEndNode end = (AbstractEndNode) node;
             killEnd(end);
         } else {
             // Normal control flow node.
@@ -63,11 +63,11 @@
         propagateKill(node);
     }
 
-    private static void killEnd(EndNode end) {
+    private static void killEnd(AbstractEndNode end) {
         MergeNode merge = end.merge();
         if (merge != null) {
             merge.removeEnd(end);
-            StructuredGraph graph = (StructuredGraph) end.graph();
+            StructuredGraph graph = end.graph();
             if (merge instanceof LoopBeginNode && merge.forwardEndCount() == 0) { // dead loop
                 for (PhiNode phi : merge.phis().snapshot()) {
                     propagateKill(phi);
@@ -141,7 +141,7 @@
         if (singleValue != null) {
             Collection<PhiNode> phiUsages = phiNode.usages().filter(PhiNode.class).snapshot();
             Collection<ProxyNode> proxyUsages = phiNode.usages().filter(ProxyNode.class).snapshot();
-            ((StructuredGraph) phiNode.graph()).replaceFloating(phiNode, singleValue);
+            phiNode.graph().replaceFloating(phiNode, singleValue);
             for (PhiNode phi : phiUsages) {
                 checkRedundantPhi(phi);
             }
@@ -152,7 +152,7 @@
     }
 
     public static void checkRedundantProxy(ProxyNode vpn) {
-        BeginNode proxyPoint = vpn.proxyPoint();
+        AbstractBeginNode proxyPoint = vpn.proxyPoint();
         if (proxyPoint instanceof LoopExitNode) {
             LoopExitNode exit = (LoopExitNode) proxyPoint;
             LoopBeginNode loopBegin = exit.loopBegin();
@@ -165,7 +165,7 @@
                 if (vpnValue == v2) {
                     Collection<PhiNode> phiUsages = vpn.usages().filter(PhiNode.class).snapshot();
                     Collection<ProxyNode> proxyUsages = vpn.usages().filter(ProxyNode.class).snapshot();
-                    ((StructuredGraph) vpn.graph()).replaceFloating(vpn, vpnValue);
+                    vpn.graph().replaceFloating(vpn, vpnValue);
                     for (PhiNode phi : phiUsages) {
                         checkRedundantPhi(phi);
                     }
@@ -229,7 +229,7 @@
     public static RuntimeException approxSourceException(Node node, Throwable cause) {
         final StackTraceElement[] elements = approxSourceStackTraceElement(node);
         @SuppressWarnings("serial")
-        RuntimeException exception = new RuntimeException(cause.getMessage(), cause) {
+        RuntimeException exception = new RuntimeException((cause == null) ? null : cause.getMessage(), cause) {
 
             @Override
             public final synchronized Throwable fillInStackTrace() {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/NodesToDoubles.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/NodesToDoubles.java	Mon May 13 17:11:31 2013 +0200
@@ -35,6 +35,7 @@
     }
 
     public void put(FixedNode n, double value) {
+        assert value >= 0.0;
         nodeProbabilities.put(n, value);
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/AllocatedObjectNode.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,60 @@
+/*
+ * 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.virtual;
+
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+
+/**
+ * Selects one object from a {@link CommitAllocationNode}. The object is identified by its
+ * {@link VirtualObjectNode}.
+ */
+public class AllocatedObjectNode extends FloatingNode implements Virtualizable {
+
+    @Input private VirtualObjectNode virtualObject;
+    @Input private CommitAllocationNode commit;
+
+    public AllocatedObjectNode(VirtualObjectNode virtualObject) {
+        super(StampFactory.exactNonNull(virtualObject.type()));
+        this.virtualObject = virtualObject;
+    }
+
+    public VirtualObjectNode getVirtualObject() {
+        return virtualObject;
+    }
+
+    public CommitAllocationNode getCommit() {
+        return commit;
+    }
+
+    public void setCommit(CommitAllocationNode x) {
+        updateUsages(commit, x);
+        commit = x;
+    }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        tool.replaceWithVirtual(getVirtualObject());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/CommitAllocationNode.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,169 @@
+/*
+ * 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.virtual;
+
+import java.util.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+
+@NodeInfo(nameTemplate = "Alloc {i#virtualObjects}")
+public final class CommitAllocationNode extends FixedWithNextNode implements VirtualizableAllocation, Lowerable, Node.IterableNodeType, Simplifiable {
+
+    @Input private final NodeInputList<VirtualObjectNode> virtualObjects = new NodeInputList<>(this);
+    @Input private final NodeInputList<ValueNode> values = new NodeInputList<>(this);
+    private List<int[]> locks = new ArrayList<>();
+
+    public CommitAllocationNode() {
+        super(StampFactory.forVoid());
+    }
+
+    public List<VirtualObjectNode> getVirtualObjects() {
+        return virtualObjects;
+    }
+
+    public List<ValueNode> getValues() {
+        return values;
+    }
+
+    public List<int[]> getLocks() {
+        return locks;
+    }
+
+    @Override
+    public boolean verify() {
+        assertTrue(virtualObjects.size() == locks.size(), "lockCounts size doesn't match");
+        int valueCount = 0;
+        for (VirtualObjectNode virtual : virtualObjects) {
+            valueCount += virtual.entryCount();
+        }
+        assertTrue(values.size() == valueCount, "values size doesn't match");
+        return super.verify();
+    }
+
+    @Override
+    public void lower(LoweringTool tool, LoweringType loweringType) {
+        if (loweringType == LoweringType.AFTER_GUARDS) {
+            tool.getRuntime().lower(this, tool);
+        }
+    }
+
+    @Override
+    public Node clone(Graph into) {
+        CommitAllocationNode clone = (CommitAllocationNode) super.clone(into);
+        clone.locks = new ArrayList<>(locks);
+        return clone;
+    }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        int pos = 0;
+        for (int i = 0; i < virtualObjects.size(); i++) {
+            VirtualObjectNode virtualObject = virtualObjects.get(i);
+            int entryCount = virtualObject.entryCount();
+            tool.createVirtualObject(virtualObject, values.subList(pos, pos + entryCount).toArray(new ValueNode[entryCount]), locks.get(i));
+            pos += entryCount;
+        }
+        tool.delete();
+    }
+
+    @Override
+    public Map<Object, Object> getDebugProperties(Map<Object, Object> map) {
+        Map<Object, Object> properties = super.getDebugProperties(map);
+        int valuePos = 0;
+        for (int objIndex = 0; objIndex < virtualObjects.size(); objIndex++) {
+            VirtualObjectNode virtual = virtualObjects.get(objIndex);
+            StringBuilder s = new StringBuilder();
+            s.append(MetaUtil.toJavaName(virtual.type(), false)).append("[");
+            for (int i = 0; i < virtual.entryCount(); i++) {
+                ValueNode value = values.get(valuePos++);
+                s.append(i == 0 ? "" : ",").append(value == null ? "_" : value.toString(Verbosity.Id));
+            }
+            s.append("]");
+            if (locks.get(objIndex).length > 0) {
+                s.append(" locked(").append(Arrays.toString(locks.get(objIndex))).append(")");
+            }
+            properties.put("object(" + virtual.toString(Verbosity.Id) + ")", s.toString());
+        }
+        return properties;
+    }
+
+    @Override
+    public void simplify(SimplifierTool tool) {
+        boolean[] used = new boolean[virtualObjects.size()];
+        int usedCount = 0;
+        for (Node usage : usages()) {
+            AllocatedObjectNode addObject = (AllocatedObjectNode) usage;
+            int index = virtualObjects.indexOf(addObject.getVirtualObject());
+            assert !used[index];
+            used[index] = true;
+            usedCount++;
+        }
+        boolean progress;
+        do {
+            progress = false;
+            int valuePos = 0;
+            for (int objIndex = 0; objIndex < virtualObjects.size(); objIndex++) {
+                VirtualObjectNode virtualObject = virtualObjects.get(objIndex);
+                if (used[objIndex]) {
+                    for (int i = 0; i < virtualObject.entryCount(); i++) {
+                        int index = virtualObjects.indexOf(values.get(valuePos + i));
+                        if (index != -1 && !used[index]) {
+                            progress = true;
+                            used[index] = true;
+                            usedCount++;
+                        }
+                    }
+                }
+                valuePos += virtualObject.entryCount();
+            }
+
+        } while (progress);
+
+        if (usedCount < virtualObjects.size()) {
+            List<VirtualObjectNode> newVirtualObjects = new ArrayList<>(usedCount);
+            List<int[]> newLocks = new ArrayList<>(usedCount);
+            List<ValueNode> newValues = new ArrayList<>();
+            int valuePos = 0;
+            for (int objIndex = 0; objIndex < virtualObjects.size(); objIndex++) {
+                VirtualObjectNode virtualObject = virtualObjects.get(objIndex);
+                if (used[objIndex]) {
+                    newVirtualObjects.add(virtualObject);
+                    newLocks.add(locks.get(objIndex));
+                    newValues.addAll(values.subList(valuePos, valuePos + virtualObject.entryCount()));
+                }
+                valuePos += virtualObject.entryCount();
+            }
+            virtualObjects.clear();
+            virtualObjects.addAll(newVirtualObjects);
+            locks.clear();
+            locks.addAll(newLocks);
+            values.clear();
+            values.addAll(newValues);
+        }
+    }
+
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java	Mon May 13 17:11:31 2013 +0200
@@ -22,14 +22,11 @@
  */
 package com.oracle.graal.nodes.virtual;
 
-import java.util.*;
-
 import sun.misc.*;
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(nameTemplate = "VirtualArray {p#componentType/s}[{p#length}]")
@@ -72,7 +69,7 @@
     }
 
     @Override
-    public String fieldName(int index) {
+    public String entryName(int index) {
         return "[" + index + "]";
     }
 
@@ -143,17 +140,7 @@
     }
 
     @Override
-    public void materializeAt(FixedWithNextNode materializeNode, List<ValueNode> values, boolean defaultValuesOnly, int lockCount) {
-        StructuredGraph graph = (StructuredGraph) graph();
-        ResolvedJavaType element = componentType();
-        NewArrayNode newArray = graph.add(new NewArrayNode(element, ConstantNode.forInt(entryCount(), graph), defaultValuesOnly, lockCount > 0));
-        materializeNode.replaceAtUsages(newArray);
-        graph.addBeforeFixed(materializeNode, newArray);
-        if (!defaultValuesOnly) {
-            for (int i = 0; i < entryCount(); i++) {
-                graph.addBeforeFixed(materializeNode, graph.add(new StoreIndexedNode(newArray, ConstantNode.forInt(i, graph), element.getKind(), values.get(i))));
-            }
-        }
-        graph.removeFixed(materializeNode);
+    public ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, int[] locks) {
+        return new AllocatedObjectNode(this);
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualBoxingNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualBoxingNode.java	Mon May 13 17:11:31 2013 +0200
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.nodes.virtual;
 
-import java.util.*;
-
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
@@ -48,11 +46,9 @@
     }
 
     @Override
-    public void materializeAt(FixedWithNextNode materializeNode, List<ValueNode> values, boolean defaultValuesOnly, int lockCount) {
-        assert values.size() == 1;
-        assert lockCount == 0;
-        StructuredGraph graph = (StructuredGraph) graph();
-        BoxNode valueOf = graph.add(new BoxNode(values.get(0), type(), boxingKind));
-        graph.replaceFixedWithFixed(materializeNode, valueOf);
+    public ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, int[] locks) {
+        assert entries.length == 1;
+        assert locks.length == 0;
+        return new BoxNode(entries[0], type(), boxingKind);
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualInstanceNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualInstanceNode.java	Mon May 13 17:11:31 2013 +0200
@@ -22,14 +22,11 @@
  */
 package com.oracle.graal.nodes.virtual;
 
-import java.util.*;
-
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.java.*;
 
-@NodeInfo(nameTemplate = "VirtualInstance {p#type}")
+@NodeInfo(nameTemplate = "VirtualInstance {p#type/s}")
 public class VirtualInstanceNode extends VirtualObjectNode {
 
     private final ResolvedJavaType type;
@@ -68,7 +65,7 @@
     }
 
     @Override
-    public String fieldName(int index) {
+    public String entryName(int index) {
         return fields[index].getName();
     }
 
@@ -99,16 +96,7 @@
     }
 
     @Override
-    public void materializeAt(FixedWithNextNode materializeNode, List<ValueNode> values, boolean defaultValuesOnly, int lockCount) {
-        StructuredGraph graph = (StructuredGraph) graph();
-        NewInstanceNode newInstance = graph.add(new NewInstanceNode(type(), defaultValuesOnly, lockCount > 0));
-        materializeNode.replaceAtUsages(newInstance);
-        graph.addBeforeFixed(materializeNode, newInstance);
-        if (!defaultValuesOnly) {
-            for (int i = 0; i < entryCount(); i++) {
-                graph.addBeforeFixed(materializeNode, graph.add(new StoreFieldNode(newInstance, field(i), values.get(i))));
-            }
-        }
-        graph.removeFixed(materializeNode);
+    public ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, int[] locks) {
+        return new AllocatedObjectNode(this);
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java	Mon May 13 17:11:31 2013 +0200
@@ -22,41 +22,68 @@
  */
 package com.oracle.graal.nodes.virtual;
 
-import java.util.*;
-
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
-@NodeInfo(nameTemplate = "VirtualObject {p#type}")
 public abstract class VirtualObjectNode extends ValueNode implements LIRLowerable {
 
     public VirtualObjectNode() {
         super(StampFactory.virtual());
     }
 
+    /**
+     * The type of object described by this {@link VirtualObjectNode}. In case of arrays, this is
+     * the array type (and not the component type).
+     */
     public abstract ResolvedJavaType type();
 
+    /**
+     * The number of entries this virtual object has. Either the number of fields or the number of
+     * array elements.
+     */
     public abstract int entryCount();
 
+    /**
+     * Returns the name of the entry at the given index. Only used for debugging purposes.
+     */
+    public abstract String entryName(int i);
+
+    /**
+     * If the given index denotes an entry in this virtual object, the index of this entry is
+     * returned. If no such entry can be found, this method returns -1.
+     */
+    public abstract int entryIndexForOffset(long constantOffset);
+
+    /**
+     * Returns the {@link Kind} of the entry at the given index.
+     */
+    public abstract Kind entryKind(int index);
+
+    /**
+     * Returns an exact duplicate of this virtual object node, which has not been added to the graph
+     * yet.
+     */
+    public abstract VirtualObjectNode duplicate();
+
+    /**
+     * Specifies whether this virtual object has an object identity. If not, then the result of a
+     * comparison of two virtual objects is determined by comparing their contents.
+     */
+    public boolean hasIdentity() {
+        return true;
+    }
+
+    /**
+     * Returns a node that can be used to materialize this virtual object. If this returns an
+     * {@link AllocatedObjectNode} then this node will be attached to a {@link CommitAllocationNode}
+     * , otherwise the node will just be added to the graph.
+     */
+    public abstract ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, int[] locks);
+
     @Override
     public void generate(LIRGeneratorTool gen) {
         // nothing to do...
     }
-
-    public abstract String fieldName(int i);
-
-    public abstract void materializeAt(FixedWithNextNode materializeNode, List<ValueNode> values, boolean defaultValuesOnly, int lockCount);
-
-    public abstract int entryIndexForOffset(long constantOffset);
-
-    public abstract Kind entryKind(int index);
-
-    public abstract VirtualObjectNode duplicate();
-
-    public boolean hasIdentity() {
-        return true;
-    }
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Mon May 13 17:11:31 2013 +0200
@@ -22,14 +22,13 @@
  */
 package com.oracle.graal.phases.common;
 
-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.graph.*;
-import com.oracle.graal.graph.Graph.InputChangedListener;
+import com.oracle.graal.graph.Graph.NodeChangedListener;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
@@ -49,6 +48,7 @@
     public static final DebugMetric METRIC_GLOBAL_VALUE_NUMBERING_HITS = Debug.metric("GlobalValueNumberingHits");
 
     private final CustomCanonicalizer customCanonicalizer;
+    private final Iterable<Node> workingSet;
 
     public interface CustomCanonicalizer {
 
@@ -60,12 +60,17 @@
     }
 
     public CanonicalizerPhase(CustomCanonicalizer customCanonicalizer) {
+        this(customCanonicalizer, null);
+    }
+
+    public CanonicalizerPhase(CustomCanonicalizer customCanonicalizer, Iterable<Node> workingSet) {
         this.customCanonicalizer = customCanonicalizer;
+        this.workingSet = workingSet;
     }
 
     @Override
     protected void run(StructuredGraph graph, PhaseContext context) {
-        new Instance(context.getRuntime(), context.getAssumptions(), null, customCanonicalizer).run(graph);
+        new Instance(context.getRuntime(), context.getAssumptions(), workingSet, customCanonicalizer).run(graph);
     }
 
     public static class Instance extends Phase {
@@ -78,7 +83,6 @@
 
         private NodeWorkList workList;
         private Tool tool;
-        private List<Node> snapshotTemp;
 
         public Instance(MetaAccessProvider runtime, Assumptions assumptions) {
             this(runtime, assumptions, null, 0, null);
@@ -110,7 +114,6 @@
             this.runtime = runtime;
             this.customCanonicalizer = customCanonicalizer;
             this.initWorkingSet = workingSet;
-            this.snapshotTemp = new ArrayList<>();
         }
 
         @Override
@@ -129,19 +132,22 @@
         }
 
         private void processWorkSet(StructuredGraph graph) {
-            graph.trackInputChange(new InputChangedListener() {
+            NodeChangedListener nodeChangedListener = new NodeChangedListener() {
 
                 @Override
-                public void inputChanged(Node node) {
+                public void nodeChanged(Node node) {
                     workList.addAgain(node);
                 }
-            });
+            };
+            graph.trackInputChange(nodeChangedListener);
+            graph.trackUsagesDroppedZero(nodeChangedListener);
 
             for (Node n : workList) {
                 processNode(n, graph);
             }
 
             graph.stopTrackingInputChange();
+            graph.stopTrackingUsagesDroppedZero();
         }
 
         private void processNode(Node node, StructuredGraph graph) {
@@ -153,17 +159,9 @@
                 }
                 int mark = graph.getMark();
                 if (!tryKillUnused(node)) {
-                    node.inputs().filter(GraphUtil.isFloatingNode()).snapshotTo(snapshotTemp);
                     if (!tryCanonicalize(node, graph)) {
                         tryInferStamp(node, graph);
-                    } else {
-                        for (Node in : snapshotTemp) {
-                            if (in.isAlive() && in.usages().isEmpty()) {
-                                GraphUtil.killWithUnusedFloatingInputs(in);
-                            }
-                        }
                     }
-                    snapshotTemp.clear();
                 }
 
                 for (Node newNode : graph.getNewNodes(mark)) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java	Mon May 13 17:11:31 2013 +0200
@@ -213,7 +213,7 @@
         }
 
         @Override
-        public void afterSplit(BeginNode node) {
+        public void afterSplit(AbstractBeginNode node) {
         }
 
         @Override
@@ -355,7 +355,7 @@
             }
         }
 
-        private void registerControlSplitInfo(Node pred, BeginNode begin) {
+        private void registerControlSplitInfo(Node pred, AbstractBeginNode begin) {
             assert pred != null && begin != null;
 
             if (pred instanceof IfNode) {
@@ -461,8 +461,8 @@
 
         @Override
         protected void node(FixedNode node) {
-            if (node instanceof BeginNode) {
-                BeginNode begin = (BeginNode) node;
+            if (node instanceof AbstractBeginNode) {
+                AbstractBeginNode begin = (AbstractBeginNode) node;
                 Node pred = node.predecessor();
 
                 if (pred != null) {
@@ -501,8 +501,8 @@
                         GraphUtil.killWithUnusedFloatingInputs(compare);
                     }
                 }
-            } else if (node instanceof EndNode) {
-                EndNode endNode = (EndNode) node;
+            } else if (node instanceof AbstractEndNode) {
+                AbstractEndNode endNode = (AbstractEndNode) node;
                 for (PhiNode phi : endNode.merge().phis()) {
                     int index = endNode.merge().phiPredecessorIndex(endNode);
                     ValueNode value = phi.valueAt(index);
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertDeoptimizeToGuardPhase.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertDeoptimizeToGuardPhase.java	Mon May 13 17:11:31 2013 +0200
@@ -27,17 +27,16 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.*;
 
 public class ConvertDeoptimizeToGuardPhase extends Phase {
 
-    private static BeginNode findBeginNode(Node startNode) {
+    private static AbstractBeginNode findBeginNode(Node startNode) {
         Node n = startNode;
         while (true) {
-            if (n instanceof BeginNode) {
-                return (BeginNode) n;
+            if (n instanceof AbstractBeginNode) {
+                return (AbstractBeginNode) n;
             } else {
                 n = n.predecessor();
             }
@@ -58,17 +57,17 @@
         new DeadCodeEliminationPhase().apply(graph);
     }
 
-    private void visitDeoptBegin(BeginNode deoptBegin, DeoptimizeNode deopt, StructuredGraph graph) {
+    private void visitDeoptBegin(AbstractBeginNode deoptBegin, DeoptimizeNode deopt, StructuredGraph graph) {
         if (deoptBegin instanceof MergeNode) {
             MergeNode mergeNode = (MergeNode) deoptBegin;
             Debug.log("Visiting %s followed by %s", mergeNode, deopt);
-            List<BeginNode> begins = new ArrayList<>();
-            for (EndNode end : mergeNode.forwardEnds()) {
-                BeginNode newBeginNode = findBeginNode(end);
+            List<AbstractBeginNode> begins = new ArrayList<>();
+            for (AbstractEndNode end : mergeNode.forwardEnds()) {
+                AbstractBeginNode newBeginNode = findBeginNode(end);
                 assert !begins.contains(newBeginNode);
                 begins.add(newBeginNode);
             }
-            for (BeginNode begin : begins) {
+            for (AbstractBeginNode begin : begins) {
                 assert !begin.isDeleted();
                 visitDeoptBegin(begin, deopt, graph);
             }
@@ -76,24 +75,20 @@
             return;
         } else if (deoptBegin.predecessor() instanceof IfNode) {
             IfNode ifNode = (IfNode) deoptBegin.predecessor();
-            BeginNode otherBegin = ifNode.trueSuccessor();
+            AbstractBeginNode otherBegin = ifNode.trueSuccessor();
             LogicNode conditionNode = ifNode.condition();
-            if (!(conditionNode instanceof InstanceOfNode) && !(conditionNode instanceof InstanceOfDynamicNode)) {
-                // TODO The lowering currently does not support a FixedGuard as the usage of an
-                // InstanceOfNode. Relax this restriction.
-                FixedGuardNode guard = graph.add(new FixedGuardNode(conditionNode, deopt.reason(), deopt.action(), deoptBegin == ifNode.trueSuccessor()));
-                FixedWithNextNode pred = (FixedWithNextNode) ifNode.predecessor();
-                if (deoptBegin == ifNode.trueSuccessor()) {
-                    graph.removeSplitPropagate(ifNode, ifNode.falseSuccessor());
-                } else {
-                    graph.removeSplitPropagate(ifNode, ifNode.trueSuccessor());
-                }
-                Debug.log("Converting %s on %-5s branch of %s to guard for remaining branch %s.", deopt, deoptBegin == ifNode.trueSuccessor() ? "true" : "false", ifNode, otherBegin);
-                FixedNode next = pred.next();
-                pred.setNext(guard);
-                guard.setNext(next);
-                return;
+            FixedGuardNode guard = graph.add(new FixedGuardNode(conditionNode, deopt.reason(), deopt.action(), deoptBegin == ifNode.trueSuccessor()));
+            FixedWithNextNode pred = (FixedWithNextNode) ifNode.predecessor();
+            if (deoptBegin == ifNode.trueSuccessor()) {
+                graph.removeSplitPropagate(ifNode, ifNode.falseSuccessor());
+            } else {
+                graph.removeSplitPropagate(ifNode, ifNode.trueSuccessor());
             }
+            Debug.log("Converting %s on %-5s branch of %s to guard for remaining branch %s.", deopt, deoptBegin == ifNode.trueSuccessor() ? "true" : "false", ifNode, otherBegin);
+            FixedNode next = pred.next();
+            pred.setNext(guard);
+            guard.setNext(next);
+            return;
         }
 
         // We could not convert the control split - at least cut off control flow after the split.
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CullFrameStatesPhase.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CullFrameStatesPhase.java	Mon May 13 17:11:31 2013 +0200
@@ -90,7 +90,7 @@
         }
 
         @Override
-        public void afterSplit(BeginNode node) {
+        public void afterSplit(AbstractBeginNode node) {
         }
 
         @Override
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeadCodeEliminationPhase.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeadCodeEliminationPhase.java	Mon May 13 17:11:31 2013 +0200
@@ -52,8 +52,8 @@
 
     private static void iterateSuccessors(NodeFlood flood) {
         for (Node current : flood) {
-            if (current instanceof EndNode) {
-                EndNode end = (EndNode) current;
+            if (current instanceof AbstractEndNode) {
+                AbstractEndNode end = (AbstractEndNode) current;
                 flood.add(end.merge());
             } else {
                 for (Node successor : current.successors()) {
@@ -64,7 +64,7 @@
     }
 
     private static void disconnectCFGNodes(NodeFlood flood, StructuredGraph graph) {
-        for (EndNode node : graph.getNodes(EndNode.class)) {
+        for (AbstractEndNode node : graph.getNodes(AbstractEndNode.class)) {
             if (!flood.isMarked(node)) {
                 MergeNode merge = node.merge();
                 if (merge != null && flood.isMarked(merge)) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/EliminatePartiallyRedundantGuardsPhase.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/EliminatePartiallyRedundantGuardsPhase.java	Mon May 13 17:11:31 2013 +0200
@@ -116,16 +116,10 @@
         }
         Collection<GuardNode> hits = new LinkedList<>();
         for (GuardNode guard : merge.guards()) {
-            if (guard.dependencies().size() != 1) {
-                continue;
-            }
-            for (EndNode end : merge.forwardEnds()) {
-                BeginNode begin = BeginNode.prevBegin(end);
+            for (AbstractEndNode end : merge.forwardEnds()) {
+                AbstractBeginNode begin = AbstractBeginNode.prevBegin(end);
                 boolean found = false;
                 for (GuardNode predecessorGuard : begin.guards()) {
-                    if (predecessorGuard.dependencies().size() != 1) {
-                        continue;
-                    }
                     if (guard.condition() == predecessorGuard.condition() && guard.negated() == predecessorGuard.negated()) {
                         hits.add(guard);
                         found = true;
@@ -140,8 +134,8 @@
         Graph graph = merge.graph();
         for (GuardNode guard : hits) {
             PhiNode phi = graph.add(new PhiNode(PhiType.Guard, merge, null));
-            for (EndNode otherEnd : merge.forwardEnds()) {
-                phi.addInput(graph.unique(new GuardNode(guard.condition(), BeginNode.prevBegin(otherEnd), guard.reason(), guard.action(), guard.negated())));
+            for (AbstractEndNode otherEnd : merge.forwardEnds()) {
+                phi.addInput(graph.unique(new GuardNode(guard.condition(), AbstractBeginNode.prevBegin(otherEnd), guard.reason(), guard.action(), guard.negated())));
             }
             guard.replaceAndDelete(phi);
             metricPRGuardsEliminatedAtMerge.increment();
@@ -152,11 +146,8 @@
     private static boolean eliminateAtControlSplit(ControlSplitNode controlSplit) {
         Map<Condition, Collection<GuardNode>> conditionToGuard = new HashMap<>();
         for (Node successor : controlSplit.successors()) {
-            BeginNode begin = (BeginNode) successor;
+            AbstractBeginNode begin = (AbstractBeginNode) successor;
             for (GuardNode guard : begin.guards()) {
-                if (guard.dependencies().size() != 1) {
-                    continue;
-                }
                 Condition condition = new Condition(guard.condition(), guard.negated());
                 Collection<GuardNode> guards = conditionToGuard.get(condition);
                 if (guards == null) {
@@ -175,9 +166,9 @@
             }
             DeoptimizationReason reason = null;
             DeoptimizationAction action = DeoptimizationAction.None;
-            Set<BeginNode> begins = new HashSet<>(3);
+            Set<AbstractBeginNode> begins = new HashSet<>(3);
             for (GuardNode guard : guards) {
-                BeginNode begin = (BeginNode) guard.dependencies().first();
+                AbstractBeginNode begin = (AbstractBeginNode) guard.getGuard();
                 begins.add(begin);
                 if (guard.action().ordinal() > action.ordinal()) {
                     action = guard.action();
@@ -191,7 +182,7 @@
             if (begins.size() == controlSplit.successors().count()) {
                 hits = true;
                 Condition condition = entry.getKey();
-                GuardNode newGuard = controlSplit.graph().unique(new GuardNode(condition.conditionNode, BeginNode.prevBegin(controlSplit), reason, action, condition.negated));
+                GuardNode newGuard = controlSplit.graph().unique(new GuardNode(condition.conditionNode, AbstractBeginNode.prevBegin(controlSplit), reason, action, condition.negated));
                 for (GuardNode guard : guards) {
                     guard.replaceAndDelete(newGuard);
                     metricPRGuardsEliminatedAtSplit.increment();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ExpandLogicPhase.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,96 @@
+/*
+ * 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.phases.common;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.phases.*;
+
+public class ExpandLogicPhase extends Phase {
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        for (LogicBinaryNode logic : graph.getNodes(LogicBinaryNode.class)) {
+            processBinary(logic);
+        }
+        assert graph.getNodes(LogicBinaryNode.class).isEmpty();
+    }
+
+    private static void processBinary(LogicBinaryNode binary) {
+        while (binary.usages().isNotEmpty()) {
+            Node usage = binary.usages().first();
+            if (usage instanceof LogicBinaryNode) {
+                processBinary((LogicBinaryNode) usage);
+            } else if (usage instanceof IfNode) {
+                if (binary instanceof LogicConjunctionNode) {
+                    processIf(binary.getX(), binary.isXNegated(), binary.getY(), binary.isYNegated(), (IfNode) usage, false);
+                } else if (binary instanceof LogicDisjunctionNode) {
+                    processIf(binary.getX(), !binary.isXNegated(), binary.getY(), !binary.isYNegated(), (IfNode) usage, true);
+                } else {
+                    throw GraalInternalError.shouldNotReachHere();
+                }
+            } else if (usage instanceof ConditionalNode) {
+                if (binary instanceof LogicConjunctionNode) {
+                    processConditional(binary.getX(), binary.isXNegated(), binary.getY(), binary.isYNegated(), (ConditionalNode) usage, false);
+                } else if (binary instanceof LogicDisjunctionNode) {
+                    processConditional(binary.getX(), !binary.isXNegated(), binary.getY(), !binary.isYNegated(), (ConditionalNode) usage, true);
+                } else {
+                    throw GraalInternalError.shouldNotReachHere();
+                }
+            } else {
+                throw GraalInternalError.shouldNotReachHere();
+            }
+        }
+        binary.safeDelete();
+    }
+
+    private static void processIf(LogicNode x, boolean xNegated, LogicNode y, boolean yNegated, IfNode ifNode, boolean negateTargets) {
+        AbstractBeginNode trueTarget = negateTargets ? ifNode.falseSuccessor() : ifNode.trueSuccessor();
+        AbstractBeginNode falseTarget = negateTargets ? ifNode.trueSuccessor() : ifNode.falseSuccessor();
+        double p = Math.sqrt(ifNode.probability(trueTarget));
+        ifNode.clearSuccessors();
+        Graph graph = ifNode.graph();
+        MergeNode falseTargetMerge = graph.add(new MergeNode());
+        falseTargetMerge.setNext(falseTarget);
+        EndNode firstFalseEnd = graph.add(new EndNode());
+        EndNode secondFalseEnd = graph.add(new EndNode());
+        falseTargetMerge.addForwardEnd(firstFalseEnd);
+        falseTargetMerge.addForwardEnd(secondFalseEnd);
+        AbstractBeginNode firstFalseTarget = AbstractBeginNode.begin(firstFalseEnd);
+        AbstractBeginNode secondFalseTarget = AbstractBeginNode.begin(secondFalseEnd);
+        AbstractBeginNode secondIf = AbstractBeginNode.begin(graph.add(new IfNode(y, yNegated ? firstFalseTarget : trueTarget, yNegated ? trueTarget : firstFalseTarget, yNegated ? 1 - p : p)));
+        IfNode firstIf = graph.add(new IfNode(x, xNegated ? secondFalseTarget : secondIf, xNegated ? secondIf : secondFalseTarget, xNegated ? 1 - p : p));
+        ifNode.replaceAtPredecessor(firstIf);
+        ifNode.safeDelete();
+    }
+
+    private static void processConditional(LogicNode x, boolean xNegated, LogicNode y, boolean yNegated, ConditionalNode conditional, boolean negateTargets) {
+        ValueNode trueTarget = negateTargets ? conditional.falseValue() : conditional.trueValue();
+        ValueNode falseTarget = negateTargets ? conditional.trueValue() : conditional.falseValue();
+        Graph graph = conditional.graph();
+        ConditionalNode secondConditional = graph.unique(new ConditionalNode(y, yNegated ? falseTarget : trueTarget, yNegated ? trueTarget : falseTarget));
+        ConditionalNode firstConditional = graph.unique(new ConditionalNode(x, xNegated ? falseTarget : secondConditional, xNegated ? secondConditional : falseTarget));
+        conditional.replaceAndDelete(firstConditional);
+    }
+}
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java	Mon May 13 17:11:31 2013 +0200
@@ -27,6 +27,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.PhiNode.PhiType;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.graph.*;
 import com.oracle.graal.phases.graph.ReentrantNodeIterator.LoopInfo;
@@ -36,7 +37,7 @@
 
     private static class MemoryMap {
 
-        private IdentityHashMap<Object, ValueNode> lastMemorySnapshot;
+        private IdentityHashMap<LocationIdentity, ValueNode> lastMemorySnapshot;
 
         public MemoryMap(MemoryMap memoryMap) {
             lastMemorySnapshot = new IdentityHashMap<>(memoryMap.lastMemorySnapshot);
@@ -51,7 +52,7 @@
             lastMemorySnapshot = new IdentityHashMap<>();
         }
 
-        private ValueNode getLastLocationAccess(Object locationIdentity) {
+        private ValueNode getLastLocationAccess(LocationIdentity locationIdentity) {
             ValueNode lastLocationAccess;
             if (locationIdentity == LocationNode.FINAL_LOCATION) {
                 return null;
@@ -73,50 +74,51 @@
 
     @Override
     protected void run(StructuredGraph graph) {
-        Map<LoopBeginNode, Set<Object>> modifiedInLoops = new IdentityHashMap<>();
-        ReentrantNodeIterator.apply(new CollectMemoryCheckpointsClosure(modifiedInLoops), graph.start(), new HashSet<>(), null);
+        Map<LoopBeginNode, Set<LocationIdentity>> modifiedInLoops = new IdentityHashMap<>();
+        ReentrantNodeIterator.apply(new CollectMemoryCheckpointsClosure(modifiedInLoops), graph.start(), new HashSet<LocationIdentity>(), null);
         ReentrantNodeIterator.apply(new FloatingReadClosure(modifiedInLoops), graph.start(), new MemoryMap(graph.start()), null);
     }
 
-    private static class CollectMemoryCheckpointsClosure extends NodeIteratorClosure<Set<Object>> {
+    private static class CollectMemoryCheckpointsClosure extends NodeIteratorClosure<Set<LocationIdentity>> {
 
-        private final Map<LoopBeginNode, Set<Object>> modifiedInLoops;
+        private final Map<LoopBeginNode, Set<LocationIdentity>> modifiedInLoops;
 
-        public CollectMemoryCheckpointsClosure(Map<LoopBeginNode, Set<Object>> modifiedInLoops) {
+        public CollectMemoryCheckpointsClosure(Map<LoopBeginNode, Set<LocationIdentity>> modifiedInLoops) {
             this.modifiedInLoops = modifiedInLoops;
         }
 
         @Override
-        protected void processNode(FixedNode node, Set<Object> currentState) {
+        protected Set<LocationIdentity> processNode(FixedNode node, Set<LocationIdentity> currentState) {
             if (node instanceof MemoryCheckpoint) {
-                for (Object identity : ((MemoryCheckpoint) node).getLocationIdentities()) {
+                for (LocationIdentity identity : ((MemoryCheckpoint) node).getLocationIdentities()) {
                     currentState.add(identity);
                 }
             }
+            return currentState;
         }
 
         @Override
-        protected Set<Object> merge(MergeNode merge, List<Set<Object>> states) {
-            Set<Object> result = new HashSet<>();
-            for (Set<Object> other : states) {
+        protected Set<LocationIdentity> merge(MergeNode merge, List<Set<LocationIdentity>> states) {
+            Set<LocationIdentity> result = new HashSet<>();
+            for (Set<LocationIdentity> other : states) {
                 result.addAll(other);
             }
             return result;
         }
 
         @Override
-        protected Set<Object> afterSplit(BeginNode node, Set<Object> oldState) {
+        protected Set<LocationIdentity> afterSplit(AbstractBeginNode node, Set<LocationIdentity> oldState) {
             return new HashSet<>(oldState);
         }
 
         @Override
-        protected Map<LoopExitNode, Set<Object>> processLoop(LoopBeginNode loop, Set<Object> initialState) {
-            LoopInfo<Set<Object>> loopInfo = ReentrantNodeIterator.processLoop(this, loop, new HashSet<>());
-            Set<Object> modifiedLocations = new HashSet<>();
-            for (Set<Object> end : loopInfo.endStates.values()) {
+        protected Map<LoopExitNode, Set<LocationIdentity>> processLoop(LoopBeginNode loop, Set<LocationIdentity> initialState) {
+            LoopInfo<Set<LocationIdentity>> loopInfo = ReentrantNodeIterator.processLoop(this, loop, new HashSet<LocationIdentity>());
+            Set<LocationIdentity> modifiedLocations = new HashSet<>();
+            for (Set<LocationIdentity> end : loopInfo.endStates.values()) {
                 modifiedLocations.addAll(end);
             }
-            for (Set<Object> exit : loopInfo.exitStates.values()) {
+            for (Set<LocationIdentity> exit : loopInfo.exitStates.values()) {
                 exit.addAll(modifiedLocations);
                 exit.addAll(initialState);
             }
@@ -129,23 +131,24 @@
 
     private static class FloatingReadClosure extends NodeIteratorClosure<MemoryMap> {
 
-        private final Map<LoopBeginNode, Set<Object>> modifiedInLoops;
+        private final Map<LoopBeginNode, Set<LocationIdentity>> modifiedInLoops;
 
-        public FloatingReadClosure(Map<LoopBeginNode, Set<Object>> modifiedInLoops) {
+        public FloatingReadClosure(Map<LoopBeginNode, Set<LocationIdentity>> modifiedInLoops) {
             this.modifiedInLoops = modifiedInLoops;
         }
 
         @Override
-        protected void processNode(FixedNode node, MemoryMap state) {
+        protected MemoryMap processNode(FixedNode node, MemoryMap state) {
             if (node instanceof FloatableAccessNode) {
                 processFloatable((FloatableAccessNode) node, state);
             } else if (node instanceof MemoryCheckpoint) {
                 processCheckpoint((MemoryCheckpoint) node, state);
             }
+            return state;
         }
 
         private static void processCheckpoint(MemoryCheckpoint checkpoint, MemoryMap state) {
-            for (Object identity : checkpoint.getLocationIdentities()) {
+            for (LocationIdentity identity : checkpoint.getLocationIdentities()) {
                 if (identity == LocationNode.ANY_LOCATION) {
                     state.lastMemorySnapshot.clear();
                 }
@@ -154,20 +157,18 @@
         }
 
         private static void processFloatable(FloatableAccessNode accessNode, MemoryMap state) {
-            StructuredGraph graph = (StructuredGraph) accessNode.graph();
+            StructuredGraph graph = accessNode.graph();
             assert accessNode.getNullCheck() == false;
-            Object locationIdentity = accessNode.location().locationIdentity();
+            LocationIdentity locationIdentity = accessNode.location().getLocationIdentity();
             if (locationIdentity != LocationNode.ANY_LOCATION) {
                 ValueNode lastLocationAccess = state.getLastLocationAccess(locationIdentity);
                 FloatingAccessNode floatingNode = accessNode.asFloatingNode(lastLocationAccess);
                 floatingNode.setNullCheck(accessNode.getNullCheck());
                 ValueAnchorNode anchor = null;
-                for (GuardNode guard : accessNode.dependencies().filter(GuardNode.class)) {
-                    if (anchor == null) {
-                        anchor = graph.add(new ValueAnchorNode());
-                        graph.addAfterFixed(accessNode, anchor);
-                    }
-                    anchor.addAnchoredNode(guard);
+                GuardingNode guard = accessNode.getGuard();
+                if (guard != null) {
+                    anchor = graph.add(new ValueAnchorNode(guard.asNode()));
+                    graph.addAfterFixed(accessNode, anchor);
                 }
                 graph.replaceFixedWithFloating(accessNode, floatingNode);
             }
@@ -177,13 +178,13 @@
         protected MemoryMap merge(MergeNode merge, List<MemoryMap> states) {
             MemoryMap newState = new MemoryMap();
 
-            Set<Object> keys = new HashSet<>();
+            Set<LocationIdentity> keys = new HashSet<>();
             for (MemoryMap other : states) {
                 keys.addAll(other.lastMemorySnapshot.keySet());
             }
             assert !keys.contains(LocationNode.FINAL_LOCATION);
 
-            for (Object key : keys) {
+            for (LocationIdentity key : keys) {
                 int mergedStatesCount = 0;
                 boolean isPhi = false;
                 ValueNode merged = null;
@@ -214,7 +215,7 @@
         }
 
         @Override
-        protected MemoryMap afterSplit(BeginNode node, MemoryMap oldState) {
+        protected MemoryMap afterSplit(AbstractBeginNode node, MemoryMap oldState) {
             MemoryMap result = new MemoryMap(oldState);
             if (node.predecessor() instanceof InvokeWithExceptionNode) {
                 /*
@@ -225,7 +226,7 @@
                  * needs to choose by putting in the location identity on both successors.
                  */
                 InvokeWithExceptionNode checkpoint = (InvokeWithExceptionNode) node.predecessor();
-                for (Object identity : checkpoint.getLocationIdentities()) {
+                for (LocationIdentity identity : checkpoint.getLocationIdentities()) {
                     result.lastMemorySnapshot.put(identity, node);
                 }
             }
@@ -234,15 +235,15 @@
 
         @Override
         protected Map<LoopExitNode, MemoryMap> processLoop(LoopBeginNode loop, MemoryMap initialState) {
-            Set<Object> modifiedLocations = modifiedInLoops.get(loop);
+            Set<LocationIdentity> modifiedLocations = modifiedInLoops.get(loop);
             if (modifiedLocations.contains(LocationNode.ANY_LOCATION)) {
                 // create phis for all locations if ANY is modified in the loop
                 modifiedLocations = new HashSet<>(modifiedLocations);
                 modifiedLocations.addAll(initialState.lastMemorySnapshot.keySet());
             }
 
-            Map<Object, PhiNode> phis = new HashMap<>();
-            for (Object location : modifiedLocations) {
+            Map<LocationIdentity, PhiNode> phis = new HashMap<>();
+            for (LocationIdentity location : modifiedLocations) {
                 PhiNode phi = loop.graph().add(new PhiNode(PhiType.Memory, loop, location));
                 phi.addInput(initialState.getLastLocationAccess(location));
                 phis.put(location, phi);
@@ -253,8 +254,8 @@
 
             for (Map.Entry<LoopEndNode, MemoryMap> entry : loopInfo.endStates.entrySet()) {
                 int endIndex = loop.phiPredecessorIndex(entry.getKey());
-                for (Map.Entry<Object, PhiNode> phiEntry : phis.entrySet()) {
-                    Object key = phiEntry.getKey();
+                for (Map.Entry<LocationIdentity, PhiNode> phiEntry : phis.entrySet()) {
+                    LocationIdentity key = phiEntry.getKey();
                     PhiNode phi = phiEntry.getValue();
                     phi.initializeValueAt(endIndex, entry.getValue().getLastLocationAccess(key));
                 }
@@ -262,10 +263,10 @@
             for (Map.Entry<LoopExitNode, MemoryMap> entry : loopInfo.exitStates.entrySet()) {
                 LoopExitNode exit = entry.getKey();
                 MemoryMap state = entry.getValue();
-                for (Object location : modifiedLocations) {
+                for (LocationIdentity location : modifiedLocations) {
                     ValueNode lastAccessAtExit = state.lastMemorySnapshot.get(location);
                     if (lastAccessAtExit != null) {
-                        state.lastMemorySnapshot.put(location, ProxyNode.forMemory(lastAccessAtExit, exit, location, (StructuredGraph) loop.graph()));
+                        state.lastMemorySnapshot.put(location, ProxyNode.forMemory(lastAccessAtExit, exit, location, loop.graph()));
                     }
                 }
             }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FrameStateAssignmentPhase.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FrameStateAssignmentPhase.java	Mon May 13 17:11:31 2013 +0200
@@ -27,83 +27,51 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.graph.*;
-import com.oracle.graal.phases.graph.ReentrantBlockIterator.BlockIteratorClosure;
+import com.oracle.graal.phases.graph.ReentrantNodeIterator.NodeIteratorClosure;
 
 public class FrameStateAssignmentPhase extends Phase {
 
-    private static class FrameStateAssignmentState {
-
-        private FrameState framestate;
-
-        public FrameStateAssignmentState(FrameState framestate) {
-            this.framestate = framestate;
-        }
+    private static class FrameStateAssignementClosure extends NodeIteratorClosure<FrameState> {
 
-        public FrameState getFramestate() {
-            return framestate;
-        }
+        @Override
+        protected FrameState processNode(FixedNode node, FrameState currentState) {
+            if (node instanceof DeoptimizingNode) {
+                DeoptimizingNode deopt = (DeoptimizingNode) node;
+                if (deopt.canDeoptimize() && deopt.getDeoptimizationState() == null) {
+                    deopt.setDeoptimizationState(currentState);
+                }
+            }
 
-        public void setFramestate(FrameState framestate) {
-            assert framestate != null;
-            this.framestate = framestate;
+            if (node instanceof StateSplit) {
+                StateSplit stateSplit = (StateSplit) node;
+                if (stateSplit.stateAfter() != null) {
+                    FrameState newState = stateSplit.stateAfter();
+                    stateSplit.setStateAfter(null);
+                    return newState;
+                }
+            }
+            return currentState;
         }
 
         @Override
-        public String toString() {
-            return "FrameStateAssignementState: " + framestate;
-        }
-    }
-
-    private static class FrameStateAssignementClosure extends BlockIteratorClosure<FrameStateAssignmentState> {
-
-        @Override
-        protected void processBlock(Block block, FrameStateAssignmentState currentState) {
-            FixedNode node = block.getBeginNode();
-            while (node != null) {
-                if (node instanceof DeoptimizingNode) {
-                    DeoptimizingNode deopt = (DeoptimizingNode) node;
-                    if (deopt.canDeoptimize() && deopt.getDeoptimizationState() == null) {
-                        deopt.setDeoptimizationState(currentState.getFramestate());
-                    }
-                }
-
-                if (node instanceof StateSplit) {
-                    StateSplit stateSplit = (StateSplit) node;
-                    if (stateSplit.stateAfter() != null) {
-                        currentState.setFramestate(stateSplit.stateAfter());
-                        stateSplit.setStateAfter(null);
-                    }
-                }
-
-                if (node instanceof FixedWithNextNode) {
-                    node = ((FixedWithNextNode) node).next();
-                } else {
-                    node = null;
-                }
+        protected FrameState merge(MergeNode merge, List<FrameState> states) {
+            if (merge.stateAfter() != null) {
+                return merge.stateAfter();
             }
+            return singleFrameState(merge, states);
         }
 
         @Override
-        protected FrameStateAssignmentState merge(Block mergeBlock, List<FrameStateAssignmentState> states) {
-            MergeNode merge = (MergeNode) mergeBlock.getBeginNode();
-            if (merge.stateAfter() != null) {
-                return new FrameStateAssignmentState(merge.stateAfter());
-            }
-            return new FrameStateAssignmentState(singleFrameState(states));
+        protected FrameState afterSplit(AbstractBeginNode node, FrameState oldState) {
+            return oldState;
         }
 
         @Override
-        protected FrameStateAssignmentState cloneState(FrameStateAssignmentState oldState) {
-            return new FrameStateAssignmentState(oldState.getFramestate());
-        }
-
-        @Override
-        protected List<FrameStateAssignmentState> processLoop(Loop loop, FrameStateAssignmentState initialState) {
-            return ReentrantBlockIterator.processLoop(this, loop, initialState).exitStates;
+        protected Map<LoopExitNode, FrameState> processLoop(LoopBeginNode loop, FrameState initialState) {
+            return ReentrantNodeIterator.processLoop(this, loop, initialState).exitStates;
         }
 
     }
@@ -111,8 +79,7 @@
     @Override
     protected void run(StructuredGraph graph) {
         assert checkFixedDeopts(graph);
-        ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, false, false);
-        ReentrantBlockIterator.apply(new FrameStateAssignementClosure(), cfg.getStartBlock(), new FrameStateAssignmentState(null), null);
+        ReentrantNodeIterator.apply(new FrameStateAssignementClosure(), graph.start(), null, null);
     }
 
     private static boolean checkFixedDeopts(StructuredGraph graph) {
@@ -125,15 +92,34 @@
         return true;
     }
 
-    private static FrameState singleFrameState(List<FrameStateAssignmentState> states) {
-        Iterator<FrameStateAssignmentState> it = states.iterator();
-        assert it.hasNext();
-        FrameState first = it.next().getFramestate();
-        while (it.hasNext()) {
-            if (first != it.next().getFramestate()) {
+    private static FrameState singleFrameState(@SuppressWarnings("unused") MergeNode merge, List<FrameState> states) {
+        if (states.size() == 0) {
+            return null;
+        }
+        FrameState firstState = states.get(0);
+        FrameState singleState = firstState;
+        if (singleState == null) {
+            return null;
+        }
+        int singleBci = singleState.bci;
+        for (int i = 1; i < states.size(); ++i) {
+            FrameState cur = states.get(i);
+            if (cur == null) {
                 return null;
             }
+
+            if (cur != singleState) {
+                singleState = null;
+            }
+
+            if (cur.bci != singleBci) {
+                singleBci = FrameState.INVALID_FRAMESTATE_BCI;
+            }
+
         }
-        return first;
+        if (singleState != null) {
+            return singleState;
+        }
+        return null;
     }
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java	Mon May 13 17:11:31 2013 +0200
@@ -114,8 +114,7 @@
         private void processAccess(Access access) {
             GuardNode guard = nullGuarded.get(access.object());
             if (guard != null && isImplicitNullCheck(access.nullCheckLocation())) {
-                NodeInputList<ValueNode> dependencies = ((ValueNode) access).dependencies();
-                dependencies.remove(guard);
+                access.setGuard(guard.getGuard());
                 Access fixedAccess = access;
                 if (access instanceof FloatingAccessNode) {
                     fixedAccess = ((FloatingAccessNode) access).asFixedNode();
@@ -142,7 +141,7 @@
 
         private boolean isImplicitNullCheck(LocationNode location) {
             if (location instanceof ConstantLocationNode) {
-                return ((ConstantLocationNode) location).displacement() < implicitNullCheckLimit;
+                return ((ConstantLocationNode) location).getDisplacement() < implicitNullCheckLimit;
             } else {
                 return false;
             }
@@ -170,12 +169,12 @@
         }
 
         private void lowerToIf(GuardNode guard) {
-            StructuredGraph graph = (StructuredGraph) guard.graph();
-            BeginNode fastPath = graph.add(new BeginNode());
+            StructuredGraph graph = guard.graph();
+            AbstractBeginNode fastPath = graph.add(new BeginNode());
             DeoptimizeNode deopt = graph.add(new DeoptimizeNode(guard.action(), guard.reason()));
-            BeginNode deoptBranch = BeginNode.begin(deopt);
-            BeginNode trueSuccessor;
-            BeginNode falseSuccessor;
+            AbstractBeginNode deoptBranch = AbstractBeginNode.begin(deopt);
+            AbstractBeginNode trueSuccessor;
+            AbstractBeginNode falseSuccessor;
             insertLoopExits(deopt);
             if (guard.negated()) {
                 trueSuccessor = deoptBranch;
@@ -193,11 +192,14 @@
             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 = (StructuredGraph) deopt.graph();
+            StructuredGraph graph = deopt.graph();
             while (loop != null) {
                 LoopExitNode exit = graph.add(new LoopExitNode(loop.loopBegin()));
                 graph.addBeforeFixed(deopt, exit);
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java	Mon May 13 17:11:31 2013 +0200
@@ -574,7 +574,7 @@
             return result;
         }
 
-        private void queueMerge(EndNode end) {
+        private void queueMerge(AbstractEndNode end) {
             MergeNode merge = end.merge();
             if (!queuedNodes.isMarked(merge) && visitedAllEnds(merge)) {
                 queuedNodes.mark(merge);
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Mon May 13 17:11:31 2013 +0200
@@ -42,6 +42,7 @@
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.phases.common.InliningPhase.InliningData;
 
 public class InliningUtil {
@@ -275,7 +276,7 @@
         }
 
         protected static void inline(Invoke invoke, ResolvedJavaMethod concrete, InlineableElement inlineable, Assumptions assumptions, boolean receiverNullCheck) {
-            StructuredGraph graph = (StructuredGraph) invoke.asNode().graph();
+            StructuredGraph graph = invoke.asNode().graph();
             if (inlineable instanceof StructuredGraph) {
                 StructuredGraph calleeGraph = (StructuredGraph) inlineable;
                 InliningUtil.inline(invoke, calleeGraph, receiverNullCheck);
@@ -484,16 +485,19 @@
         private final List<ResolvedJavaMethod> concretes;
         private final double[] methodProbabilities;
         private final double maximumMethodProbability;
+        private final ArrayList<Integer> typesToConcretes;
         private final ArrayList<ProfiledType> ptypes;
-        private final int[] typesToConcretes;
+        private final ArrayList<Double> concretesProbabilities;
         private final double notRecordedTypeProbability;
         private final InlineableElement[] inlineableElements;
 
-        public MultiTypeGuardInlineInfo(Invoke invoke, ArrayList<ResolvedJavaMethod> concretes, ArrayList<ProfiledType> ptypes, int[] typesToConcretes, double notRecordedTypeProbability) {
+        public MultiTypeGuardInlineInfo(Invoke invoke, ArrayList<ResolvedJavaMethod> concretes, ArrayList<Double> concretesProbabilities, ArrayList<ProfiledType> ptypes,
+                        ArrayList<Integer> typesToConcretes, double notRecordedTypeProbability) {
             super(invoke);
-            assert concretes.size() > 0 && concretes.size() <= ptypes.size() : "must have at least one method but no more than types methods";
-            assert ptypes.size() == typesToConcretes.length : "array lengths must match";
+            assert concretes.size() > 0 : "must have at least one method";
+            assert ptypes.size() == typesToConcretes.size() : "array lengths must match";
 
+            this.concretesProbabilities = concretesProbabilities;
             this.concretes = concretes;
             this.ptypes = ptypes;
             this.typesToConcretes = typesToConcretes;
@@ -603,7 +607,7 @@
             }
 
             // create one separate block for each invoked method
-            BeginNode[] successors = new BeginNode[numberOfMethods + 1];
+            AbstractBeginNode[] successors = new AbstractBeginNode[numberOfMethods + 1];
             for (int i = 0; i < numberOfMethods; i++) {
                 successors[i] = createInvocationBlock(graph, invoke, returnMerge, returnValuePhi, exceptionMerge, exceptionObjectPhi, true);
             }
@@ -615,7 +619,7 @@
             } else {
                 unknownTypeSux = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TypeCheckedInliningViolated));
             }
-            successors[successors.length - 1] = BeginNode.begin(unknownTypeSux);
+            successors[successors.length - 1] = AbstractBeginNode.begin(unknownTypeSux);
 
             // replace the invoke exception edge
             if (invoke instanceof InvokeWithExceptionNode) {
@@ -629,7 +633,7 @@
             assert invoke.asNode().isAlive();
 
             // replace the invoke with a switch on the type of the actual receiver
-            createDispatchOnTypeBeforeInvoke(graph, successors, false);
+            boolean methodDispatch = createDispatchOnTypeBeforeInvoke(graph, successors, false, runtime);
 
             assert invoke.next() == continuation;
             invoke.setNext(null);
@@ -641,12 +645,18 @@
 
             // do the actual inlining for every invoke
             for (int i = 0; i < numberOfMethods; i++) {
-                BeginNode node = successors[i];
+                AbstractBeginNode node = successors[i];
                 Invoke invokeForInlining = (Invoke) node.next();
 
-                ResolvedJavaType commonType = getLeastCommonType(i);
+                ResolvedJavaType commonType;
+                if (methodDispatch) {
+                    commonType = concretes.get(i).getDeclaringClass();
+                } else {
+                    commonType = getLeastCommonType(i);
+                }
+
                 ValueNode receiver = ((MethodCallTargetNode) invokeForInlining.callTarget()).receiver();
-                boolean exact = getTypeCount(i) == 1;
+                boolean exact = (getTypeCount(i) == 1 && !methodDispatch);
                 PiNode anchoredReceiver = createAnchoredReceiver(graph, node, commonType, receiver, exact);
                 invokeForInlining.callTarget().replaceFirstInput(receiver, anchoredReceiver);
 
@@ -657,6 +667,7 @@
             if (shouldFallbackToInvoke()) {
                 replacementNodes.add(null);
             }
+
             if (GraalOptions.OptTailDuplication) {
                 /*
                  * We might want to perform tail duplication at the merge after a type switch, if
@@ -676,15 +687,15 @@
                 if (opportunities > 0) {
                     metricInliningTailDuplication.increment();
                     Debug.log("MultiTypeGuardInlineInfo starting tail duplication (%d opportunities)", opportunities);
-                    TailDuplicationPhase.tailDuplicate(returnMerge, TailDuplicationPhase.TRUE_DECISION, replacementNodes);
+                    TailDuplicationPhase.tailDuplicate(returnMerge, TailDuplicationPhase.TRUE_DECISION, replacementNodes, new HighTierContext(runtime, assumptions, replacements));
                 }
             }
         }
 
         private int getTypeCount(int concreteMethodIndex) {
             int count = 0;
-            for (int i = 0; i < typesToConcretes.length; i++) {
-                if (typesToConcretes[i] == concreteMethodIndex) {
+            for (int i = 0; i < typesToConcretes.size(); i++) {
+                if (typesToConcretes.get(i) == concreteMethodIndex) {
                     count++;
                 }
             }
@@ -693,8 +704,8 @@
 
         private ResolvedJavaType getLeastCommonType(int concreteMethodIndex) {
             ResolvedJavaType commonType = null;
-            for (int i = 0; i < typesToConcretes.length; i++) {
-                if (typesToConcretes[i] == concreteMethodIndex) {
+            for (int i = 0; i < typesToConcretes.size(); i++) {
+                if (typesToConcretes.get(i) == concreteMethodIndex) {
                     if (commonType == null) {
                         commonType = ptypes.get(i).getType();
                     } else {
@@ -717,31 +728,73 @@
         private void inlineSingleMethod(StructuredGraph graph, Assumptions assumptions) {
             assert concretes.size() == 1 && inlineableElements.length == 1 && ptypes.size() > 1 && !shouldFallbackToInvoke() && notRecordedTypeProbability == 0;
 
-            BeginNode calleeEntryNode = graph.add(new BeginNode());
+            AbstractBeginNode calleeEntryNode = graph.add(new BeginNode());
 
-            BeginNode unknownTypeSux = createUnknownTypeSuccessor(graph);
-            BeginNode[] successors = new BeginNode[]{calleeEntryNode, unknownTypeSux};
-            createDispatchOnTypeBeforeInvoke(graph, successors, false);
+            AbstractBeginNode unknownTypeSux = createUnknownTypeSuccessor(graph);
+            AbstractBeginNode[] successors = new AbstractBeginNode[]{calleeEntryNode, unknownTypeSux};
+            createDispatchOnTypeBeforeInvoke(graph, successors, false, runtime);
 
             calleeEntryNode.setNext(invoke.asNode());
 
             inline(invoke, methodAt(0), inlineableElementAt(0), assumptions, false);
         }
 
-        private void createDispatchOnTypeBeforeInvoke(StructuredGraph graph, BeginNode[] successors, boolean invokeIsOnlySuccessor) {
-            assert ptypes.size() > 1;
+        private boolean createDispatchOnTypeBeforeInvoke(StructuredGraph graph, AbstractBeginNode[] successors, boolean invokeIsOnlySuccessor, MetaAccessProvider runtime) {
+            assert ptypes.size() >= 1;
 
             Kind hubKind = ((MethodCallTargetNode) invoke.callTarget()).targetMethod().getDeclaringClass().getEncoding(Representation.ObjectHub).getKind();
             LoadHubNode hub = graph.add(new LoadHubNode(((MethodCallTargetNode) invoke.callTarget()).receiver(), hubKind));
             graph.addBeforeFixed(invoke.asNode(), hub);
 
+            if (!invokeIsOnlySuccessor && chooseMethodDispatch()) {
+                assert successors.length == concretes.size() + 1;
+                assert concretes.size() > 0;
+                Debug.log("Method check cascade with %d methods", concretes.size());
+
+                ValueNode[] constantMethods = new ValueNode[concretes.size()];
+                double[] probability = new double[concretes.size()];
+                for (int i = 0; i < concretes.size(); ++i) {
+                    ResolvedJavaMethod firstMethod = concretes.get(i);
+                    Constant firstMethodConstant = firstMethod.getEncoding();
+
+                    ValueNode firstMethodConstantNode = ConstantNode.forConstant(firstMethodConstant, runtime, graph);
+                    constantMethods[i] = firstMethodConstantNode;
+                    double concretesProbability = concretesProbabilities.get(i);
+                    assert concretesProbability >= 0.0;
+                    probability[i] = concretesProbability;
+                    if (i > 0) {
+                        double prevProbability = probability[i - 1];
+                        if (prevProbability == 1.0) {
+                            probability[i] = 1.0;
+                        } else {
+                            probability[i] = Math.min(1.0, Math.max(0.0, probability[i] / (1.0 - prevProbability)));
+                        }
+                    }
+                }
+
+                FixedNode lastSucc = successors[concretes.size()];
+                for (int i = concretes.size() - 1; i >= 0; --i) {
+                    LoadMethodNode method = graph.add(new LoadMethodNode(concretes.get(i), hub, constantMethods[i].kind()));
+                    CompareNode methodCheck = CompareNode.createCompareNode(Condition.EQ, method, constantMethods[i]);
+                    IfNode ifNode = graph.add(new IfNode(methodCheck, successors[i], lastSucc, probability[i]));
+                    method.setNext(ifNode);
+                    lastSucc = method;
+                }
+
+                FixedWithNextNode pred = (FixedWithNextNode) invoke.asNode().predecessor();
+                pred.setNext(lastSucc);
+                return true;
+            } else {
+                Debug.log("Type switch with %d types", concretes.size());
+            }
+
             ResolvedJavaType[] keys = new ResolvedJavaType[ptypes.size()];
             double[] keyProbabilities = new double[ptypes.size() + 1];
             int[] keySuccessors = new int[ptypes.size() + 1];
             for (int i = 0; i < ptypes.size(); i++) {
                 keys[i] = ptypes.get(i).getType();
                 keyProbabilities[i] = ptypes.get(i).getProbability();
-                keySuccessors[i] = invokeIsOnlySuccessor ? 0 : typesToConcretes[i];
+                keySuccessors[i] = invokeIsOnlySuccessor ? 0 : typesToConcretes.get(i);
                 assert keySuccessors[i] < successors.length - 1 : "last successor is the unknownTypeSux";
             }
             keyProbabilities[keyProbabilities.length - 1] = notRecordedTypeProbability;
@@ -750,15 +803,60 @@
             TypeSwitchNode typeSwitch = graph.add(new TypeSwitchNode(hub, successors, keys, keyProbabilities, keySuccessors));
             FixedWithNextNode pred = (FixedWithNextNode) invoke.asNode().predecessor();
             pred.setNext(typeSwitch);
+            return false;
+        }
+
+        private boolean chooseMethodDispatch() {
+            for (ResolvedJavaMethod concrete : concretes) {
+                if (!concrete.isInVirtualMethodTable()) {
+                    return false;
+                }
+            }
+
+            if (concretes.size() == 1 && this.notRecordedTypeProbability > 0) {
+                // Always chose method dispatch if there is a single concrete method and the call
+                // site is megamorphic.
+                return true;
+            }
+
+            if (concretes.size() == ptypes.size()) {
+                // Always prefer types over methods if the number of types is smaller than the
+                // number of methods.
+                return false;
+            }
+
+            return chooseMethodDispatchCostBased();
         }
 
-        private static BeginNode createInvocationBlock(StructuredGraph graph, Invoke invoke, MergeNode returnMerge, PhiNode returnValuePhi, MergeNode exceptionMerge, PhiNode exceptionObjectPhi,
-                        boolean useForInlining) {
+        private boolean chooseMethodDispatchCostBased() {
+            double remainder = 1.0 - this.notRecordedTypeProbability;
+            double costEstimateMethodDispatch = remainder;
+            for (int i = 0; i < concretes.size(); ++i) {
+                if (i != 0) {
+                    costEstimateMethodDispatch += remainder;
+                }
+                remainder -= concretesProbabilities.get(i);
+            }
+
+            double costEstimateTypeDispatch = 0.0;
+            remainder = 1.0;
+            for (int i = 0; i < ptypes.size(); ++i) {
+                if (i != 0) {
+                    costEstimateTypeDispatch += remainder;
+                }
+                remainder -= ptypes.get(i).getProbability();
+            }
+            costEstimateTypeDispatch += notRecordedTypeProbability;
+            return costEstimateMethodDispatch < costEstimateTypeDispatch;
+        }
+
+        private static AbstractBeginNode createInvocationBlock(StructuredGraph graph, Invoke invoke, MergeNode returnMerge, PhiNode returnValuePhi, MergeNode exceptionMerge,
+                        PhiNode exceptionObjectPhi, boolean useForInlining) {
             Invoke duplicatedInvoke = duplicateInvokeForInlining(graph, invoke, exceptionMerge, exceptionObjectPhi, useForInlining);
-            BeginNode calleeEntryNode = graph.add(new BeginNode());
+            AbstractBeginNode calleeEntryNode = graph.add(new BeginNode());
             calleeEntryNode.setNext(duplicatedInvoke.asNode());
 
-            EndNode endNode = graph.add(new EndNode());
+            AbstractEndNode endNode = graph.add(new EndNode());
             duplicatedInvoke.setNext(endNode);
             returnMerge.addForwardEnd(endNode);
 
@@ -793,7 +891,7 @@
                 // set new state (pop old exception object, push new one)
                 newExceptionEdge.setStateAfter(stateAfterException.duplicateModified(stateAfterException.bci, stateAfterException.rethrowException(), Kind.Object, newExceptionEdge));
 
-                EndNode endNode = graph.add(new EndNode());
+                AbstractEndNode endNode = graph.add(new EndNode());
                 newExceptionEdge.setNext(endNode);
                 exceptionMerge.addForwardEnd(endNode);
                 exceptionObjectPhi.addInput(newExceptionEdge);
@@ -812,11 +910,11 @@
             }
         }
 
-        private void tryToDevirtualizeSingleMethod(StructuredGraph graph) {
-            devirtualizeWithTypeSwitch(graph, InvokeKind.Special, concretes.get(0));
+        private void tryToDevirtualizeSingleMethod(StructuredGraph graph, MetaAccessProvider runtime) {
+            devirtualizeWithTypeSwitch(graph, InvokeKind.Special, concretes.get(0), runtime);
         }
 
-        private void tryToDevirtualizeMultipleMethods(StructuredGraph graph) {
+        private void tryToDevirtualizeMultipleMethods(StructuredGraph graph, MetaAccessProvider runtime) {
             MethodCallTargetNode methodCallTarget = (MethodCallTargetNode) invoke.callTarget();
             if (methodCallTarget.invokeKind() == InvokeKind.Interface) {
                 ResolvedJavaMethod targetMethod = methodCallTarget.targetMethod();
@@ -827,19 +925,19 @@
                 if (!leastCommonType.isInterface() && targetMethod.getDeclaringClass().isAssignableFrom(leastCommonType)) {
                     ResolvedJavaMethod baseClassTargetMethod = leastCommonType.resolveMethod(targetMethod);
                     if (baseClassTargetMethod != null) {
-                        devirtualizeWithTypeSwitch(graph, InvokeKind.Virtual, leastCommonType.resolveMethod(targetMethod));
+                        devirtualizeWithTypeSwitch(graph, InvokeKind.Virtual, leastCommonType.resolveMethod(targetMethod), runtime);
                     }
                 }
             }
         }
 
-        private void devirtualizeWithTypeSwitch(StructuredGraph graph, InvokeKind kind, ResolvedJavaMethod target) {
+        private void devirtualizeWithTypeSwitch(StructuredGraph graph, InvokeKind kind, ResolvedJavaMethod target, MetaAccessProvider runtime) {
             InliningUtil.receiverNullCheck(invoke);
 
-            BeginNode invocationEntry = graph.add(new BeginNode());
-            BeginNode unknownTypeSux = createUnknownTypeSuccessor(graph);
-            BeginNode[] successors = new BeginNode[]{invocationEntry, unknownTypeSux};
-            createDispatchOnTypeBeforeInvoke(graph, successors, true);
+            AbstractBeginNode invocationEntry = graph.add(new BeginNode());
+            AbstractBeginNode unknownTypeSux = createUnknownTypeSuccessor(graph);
+            AbstractBeginNode[] successors = new AbstractBeginNode[]{invocationEntry, unknownTypeSux};
+            createDispatchOnTypeBeforeInvoke(graph, successors, true, runtime);
 
             invocationEntry.setNext(invoke.asNode());
             ValueNode receiver = ((MethodCallTargetNode) invoke.callTarget()).receiver();
@@ -848,8 +946,8 @@
             replaceInvokeCallTarget(invoke, graph, kind, target);
         }
 
-        private static BeginNode createUnknownTypeSuccessor(StructuredGraph graph) {
-            return BeginNode.begin(graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TypeCheckedInliningViolated)));
+        private static AbstractBeginNode createUnknownTypeSuccessor(StructuredGraph graph) {
+            return AbstractBeginNode.begin(graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TypeCheckedInliningViolated)));
         }
 
         @Override
@@ -915,7 +1013,6 @@
         if (!checkInvokeConditions(invoke)) {
             return null;
         }
-        ResolvedJavaMethod caller = getCaller(invoke);
         MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
         ResolvedJavaMethod targetMethod = callTarget.targetMethod();
 
@@ -958,7 +1055,7 @@
         }
 
         // type check based inlining
-        return getTypeCheckedInlineInfo(data, invoke, maxNumberOfMethods, replacements, caller, holder, targetMethod, optimisticOpts);
+        return getTypeCheckedInlineInfo(data, invoke, maxNumberOfMethods, replacements, targetMethod, optimisticOpts);
     }
 
     private static InlineInfo getAssumptionInlineInfo(InliningData data, Invoke invoke, Replacements replacements, OptimisticOptimizations optimisticOpts, ResolvedJavaMethod concrete,
@@ -978,27 +1075,27 @@
         return new ExactInlineInfo(invoke, targetMethod);
     }
 
-    private static InlineInfo getTypeCheckedInlineInfo(InliningData data, Invoke invoke, int maxNumberOfMethods, Replacements replacements, ResolvedJavaMethod caller, ResolvedJavaType holder,
-                    ResolvedJavaMethod targetMethod, OptimisticOptimizations optimisticOpts) {
-        ProfilingInfo profilingInfo = caller.getProfilingInfo();
-        JavaTypeProfile typeProfile = profilingInfo.getTypeProfile(invoke.bci());
-        if (typeProfile == null) {
+    private static InlineInfo getTypeCheckedInlineInfo(InliningData data, Invoke invoke, int maxNumberOfMethods, Replacements replacements, ResolvedJavaMethod targetMethod, OptimisticOptimizations optimisticOpts) {
+        ValueNode receiver = invoke.callTarget().arguments().get(0);
+        if (receiver instanceof TypeProfileProxyNode) {
+            TypeProfileProxyNode typeProfileProxyNode = (TypeProfileProxyNode) receiver;
+            typeProfile = typeProfileProxyNode.getProfile();
+        } else {
             return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "no type profile exists");
         }
 
-        ProfiledType[] rawProfiledTypes = typeProfile.getTypes();
-        ArrayList<ProfiledType> ptypes = getCompatibleTypes(rawProfiledTypes, holder);
-        if (ptypes == null || ptypes.size() <= 0) {
-            return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "no types remained after filtering (%d types were recorded)", rawProfiledTypes.length);
+        ProfiledType[] ptypes = typeProfile.getTypes();
+        if (ptypes == null || ptypes.length <= 0) {
+            return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "no types in profile");
         }
 
         double notRecordedTypeProbability = typeProfile.getNotRecordedProbability();
-        if (ptypes.size() == 1 && notRecordedTypeProbability == 0) {
+        if (ptypes.length == 1 && notRecordedTypeProbability == 0) {
             if (!optimisticOpts.inlineMonomorphicCalls()) {
                 return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "inlining monomorphic calls is disabled");
             }
 
-            ResolvedJavaType type = ptypes.get(0).getType();
+            ResolvedJavaType type = ptypes[0].getType();
             ResolvedJavaMethod concrete = type.resolveMethod(targetMethod);
             if (!checkTargetConditions(data, replacements, invoke, concrete, optimisticOpts)) {
                 return null;
@@ -1008,59 +1105,83 @@
             invoke.setPolymorphic(true);
 
             if (!optimisticOpts.inlinePolymorphicCalls() && notRecordedTypeProbability == 0) {
-                return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "inlining polymorphic calls is disabled (%d types)", ptypes.size());
+                return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "inlining polymorphic calls is disabled (%d types)", ptypes.length);
             }
             if (!optimisticOpts.inlineMegamorphicCalls() && notRecordedTypeProbability > 0) {
                 // due to filtering impossible types, notRecordedTypeProbability can be > 0 although
                 // the number of types is lower than what can be recorded in a type profile
-                return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "inlining megamorphic calls is disabled (%d types, %f %% not recorded types)", ptypes.size(),
+                return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "inlining megamorphic calls is disabled (%d types, %f %% not recorded types)", ptypes.length,
                                 notRecordedTypeProbability * 100);
             }
 
-            // determine concrete methods and map type to specific method
+            // Find unique methods and their probabilities.
             ArrayList<ResolvedJavaMethod> concreteMethods = new ArrayList<>();
-            int[] typesToConcretes = new int[ptypes.size()];
-            for (int i = 0; i < ptypes.size(); i++) {
-                ResolvedJavaMethod concrete = ptypes.get(i).getType().resolveMethod(targetMethod);
-
+            ArrayList<Double> concreteMethodsProbabilities = new ArrayList<>();
+            for (int i = 0; i < ptypes.length; i++) {
+                ResolvedJavaMethod concrete = ptypes[i].getType().resolveMethod(targetMethod);
                 int index = concreteMethods.indexOf(concrete);
+                double curProbability = ptypes[i].getProbability();
                 if (index < 0) {
                     index = concreteMethods.size();
                     concreteMethods.add(concrete);
+                    concreteMethodsProbabilities.add(curProbability);
+                } else {
+                    concreteMethodsProbabilities.set(index, concreteMethodsProbabilities.get(index) + curProbability);
                 }
-                typesToConcretes[i] = index;
             }
 
             if (concreteMethods.size() > maxNumberOfMethods) {
                 return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "polymorphic call with more than %d target methods", maxNumberOfMethods);
             }
 
+            // Clear methods that fall below the threshold.
+            if (notRecordedTypeProbability > 0) {
+                ArrayList<ResolvedJavaMethod> newConcreteMethods = new ArrayList<>();
+                ArrayList<Double> newConcreteMethodsProbabilities = new ArrayList<>();
+                for (int i = 0; i < concreteMethods.size(); ++i) {
+                    if (concreteMethodsProbabilities.get(i) >= GraalOptions.MegamorphicInliningMinMethodProbability) {
+                        newConcreteMethods.add(concreteMethods.get(i));
+                        newConcreteMethodsProbabilities.add(concreteMethodsProbabilities.get(i));
+                    }
+                }
+
+                if (newConcreteMethods.size() == 0) {
+                    // No method left that is worth inlining.
+                    return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "no methods remaining after filtering less frequent methods (%d methods previously)", concreteMethods.size());
+                }
+
+                concreteMethods = newConcreteMethods;
+                concreteMethodsProbabilities = newConcreteMethodsProbabilities;
+            }
+
+            // Clean out types whose methods are no longer available.
+            ArrayList<ProfiledType> usedTypes = new ArrayList<>();
+            ArrayList<Integer> typesToConcretes = new ArrayList<>();
+            for (ProfiledType type : ptypes) {
+                ResolvedJavaMethod concrete = type.getType().resolveMethod(targetMethod);
+                int index = concreteMethods.indexOf(concrete);
+                if (index == -1) {
+                    notRecordedTypeProbability += type.getProbability();
+                } else {
+                    usedTypes.add(type);
+                    typesToConcretes.add(index);
+                }
+            }
+
+            if (usedTypes.size() == 0) {
+                // No type left that is worth checking for.
+                return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "no types remaining after filtering less frequent types (%d types previously)", ptypes.length);
+            }
+
             for (ResolvedJavaMethod concrete : concreteMethods) {
                 if (!checkTargetConditions(data, replacements, invoke, concrete, optimisticOpts)) {
                     return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "it is a polymorphic method call and at least one invoked method cannot be inlined");
                 }
             }
-            return new MultiTypeGuardInlineInfo(invoke, concreteMethods, ptypes, typesToConcretes, notRecordedTypeProbability);
+            return new MultiTypeGuardInlineInfo(invoke, concreteMethods, concreteMethodsProbabilities, usedTypes, typesToConcretes, notRecordedTypeProbability);
         }
     }
 
-    private static ArrayList<ProfiledType> getCompatibleTypes(ProfiledType[] types, ResolvedJavaType holder) {
-        ArrayList<ProfiledType> result = new ArrayList<>();
-        for (int i = 0; i < types.length; i++) {
-            ProfiledType ptype = types[i];
-            ResolvedJavaType type = ptype.getType();
-            assert !type.isInterface() && (type.isArray() || !Modifier.isAbstract(type.getModifiers())) : type;
-            if (!GraalOptions.OptFilterProfiledTypes || holder.isAssignableFrom(type)) {
-                result.add(ptype);
-            }
-        }
-        return result;
-    }
-
-    private static ResolvedJavaMethod getCaller(Invoke invoke) {
-        return invoke.stateAfter().method();
-    }
-
     private static PiNode createAnchoredReceiver(StructuredGraph graph, FixedNode anchor, ResolvedJavaType commonType, ValueNode receiver, boolean exact) {
         // to avoid that floating reads on receiver fields float above the type check
         return graph.unique(new PiNode(receiver, exact ? StampFactory.exactNonNull(commonType) : StampFactory.declaredNonNull(commonType), anchor));
@@ -1138,7 +1259,7 @@
      */
     public static Map<Node, Node> inline(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck) {
         NodeInputList<ValueNode> parameters = invoke.callTarget().arguments();
-        StructuredGraph graph = (StructuredGraph) invoke.asNode().graph();
+        StructuredGraph graph = invoke.asNode().graph();
 
         FrameState stateAfter = invoke.stateAfter();
         assert stateAfter.isAlive();
@@ -1166,7 +1287,7 @@
             }
         }
         // ensure proper anchoring of things that were anchored to the StartNode
-        replacements.put(entryPointNode, BeginNode.prevBegin(invoke.asNode()));
+        replacements.put(entryPointNode, AbstractBeginNode.prevBegin(invoke.asNode()));
 
         assert invoke.asNode().successors().first() != null : invoke;
         assert invoke.asNode().predecessor() != null;
@@ -1270,7 +1391,7 @@
 
     public static void receiverNullCheck(Invoke invoke) {
         MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
-        StructuredGraph graph = (StructuredGraph) callTarget.graph();
+        StructuredGraph graph = callTarget.graph();
         NodeInputList<ValueNode> parameters = callTarget.arguments();
         ValueNode firstParam = parameters.size() <= 0 ? null : parameters.get(0);
         if (!callTarget.isStatic() && firstParam.kind() == Kind.Object && !firstParam.objectStamp().nonNull()) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IterativeConditionalEliminationPhase.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IterativeConditionalEliminationPhase.java	Mon May 13 17:11:31 2013 +0200
@@ -24,7 +24,7 @@
 
 import java.util.*;
 
-import com.oracle.graal.graph.Graph.InputChangedListener;
+import com.oracle.graal.graph.Graph.NodeChangedListener;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.*;
@@ -49,7 +49,7 @@
         }
     }
 
-    private static class Listener implements InputChangedListener {
+    private static class Listener implements NodeChangedListener {
 
         private final Set<Node> canonicalizationRoots;
 
@@ -58,7 +58,7 @@
         }
 
         @Override
-        public void inputChanged(Node node) {
+        public void nodeChanged(Node node) {
             canonicalizationRoots.add(node);
         }
     }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java	Mon May 13 17:11:31 2013 +0200
@@ -31,6 +31,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.cfg.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.spi.Lowerable.LoweringType;
 import com.oracle.graal.phases.*;
@@ -45,12 +46,12 @@
     final class LoweringToolImpl implements LoweringTool {
 
         private final PhaseContext context;
-        private final FixedNode guardAnchor;
+        private final GuardingNode guardAnchor;
         private final NodeBitMap activeGuards;
         private FixedWithNextNode lastFixedNode;
         private ControlFlowGraph cfg;
 
-        public LoweringToolImpl(PhaseContext context, FixedNode guardAnchor, NodeBitMap activeGuards, ControlFlowGraph cfg) {
+        public LoweringToolImpl(PhaseContext context, GuardingNode guardAnchor, NodeBitMap activeGuards, ControlFlowGraph cfg) {
             this.context = context;
             this.guardAnchor = guardAnchor;
             this.activeGuards = activeGuards;
@@ -68,12 +69,19 @@
         }
 
         @Override
-        public ValueNode createNullCheckGuard(ValueNode object) {
-            return createGuard(object.graph().unique(new IsNullNode(object)), DeoptimizationReason.NullCheckException, DeoptimizationAction.InvalidateReprofile, true);
+        public GuardingNode createNullCheckGuard(GuardedNode guardedNode, ValueNode object) {
+            if (object.objectStamp().nonNull()) {
+                // Short cut creation of null check guard if the object is known to be non-null.
+                return null;
+            }
+            GuardingNode guard = createGuard(object.graph().unique(new IsNullNode(object)), DeoptimizationReason.NullCheckException, DeoptimizationAction.InvalidateReprofile, true);
+            assert guardedNode.getGuard() == null;
+            guardedNode.setGuard(guard);
+            return guard;
         }
 
         @Override
-        public ValueNode createGuard(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action) {
+        public GuardingNode createGuard(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action) {
             return createGuard(condition, deoptReason, action, false);
         }
 
@@ -83,7 +91,7 @@
         }
 
         @Override
-        public ValueNode createGuard(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, boolean negated) {
+        public GuardingNode createGuard(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, boolean negated) {
             if (loweringType == LoweringType.AFTER_GUARDS) {
                 throw new GraalInternalError("Cannot create guards in after-guard lowering");
             }
@@ -94,7 +102,7 @@
                     }
                 }
             }
-            GuardNode newGuard = guardAnchor.graph().unique(new GuardNode(condition, guardAnchor, deoptReason, action, negated));
+            GuardNode newGuard = guardAnchor.asNode().graph().unique(new GuardNode(condition, guardAnchor, deoptReason, action, negated));
             if (GraalOptions.OptEliminateGuards) {
                 activeGuards.grow();
                 activeGuards.mark(newGuard);
@@ -173,9 +181,9 @@
             processBlock(schedule.getCFG().getStartBlock(), graph.createNodeBitMap(), null);
         }
 
-        private void processBlock(Block block, NodeBitMap activeGuards, FixedNode parentAnchor) {
+        private void processBlock(Block block, NodeBitMap activeGuards, GuardingNode parentAnchor) {
 
-            FixedNode anchor = parentAnchor;
+            GuardingNode anchor = parentAnchor;
             if (anchor == null) {
                 anchor = block.getBeginNode();
             }
@@ -196,13 +204,13 @@
             }
 
             if (parentAnchor == null && GraalOptions.OptEliminateGuards) {
-                for (GuardNode guard : anchor.usages().filter(GuardNode.class)) {
+                for (GuardNode guard : anchor.asNode().usages().filter(GuardNode.class)) {
                     activeGuards.clear(guard);
                 }
             }
         }
 
-        private void process(final Block b, final NodeBitMap activeGuards, final FixedNode anchor) {
+        private void process(final Block b, final NodeBitMap activeGuards, final GuardingNode anchor) {
 
             final LoweringToolImpl loweringTool = new LoweringToolImpl(context, anchor, activeGuards, schedule.getCFG());
 
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java	Mon May 13 17:11:31 2013 +0200
@@ -36,13 +36,14 @@
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.graph.*;
+import com.oracle.graal.phases.tiers.*;
 
 /**
  * This class is a phase that looks for opportunities for tail duplication. The static method
- * {@link #tailDuplicate(MergeNode, TailDuplicationDecision, List)} can also be used to drive tail
- * duplication from other places, e.g., inlining.
+ * {@link #tailDuplicate(MergeNode, TailDuplicationDecision, List, PhaseContext)} can also be used
+ * to drive tail duplication from other places, e.g., inlining.
  */
-public class TailDuplicationPhase extends Phase {
+public class TailDuplicationPhase extends BasePhase<PhaseContext> {
 
     /*
      * Various metrics on the circumstances in which tail duplication was/wasn't performed.
@@ -129,14 +130,14 @@
     };
 
     @Override
-    protected void run(StructuredGraph graph) {
+    protected void run(StructuredGraph graph, PhaseContext phaseContext) {
         NodesToDoubles nodeProbabilities = new ComputeProbabilityClosure(graph).apply();
 
         // A snapshot is taken here, so that new MergeNode instances aren't considered for tail
         // duplication.
         for (MergeNode merge : graph.getNodes(MergeNode.class).snapshot()) {
             if (!(merge instanceof LoopBeginNode) && nodeProbabilities.get(merge) >= GraalOptions.TailDuplicationProbability) {
-                tailDuplicate(merge, DEFAULT_DECISION, null);
+                tailDuplicate(merge, DEFAULT_DECISION, null, phaseContext);
             }
         }
     }
@@ -156,8 +157,9 @@
      *            size needs to match the merge's end count. Each entry can either be null or a
      *            {@link PiNode}, and is used to replace {@link PiNode#object()} with the
      *            {@link PiNode} in the duplicated branch that corresponds to the entry.
+     * @param phaseContext
      */
-    public static boolean tailDuplicate(MergeNode merge, TailDuplicationDecision decision, List<PiNode> replacements) {
+    public static boolean tailDuplicate(MergeNode merge, TailDuplicationDecision decision, List<PiNode> replacements, PhaseContext phaseContext) {
         assert !(merge instanceof LoopBeginNode);
         assert replacements == null || replacements.size() == merge.forwardEndCount();
         FixedNode fixed = merge;
@@ -167,18 +169,18 @@
             fixedCount++;
         }
         if (fixedCount > 1) {
-            if (fixed instanceof EndNode && !(((EndNode) fixed).merge() instanceof LoopBeginNode)) {
+            if (fixed instanceof AbstractEndNode && !(((AbstractEndNode) fixed).merge() instanceof LoopBeginNode)) {
                 metricDuplicationEnd.increment();
                 if (decision.doTransform(merge, fixedCount)) {
                     metricDuplicationEndPerformed.increment();
-                    new DuplicationOperation(merge, replacements).duplicate();
+                    new DuplicationOperation(merge, replacements).duplicate(phaseContext);
                     return true;
                 }
             } else if (merge.stateAfter() != null) {
                 metricDuplicationOther.increment();
                 if (decision.doTransform(merge, fixedCount)) {
                     metricDuplicationOtherPerformed.increment();
-                    new DuplicationOperation(merge, replacements).duplicate();
+                    new DuplicationOperation(merge, replacements).duplicate(phaseContext);
                     return true;
                 }
             }
@@ -207,7 +209,7 @@
         public DuplicationOperation(MergeNode merge, List<PiNode> replacements) {
             this.merge = merge;
             this.replacements = replacements;
-            this.graph = (StructuredGraph) merge.graph();
+            this.graph = merge.graph();
         }
 
         /**
@@ -220,10 +222,14 @@
          * <li>Determines the complete set of duplicated nodes.</li>
          * <li>Performs the actual duplication.</li>
          * </ul>
+         * 
+         * @param phaseContext
          */
-        private void duplicate() {
+        private void duplicate(PhaseContext phaseContext) {
             Debug.log("tail duplication at merge %s in %s", merge, graph.method());
 
+            int startMark = graph.getMark();
+
             ValueAnchorNode anchor = addValueAnchor();
 
             // determine the fixed nodes that should be duplicated (currently: all nodes up until
@@ -240,18 +246,18 @@
                 fixed = ((FixedWithNextNode) fixed).next();
             }
 
-            EndNode endAfter = createNewMerge(fixed, stateAfter);
+            AbstractEndNode endAfter = createNewMerge(fixed, stateAfter);
             MergeNode mergeAfter = endAfter.merge();
             fixedNodes.add(endAfter);
             final HashSet<Node> duplicatedNodes = buildDuplicatedNodeSet(fixedNodes, stateAfter);
             mergeAfter.clearEnds();
             expandDuplicated(duplicatedNodes, mergeAfter);
 
-            List<EndNode> endSnapshot = merge.forwardEnds().snapshot();
+            List<AbstractEndNode> endSnapshot = merge.forwardEnds().snapshot();
             List<PhiNode> phiSnapshot = merge.phis().snapshot();
 
             int endIndex = 0;
-            for (final EndNode forwardEnd : merge.forwardEnds()) {
+            for (final AbstractEndNode forwardEnd : merge.forwardEnds()) {
                 Map<Node, Node> duplicates;
                 if (replacements == null || replacements.get(endIndex) == null) {
                     duplicates = graph.addDuplicates(duplicatedNodes, (DuplicationReplacement) null);
@@ -263,31 +269,26 @@
                 for (Map.Entry<ValueNode, PhiNode> phi : bottomPhis.entrySet()) {
                     phi.getValue().initializeValueAt(merge.forwardEndIndex(forwardEnd), (ValueNode) duplicates.get(phi.getKey()));
                 }
-                mergeAfter.addForwardEnd((EndNode) duplicates.get(endAfter));
+                mergeAfter.addForwardEnd((AbstractEndNode) duplicates.get(endAfter));
 
                 // re-wire the duplicated ValueAnchorNode to the predecessor of the corresponding
                 // EndNode
                 FixedNode anchorDuplicate = (FixedNode) duplicates.get(anchor);
                 ((FixedWithNextNode) forwardEnd.predecessor()).setNext(anchorDuplicate);
                 // move dependencies on the ValueAnchorNode to the previous BeginNode
-                BeginNode prevBegin = BeginNode.prevBegin(anchorDuplicate);
+                AbstractBeginNode prevBegin = AbstractBeginNode.prevBegin(anchorDuplicate);
                 anchorDuplicate.replaceAtUsages(prevBegin);
 
                 // re-wire the phi duplicates to the correct input
                 for (PhiNode phi : phiSnapshot) {
                     PhiNode phiDuplicate = (PhiNode) duplicates.get(phi);
-                    for (Node usage : phiDuplicate.usages()) {
-                        if (usage instanceof ValueNode) {
-                            ((ValueNode) usage).dependencies().add(prevBegin);
-                        }
-                    }
                     phiDuplicate.replaceAtUsages(phi.valueAt(forwardEnd));
                     phiDuplicate.safeDelete();
                 }
                 endIndex++;
             }
             GraphUtil.killCFG(merge);
-            for (EndNode forwardEnd : endSnapshot) {
+            for (AbstractEndNode forwardEnd : endSnapshot) {
                 forwardEnd.safeDelete();
             }
             for (PhiNode phi : phiSnapshot) {
@@ -297,6 +298,7 @@
                     phi.setMerge(mergeAfter);
                 }
             }
+            new CanonicalizerPhase(null, graph.getNewNodes(startMark)).apply(graph, phaseContext);
             Debug.dump(graph, "After tail duplication at %s", merge);
         }
 
@@ -421,9 +423,9 @@
          * @param stateAfterMerge The frame state that should be used for the merge.
          * @return The newly created end node.
          */
-        private EndNode createNewMerge(FixedNode successor, FrameState stateAfterMerge) {
+        private AbstractEndNode createNewMerge(FixedNode successor, FrameState stateAfterMerge) {
             MergeNode newBottomMerge = graph.add(new MergeNode());
-            EndNode newBottomEnd = graph.add(new EndNode());
+            AbstractEndNode newBottomEnd = graph.add(new EndNode());
             newBottomMerge.addForwardEnd(newBottomEnd);
             newBottomMerge.setStateAfter(stateAfterMerge);
             ((FixedWithNextNode) successor.predecessor()).setNext(newBottomEnd);
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Mon May 13 17:11:31 2013 +0200
@@ -34,9 +34,13 @@
     private static final boolean ____ = false;
     // Checkstyle: resume
 
-    public static int     Threads                            = 4;
+    public static int     Threads;
+    static {
+        Threads = Runtime.getRuntime().availableProcessors();
+    }
 
     public static String  CompilerConfiguration              = "basic";
+    public static String  GraalRuntime                       = "basic";
 
     // inlining settings
     public static boolean Inline                             = true;
@@ -44,7 +48,8 @@
     public static boolean Intrinsify                         = true;
            static boolean InlineMonomorphicCalls             = true;
            static boolean InlinePolymorphicCalls             = true;
-           static boolean InlineMegamorphicCalls             = ____;
+           static boolean InlineMegamorphicCalls             = true;
+    public static double  MegamorphicInliningMinMethodProbability = 0.33;
     public static int     MaximumDesiredSize                 = 5000;
     public static int     MaximumRecursiveInlining           = 1;
     public static float   BoostInliningForEscapeAnalysis     = 2f;
@@ -103,6 +108,7 @@
     public static int     LoopMaxUnswitch                    = 3;
     public static int     LoopUnswitchMaxIncrease            = 50;
     public static int     LoopUnswitchUncertaintyBoost       = 5;
+    public static boolean UseLoopLimitChecks                 = true;
 
     // debugging settings
     public static boolean ZapStackOnMethodEntry              = ____;
@@ -219,6 +225,7 @@
     public static boolean IntrinsifyUnsafeMethods            = true;
     public static boolean IntrinsifyMathMethods              = true;
     public static boolean IntrinsifyAESMethods               = true;
+    public static boolean IntrinsifyReflectionMethods        = true;
     public static boolean IntrinsifyInstalledCodeMethods     = true;
     public static boolean IntrinsifyCallSiteTarget           = true;
     /**
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/OptimisticOptimizations.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/OptimisticOptimizations.java	Mon May 13 17:11:31 2013 +0200
@@ -34,7 +34,7 @@
     private static final DebugMetric disabledOptimisticOptsMetric = Debug.metric("DisabledOptimisticOpts");
 
     public static enum Optimization {
-        RemoveNeverExecutedCode, UseTypeCheckedInlining, UseTypeCheckHints, UseExceptionProbabilityForOperations, UseExceptionProbability
+        RemoveNeverExecutedCode, UseTypeCheckedInlining, UseTypeCheckHints, UseExceptionProbabilityForOperations, UseExceptionProbability, UseLoopLimitChecks
     }
 
     private final Set<Optimization> enabledOpts;
@@ -47,6 +47,7 @@
         addOptimization(method, DeoptimizationReason.TypeCheckedInliningViolated, Optimization.UseTypeCheckedInlining);
         addOptimization(method, DeoptimizationReason.OptimizedTypeCheckViolated, Optimization.UseTypeCheckHints);
         addOptimization(method, DeoptimizationReason.NotCompiledExceptionHandler, Optimization.UseExceptionProbability);
+        addOptimization(method, DeoptimizationReason.LoopLimitCheck, Optimization.UseLoopLimitChecks);
     }
 
     private void addOptimization(ResolvedJavaMethod method, DeoptimizationReason deoptReason, Optimization optimization) {
@@ -109,6 +110,10 @@
         return GraalOptions.UseExceptionProbabilityForOperations && enabledOpts.contains(Optimization.UseExceptionProbabilityForOperations);
     }
 
+    public boolean useLoopLimitChecks() {
+        return GraalOptions.UseLoopLimitChecks && enabledOpts.contains(Optimization.UseLoopLimitChecks);
+    }
+
     public boolean lessOptimisticThan(OptimisticOptimizations other) {
         for (Optimization opt : Optimization.values()) {
             if (!enabledOpts.contains(opt) && other.enabledOpts.contains(opt)) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/VerifyPhase.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,35 @@
+/*
+ * 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.phases;
+
+import com.oracle.graal.nodes.*;
+
+public abstract class VerifyPhase extends Phase {
+
+    @Override
+    protected final void run(StructuredGraph graph) {
+        assert verify(graph);
+    }
+
+    protected abstract boolean verify(StructuredGraph graph);
+}
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ComputeInliningRelevanceClosure.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ComputeInliningRelevanceClosure.java	Mon May 13 17:11:31 2013 +0200
@@ -70,7 +70,7 @@
             if (scope.start instanceof LoopBeginNode) {
                 assert scope.parent != null;
                 double parentProbability = 0;
-                for (EndNode end : ((LoopBeginNode) scope.start).forwardEnds()) {
+                for (AbstractEndNode end : ((LoopBeginNode) scope.start).forwardEnds()) {
                     parentProbability += nodeProbabilities.get(end);
                 }
                 return parentProbability / scope.parent.minPathProbability;
@@ -170,7 +170,7 @@
             int pathBeginCount = pathBeginNodes.size();
 
             for (Node sux : controlSplit.successors()) {
-                double probability = controlSplit.probability((BeginNode) sux);
+                double probability = controlSplit.probability((AbstractBeginNode) sux);
                 if (probability > maxProbability) {
                     maxProbability = probability;
                     maxSux = sux;
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ComputeProbabilityClosure.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ComputeProbabilityClosure.java	Mon May 13 17:11:31 2013 +0200
@@ -76,11 +76,6 @@
         }
     }
 
-    private static boolean isRelativeProbability(double prob) {
-        // 1.01 to allow for some rounding errors
-        return prob >= 0 && prob <= 1.01;
-    }
-
     public static class LoopInfo {
 
         public final LoopBeginNode loopBegin;
@@ -128,6 +123,7 @@
         public LoopInfo loopInfo;
 
         public Probability(double probability, HashSet<LoopInfo> loops) {
+            assert probability >= 0.0;
             this.probability = probability;
             this.loops = new HashSet<>(4);
             if (loops != null) {
@@ -171,7 +167,7 @@
                 }
                 loops = intersection;
                 mergeLoops.put(merge, new HashSet<>(intersection));
-                assert isRelativeProbability(probability) : probability;
+                probability = Math.max(0.0, probability);
             }
             return true;
         }
@@ -205,7 +201,7 @@
         }
 
         @Override
-        public void afterSplit(BeginNode node) {
+        public void afterSplit(AbstractBeginNode node) {
             assert node.predecessor() != null;
             Node pred = node.predecessor();
             if (pred instanceof Invoke) {
@@ -216,7 +212,10 @@
             } else {
                 assert pred instanceof ControlSplitNode;
                 ControlSplitNode x = (ControlSplitNode) pred;
-                probability *= x.probability(node);
+                double nodeProbability = x.probability(node);
+                assert nodeProbability >= 0.0 : "Node " + x + " provided negative probability for begin " + node + ": " + nodeProbability;
+                probability *= nodeProbability;
+                assert probability >= 0.0;
             }
         }
     }
@@ -272,7 +271,7 @@
         }
 
         @Override
-        public void afterSplit(BeginNode node) {
+        public void afterSplit(AbstractBeginNode node) {
             // nothing to do...
         }
     }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/MergeableState.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/MergeableState.java	Mon May 13 17:11:31 2013 +0200
@@ -36,5 +36,5 @@
 
     void loopEnds(LoopBeginNode loopBegin, List<T> loopEndStates);
 
-    void afterSplit(BeginNode node);
+    void afterSplit(AbstractBeginNode node);
 }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/PostOrderNodeIterator.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/PostOrderNodeIterator.java	Mon May 13 17:11:31 2013 +0200
@@ -43,7 +43,7 @@
 public abstract class PostOrderNodeIterator<T extends MergeableState<T>> {
 
     private final NodeBitMap visitedEnds;
-    private final Deque<BeginNode> nodeQueue;
+    private final Deque<AbstractBeginNode> nodeQueue;
     private final IdentityHashMap<FixedNode, T> nodeStates;
     private final FixedNode start;
 
@@ -109,13 +109,13 @@
             for (Node node : successors) {
                 if (node != null) {
                     nodeStates.put((FixedNode) node.predecessor(), state);
-                    nodeQueue.addFirst((BeginNode) node);
+                    nodeQueue.addFirst((AbstractBeginNode) node);
                 }
             }
         } else {
             for (Node node : x.successors()) {
                 if (node != null) {
-                    nodeQueue.addFirst((BeginNode) node);
+                    nodeQueue.addFirst((AbstractBeginNode) node);
                 }
             }
         }
@@ -124,7 +124,7 @@
     private FixedNode nextQueuedNode() {
         int maxIterations = nodeQueue.size();
         while (maxIterations-- > 0) {
-            BeginNode node = nodeQueue.removeFirst();
+            AbstractBeginNode node = nodeQueue.removeFirst();
             if (node instanceof MergeNode) {
                 MergeNode merge = (MergeNode) node;
                 state = nodeStates.get(merge.forwardEndAt(0)).clone();
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantBlockIterator.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantBlockIterator.java	Mon May 13 17:11:31 2013 +0200
@@ -37,7 +37,7 @@
 
     public abstract static class BlockIteratorClosure<StateT> {
 
-        protected abstract void processBlock(Block block, StateT currentState);
+        protected abstract StateT processBlock(Block block, StateT currentState);
 
         protected abstract StateT merge(Block merge, List<StateT> states);
 
@@ -62,8 +62,8 @@
         }
         for (Block loopExit : loop.exits) {
             assert loopExit.getPredecessorCount() == 1;
+            assert blockEndStates.containsKey(loopExit.getBeginNode());
             StateT exitState = blockEndStates.get(loopExit.getBeginNode());
-            assert exitState != null;
             // make sure all exit states are unique objects
             info.exitStates.add(closure.cloneState(exitState));
         }
@@ -82,7 +82,7 @@
 
         while (true) {
             if (boundary == null || boundary.contains(current)) {
-                closure.processBlock(current, state);
+                state = closure.processBlock(current, state);
 
                 if (current.getSuccessors().isEmpty()) {
                     // nothing to do...
@@ -115,16 +115,16 @@
                             current = successor;
                             continue;
                         } else {
-                            if (current.getEndNode() instanceof EndNode) {
+                            if (current.getEndNode() instanceof AbstractEndNode) {
                                 assert successor.getPredecessors().size() > 1 : "invalid block schedule at " + successor.getBeginNode();
-                                EndNode end = (EndNode) current.getEndNode();
+                                AbstractEndNode end = (AbstractEndNode) current.getEndNode();
 
                                 // add the end node and see if the merge is ready for processing
                                 assert !states.containsKey(end);
                                 states.put(end, state);
                                 MergeNode merge = end.merge();
                                 boolean endsVisited = true;
-                                for (EndNode forwardEnd : merge.forwardEnds()) {
+                                for (AbstractEndNode forwardEnd : merge.forwardEnds()) {
                                     if (!states.containsKey(forwardEnd)) {
                                         endsVisited = false;
                                         break;
@@ -156,18 +156,18 @@
             } else {
                 current = blockQueue.removeFirst();
                 if (current.getPredecessors().size() == 1) {
+                    assert states.containsKey(current.getBeginNode());
                     state = states.get(current.getBeginNode());
                 } else {
                     assert current.getPredecessors().size() > 1;
                     MergeNode merge = (MergeNode) current.getBeginNode();
                     ArrayList<StateT> mergedStates = new ArrayList<>(merge.forwardEndCount());
                     for (Block predecessor : current.getPredecessors()) {
-                        EndNode end = (EndNode) predecessor.getEndNode();
+                        AbstractEndNode end = (AbstractEndNode) predecessor.getEndNode();
                         mergedStates.add(states.get(end));
                     }
                     state = closure.merge(current, mergedStates);
                 }
-                assert state != null;
             }
         }
     }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantNodeIterator.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantNodeIterator.java	Mon May 13 17:11:31 2013 +0200
@@ -37,11 +37,11 @@
 
     public abstract static class NodeIteratorClosure<StateT> {
 
-        protected abstract void processNode(FixedNode node, StateT currentState);
+        protected abstract StateT processNode(FixedNode node, StateT currentState);
 
         protected abstract StateT merge(MergeNode merge, List<StateT> states);
 
-        protected abstract StateT afterSplit(BeginNode node, StateT oldState);
+        protected abstract StateT afterSplit(AbstractBeginNode node, StateT oldState);
 
         protected abstract Map<LoopExitNode, StateT> processLoop(LoopBeginNode loop, StateT initialState);
     }
@@ -70,7 +70,7 @@
     }
 
     public static <StateT> Map<FixedNode, StateT> apply(NodeIteratorClosure<StateT> closure, FixedNode start, StateT initialState, Set<FixedNode> boundary) {
-        Deque<BeginNode> nodeQueue = new ArrayDeque<>();
+        Deque<AbstractBeginNode> nodeQueue = new ArrayDeque<>();
         IdentityHashMap<FixedNode, StateT> blockEndStates = new IdentityHashMap<>();
 
         StateT state = initialState;
@@ -82,13 +82,13 @@
                     current = null;
                 } else {
                     FixedNode next = ((FixedWithNextNode) current).next();
-                    closure.processNode(current, state);
+                    state = closure.processNode(current, state);
                     current = next;
                 }
             }
 
             if (current != null) {
-                closure.processNode(current, state);
+                state = closure.processNode(current, state);
 
                 NodeClassIterator successors = current.successors().iterator();
                 if (!successors.hasNext()) {
@@ -107,7 +107,7 @@
                             assert !blockEndStates.containsKey(current);
                             blockEndStates.put(current, state);
                             boolean endsVisited = true;
-                            for (EndNode forwardEnd : merge.forwardEnds()) {
+                            for (AbstractEndNode forwardEnd : merge.forwardEnds()) {
                                 if (!blockEndStates.containsKey(forwardEnd)) {
                                     endsVisited = false;
                                     break;
@@ -116,7 +116,7 @@
                             if (endsVisited) {
                                 ArrayList<StateT> states = new ArrayList<>(merge.forwardEndCount());
                                 for (int i = 0; i < merge.forwardEndCount(); i++) {
-                                    EndNode forwardEnd = merge.forwardEndAt(i);
+                                    AbstractEndNode forwardEnd = merge.forwardEndAt(i);
                                     assert blockEndStates.containsKey(forwardEnd);
                                     StateT other = blockEndStates.get(forwardEnd);
                                     states.add(other);
@@ -134,11 +134,11 @@
                         continue;
                     } else {
                         while (successors.hasNext()) {
-                            BeginNode successor = (BeginNode) successors.next();
+                            AbstractBeginNode successor = (AbstractBeginNode) successors.next();
                             blockEndStates.put(successor, closure.afterSplit(successor, state));
                             nodeQueue.add(successor);
                         }
-                        state = closure.afterSplit((BeginNode) firstSuccessor, state);
+                        state = closure.afterSplit((AbstractBeginNode) firstSuccessor, state);
                         current = firstSuccessor;
                         continue;
                     }
@@ -151,7 +151,7 @@
             } else {
                 current = nodeQueue.removeFirst();
                 state = blockEndStates.get(current);
-                assert !(current instanceof MergeNode) && current instanceof BeginNode;
+                assert !(current instanceof MergeNode) && current instanceof AbstractBeginNode;
             }
         } while (true);
     }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ScopedPostOrderNodeIterator.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ScopedPostOrderNodeIterator.java	Mon May 13 17:11:31 2013 +0200
@@ -141,7 +141,7 @@
         return result;
     }
 
-    private void queueMerge(EndNode end) {
+    private void queueMerge(AbstractEndNode end) {
         MergeNode merge = end.merge();
         if (!queuedNodes.isMarked(merge) && visitedAllEnds(merge)) {
             queue(merge);
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Mon May 13 17:11:31 2013 +0200
@@ -31,6 +31,7 @@
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity;
 import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.graph.*;
@@ -83,22 +84,23 @@
     private class MemoryScheduleClosure extends BlockIteratorClosure<HashSet<FloatingReadNode>> {
 
         @Override
-        protected void processBlock(Block block, HashSet<FloatingReadNode> currentState) {
+        protected HashSet<FloatingReadNode> processBlock(Block block, HashSet<FloatingReadNode> currentState) {
             for (Node node : getBlockToNodesMap().get(block)) {
                 if (node instanceof FloatingReadNode) {
                     currentState.add((FloatingReadNode) node);
                 } else if (node instanceof MemoryCheckpoint) {
-                    for (Object identity : ((MemoryCheckpoint) node).getLocationIdentities()) {
+                    for (LocationIdentity identity : ((MemoryCheckpoint) node).getLocationIdentities()) {
                         for (Iterator<FloatingReadNode> iter = currentState.iterator(); iter.hasNext();) {
                             FloatingReadNode read = iter.next();
                             FixedNode fixed = (FixedNode) node;
-                            if (identity == LocationNode.ANY_LOCATION || read.location().locationIdentity() == identity) {
+                            if (identity == LocationNode.ANY_LOCATION || read.location().getLocationIdentity() == identity) {
                                 addPhantomReference(read, fixed);
                             }
                         }
                     }
                 }
             }
+            return currentState;
         }
 
         public void addPhantomReference(FloatingReadNode read, FixedNode fixed) {
@@ -171,7 +173,7 @@
 
     @Override
     protected void run(StructuredGraph graph) {
-        cfg = ControlFlowGraph.compute(graph, true, true, true, false);
+        cfg = ControlFlowGraph.compute(graph, true, true, true, true);
         earliestCache = graph.createNodeMap();
         blockToNodesMap = new BlockMap<>(cfg);
 
@@ -652,7 +654,7 @@
                 }
             }
 
-            if (instruction instanceof BeginNode) {
+            if (instruction instanceof AbstractBeginNode) {
                 ArrayList<ProxyNode> proxies = (instruction instanceof LoopExitNode) ? new ArrayList<ProxyNode>() : null;
                 for (ScheduledNode inBlock : blockToNodesMap.get(b)) {
                     if (!visited.isMarked(inBlock)) {
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/MidTierContext.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/MidTierContext.java	Mon May 13 17:11:31 2013 +0200
@@ -25,17 +25,24 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.phases.*;
 
 public class MidTierContext extends PhaseContext {
 
     private final TargetDescription target;
+    private final OptimisticOptimizations optimisticOpts;
 
-    public MidTierContext(MetaAccessProvider runtime, Assumptions assumptions, Replacements replacements, TargetDescription target) {
+    public MidTierContext(MetaAccessProvider runtime, Assumptions assumptions, Replacements replacements, TargetDescription target, OptimisticOptimizations optimisticOpts) {
         super(runtime, assumptions, replacements);
         this.target = target;
+        this.optimisticOpts = optimisticOpts;
     }
 
     public TargetDescription getTarget() {
         return target;
     }
+
+    public OptimisticOptimizations getOptimisticOptimizations() {
+        return optimisticOpts;
+    }
 }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/GraphOrder.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/GraphOrder.java	Mon May 13 17:11:31 2013 +0200
@@ -39,13 +39,7 @@
 
         NodeBitMap visited = graph.createNodeBitMap();
 
-        for (ReturnNode node : graph.getNodes(ReturnNode.class)) {
-            result.visitForward(visited, node);
-        }
-        for (UnwindNode node : graph.getNodes(UnwindNode.class)) {
-            result.visitForward(visited, node);
-        }
-        for (DeoptimizeNode node : graph.getNodes(DeoptimizeNode.class)) {
+        for (ControlSinkNode node : graph.getNodes(ControlSinkNode.class)) {
             result.visitForward(visited, node);
         }
         return result;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/verify/VerifyValueUsage.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,61 @@
+/*
+ * 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.phases.verify;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.phases.*;
+
+public class VerifyValueUsage extends VerifyPhase {
+
+    private MetaAccessProvider runtime;
+
+    public VerifyValueUsage(MetaAccessProvider runtime) {
+        this.runtime = runtime;
+    }
+
+    private boolean checkType(ValueNode node) {
+        if (node.stamp() instanceof ObjectStamp) {
+            ResolvedJavaType valueType = runtime.lookupJavaType(Value.class);
+            ResolvedJavaType nodeType = node.objectStamp().type();
+
+            if (valueType.isAssignableFrom(nodeType)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    protected boolean verify(StructuredGraph graph) {
+        for (ObjectEqualsNode cn : graph.getNodes().filter(ObjectEqualsNode.class)) {
+            String desc = "VerifyValueUsage: " + cn.x() + " or " + cn.y() + " in " + graph.method() + " uses object identity. Should use equals() instead.";
+            if (!graph.method().toString().endsWith("equals(Object)>")) {
+                assert !((checkType(cn.x()) && !(cn.y() instanceof ConstantNode)) || (checkType(cn.y()) && !(cn.x() instanceof ConstantNode))) : desc;
+            }
+        }
+        return true;
+    }
+}
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java	Mon May 13 17:11:31 2013 +0200
@@ -162,7 +162,7 @@
             PhiNode phi = (PhiNode) node;
             assert nodeBlock.getBeginNode() == phi.merge();
             for (Block pred : nodeBlock.getPredecessors()) {
-                schedule(phi.valueAt((EndNode) pred.getEndNode()), pred);
+                schedule(phi.valueAt((AbstractEndNode) pred.getEndNode()), pred);
             }
 
         } else {
@@ -446,9 +446,10 @@
                 @Override
                 protected void doState(LIRFrameState state) {
                     if (state.hasDebugInfo()) {
-                        stateString.append(debugInfoToString(state.debugInfo().getBytecodePosition(), state.debugInfo().getRegisterRefMap(), state.debugInfo().getFrameRefMap(), target.arch));
+                        DebugInfo di = state.debugInfo();
+                        stateString.append(debugInfoToString(di.getBytecodePosition(), di.getRegisterRefMap(), di.getFrameRefMap(), di.getCalleeSaveInfo(), target.arch));
                     } else {
-                        stateString.append(debugInfoToString(state.topFrame, null, null, target.arch));
+                        stateString.append(debugInfoToString(state.topFrame, null, null, null, target.arch));
                     }
                 }
             });
@@ -470,7 +471,7 @@
             return "-";
         }
         String prefix;
-        if (node instanceof BeginNode && lir == null) {
+        if (node instanceof AbstractBeginNode && lir == null) {
             prefix = "B";
         } else if (node instanceof ValueNode) {
             ValueNode value = (ValueNode) node;
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java	Mon May 13 17:11:31 2013 +0200
@@ -45,7 +45,7 @@
 
     private CFGPrinter cfgPrinter;
     private File cfgFile;
-    private ResolvedJavaMethod curMethod;
+    private JavaMethod curMethod;
     private List<String> curDecorators = Collections.emptyList();
 
     @Override
@@ -64,17 +64,18 @@
      * and decorator pair.
      */
     private boolean checkMethodScope() {
-        ResolvedJavaMethod method = null;
+        JavaMethod method = null;
         ArrayList<String> decorators = new ArrayList<>();
         for (Object o : Debug.context()) {
-            if (o instanceof ResolvedJavaMethod) {
-                method = (ResolvedJavaMethod) o;
+            if (o instanceof JavaMethod) {
+                method = (JavaMethod) o;
                 decorators.clear();
             } else if (o instanceof StructuredGraph) {
                 StructuredGraph graph = (StructuredGraph) o;
-                assert graph != null && graph.method() != null : "cannot find method context for CFG dump";
-                method = graph.method();
-                decorators.clear();
+                if (graph.method() != null) {
+                    method = graph.method();
+                    decorators.clear();
+                }
             } else if (o instanceof DebugDumpScope) {
                 DebugDumpScope debugDumpScope = (DebugDumpScope) o;
                 if (debugDumpScope.decorator) {
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CompilationPrinter.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CompilationPrinter.java	Mon May 13 17:11:31 2013 +0200
@@ -114,7 +114,7 @@
     /**
      * Formats given debug info as a multi line string.
      */
-    protected String debugInfoToString(BytecodePosition codePos, BitSet registerRefMap, BitSet frameRefMap, Architecture arch) {
+    protected String debugInfoToString(BytecodePosition codePos, BitSet registerRefMap, BitSet frameRefMap, RegisterSaveLayout calleeSaveInfo, Architecture arch) {
         StringBuilder sb = new StringBuilder();
 
         if (registerRefMap != null) {
@@ -128,8 +128,16 @@
 
         if (frameRefMap != null) {
             sb.append("frame-ref-map:");
-            for (int reg = frameRefMap.nextSetBit(0); reg >= 0; reg = frameRefMap.nextSetBit(reg + 1)) {
-                sb.append(' ').append("s").append(reg);
+            for (int slot = frameRefMap.nextSetBit(0); slot >= 0; slot = frameRefMap.nextSetBit(slot + 1)) {
+                sb.append(' ').append("s").append(slot);
+            }
+            sb.append("\n");
+        }
+
+        if (calleeSaveInfo != null) {
+            sb.append("callee-save-info:");
+            for (Map.Entry<Register, Integer> e : calleeSaveInfo.registersToSlots(true).entrySet()) {
+                sb.append(" " + e.getKey() + " -> s" + e.getValue());
             }
             sb.append("\n");
         }
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/GraphPrinterDumpHandler.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/GraphPrinterDumpHandler.java	Mon May 13 17:11:31 2013 +0200
@@ -30,6 +30,7 @@
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.phases.*;
@@ -180,10 +181,18 @@
 
     private static List<String> getInlineContext() {
         List<String> result = new ArrayList<>();
+        Object last = null;
         for (Object o : Debug.context()) {
-            if (o instanceof ResolvedJavaMethod) {
-                ResolvedJavaMethod method = (ResolvedJavaMethod) o;
-                result.add(MetaUtil.format("%H::%n(%p)", method));
+            JavaMethod method = GraalDebugConfig.asJavaMethod(o);
+            if (method != null) {
+                if (last != method) {
+                    result.add(MetaUtil.format("%H::%n(%p)", method));
+                } else {
+                    // This prevents multiple adjacent method context objects for the same method
+                    // from resulting in multiple IGV tree levels. This works on the
+                    // assumption that real inlining debug scopes will have a graph
+                    // context object between the inliner and inlinee context objects.
+                }
             } else if (o instanceof DebugDumpScope) {
                 DebugDumpScope debugDumpScope = (DebugDumpScope) o;
                 if (debugDumpScope.decorator && !result.isEmpty()) {
@@ -192,6 +201,7 @@
                     result.add(debugDumpScope.name);
                 }
             }
+            last = o;
         }
         if (result.isEmpty()) {
             result.add("Top Scope");
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinter.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinter.java	Mon May 13 17:11:31 2013 +0200
@@ -165,9 +165,9 @@
                     printProperty(bit, "true");
                 }
             }
-            if (node.getClass() == BeginNode.class) {
+            if (node.getClass() == AbstractBeginNode.class) {
                 printProperty("shortName", "B");
-            } else if (node.getClass() == EndNode.class) {
+            } else if (node.getClass() == AbstractEndNode.class) {
                 printProperty("shortName", "E");
             }
             if (node.predecessor() != null) {
--- a/graal/com.oracle.graal.ptx/src/com/oracle/graal/ptx/PTX.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.ptx/src/com/oracle/graal/ptx/PTX.java	Mon May 13 17:11:31 2013 +0200
@@ -23,18 +23,21 @@
 package com.oracle.graal.ptx;
 
 import static com.oracle.graal.api.code.MemoryBarriers.*;
-import static com.oracle.graal.api.code.Register.RegisterFlag.*;
 
 import java.nio.*;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.Register.*;
+import com.oracle.graal.api.code.Register.RegisterCategory;
+import com.oracle.graal.api.meta.*;
 
 /**
  * Represents the PTX architecture.
  */
 public class PTX extends Architecture {
 
+    public static final RegisterCategory CPU = new RegisterCategory("CPU");
+    public static final RegisterCategory FPU = new RegisterCategory("FPU");
+
     // @formatter:off
 
     /*
@@ -49,23 +52,23 @@
      */
 
     // General purpose registers
-    public static final Register r0  = new Register(0,  0,  8, "r0",  CPU, RegisterFlag.Byte);
-    public static final Register r1  = new Register(1,  1,  8, "r1",  CPU, RegisterFlag.Byte);
-    public static final Register r2  = new Register(2,  2,  8, "r2",  CPU, RegisterFlag.Byte);
-    public static final Register r3  = new Register(3,  3,  8, "r3",  CPU, RegisterFlag.Byte);
-    public static final Register r4  = new Register(4,  4,  8, "r4",  CPU, RegisterFlag.Byte);
-    public static final Register r5  = new Register(5,  5,  8, "r5",  CPU, RegisterFlag.Byte);
-    public static final Register r6  = new Register(6,  6,  8, "r6",  CPU, RegisterFlag.Byte);
-    public static final Register r7  = new Register(7,  7,  8, "r7",  CPU, RegisterFlag.Byte);
+    public static final Register r0  = new Register(0,  0,  "r0",  CPU);
+    public static final Register r1  = new Register(1,  1,  "r1",  CPU);
+    public static final Register r2  = new Register(2,  2,  "r2",  CPU);
+    public static final Register r3  = new Register(3,  3,  "r3",  CPU);
+    public static final Register r4  = new Register(4,  4,  "r4",  CPU);
+    public static final Register r5  = new Register(5,  5,  "r5",  CPU);
+    public static final Register r6  = new Register(6,  6,  "r6",  CPU);
+    public static final Register r7  = new Register(7,  7,  "r7",  CPU);
 
-    public static final Register r8  = new Register(8,  8,  8, "r8",  CPU, RegisterFlag.Byte);
-    public static final Register r9  = new Register(9,  9,  8, "r9",  CPU, RegisterFlag.Byte);
-    public static final Register r10 = new Register(10, 10, 8, "r10", CPU, RegisterFlag.Byte);
-    public static final Register r11 = new Register(11, 11, 8, "r11", CPU, RegisterFlag.Byte);
-    public static final Register r12 = new Register(12, 12, 8, "r12", CPU, RegisterFlag.Byte);
-    public static final Register r13 = new Register(13, 13, 8, "r13", CPU, RegisterFlag.Byte);
-    public static final Register r14 = new Register(14, 14, 8, "r14", CPU, RegisterFlag.Byte);
-    public static final Register r15 = new Register(15, 15, 8, "r15", CPU, RegisterFlag.Byte);
+    public static final Register r8  = new Register(8,  8,  "r8",  CPU);
+    public static final Register r9  = new Register(9,  9,  "r9",  CPU);
+    public static final Register r10 = new Register(10, 10, "r10", CPU);
+    public static final Register r11 = new Register(11, 11, "r11", CPU);
+    public static final Register r12 = new Register(12, 12, "r12", CPU);
+    public static final Register r13 = new Register(13, 13, "r13", CPU);
+    public static final Register r14 = new Register(14, 14, "r14", CPU);
+    public static final Register r15 = new Register(15, 15, "r15", CPU);
 
     public static final Register[] gprRegisters = {
         r0,  r1,  r2,  r3,  r4,  r5,  r6,  r7,
@@ -73,23 +76,23 @@
     };
 
     // Floating point registers
-    public static final Register f0  = new Register(16, 0,  8, "f0",  FPU);
-    public static final Register f1  = new Register(17, 1,  8, "f1",  FPU);
-    public static final Register f2  = new Register(18, 2,  8, "f2",  FPU);
-    public static final Register f3  = new Register(19, 3,  8, "f3",  FPU);
-    public static final Register f4  = new Register(20, 4,  8, "f4",  FPU);
-    public static final Register f5  = new Register(21, 5,  8, "f5",  FPU);
-    public static final Register f6  = new Register(22, 6,  8, "f6",  FPU);
-    public static final Register f7  = new Register(23, 7,  8, "f7",  FPU);
+    public static final Register f0  = new Register(16, 0,  "f0",  FPU);
+    public static final Register f1  = new Register(17, 1,  "f1",  FPU);
+    public static final Register f2  = new Register(18, 2,  "f2",  FPU);
+    public static final Register f3  = new Register(19, 3,  "f3",  FPU);
+    public static final Register f4  = new Register(20, 4,  "f4",  FPU);
+    public static final Register f5  = new Register(21, 5,  "f5",  FPU);
+    public static final Register f6  = new Register(22, 6,  "f6",  FPU);
+    public static final Register f7  = new Register(23, 7,  "f7",  FPU);
 
-    public static final Register f8  = new Register(24, 8,  8, "f8",  FPU);
-    public static final Register f9  = new Register(25, 9,  8, "f9",  FPU);
-    public static final Register f10 = new Register(26, 10, 8, "f10", FPU);
-    public static final Register f11 = new Register(27, 11, 8, "f11", FPU);
-    public static final Register f12 = new Register(28, 12, 8, "f12", FPU);
-    public static final Register f13 = new Register(29, 13, 8, "f13", FPU);
-    public static final Register f14 = new Register(30, 14, 8, "f14", FPU);
-    public static final Register f15 = new Register(31, 15, 8, "f15", FPU);
+    public static final Register f8  = new Register(24, 8,  "f8",  FPU);
+    public static final Register f9  = new Register(25, 9,  "f9",  FPU);
+    public static final Register f10 = new Register(26, 10, "f10", FPU);
+    public static final Register f11 = new Register(27, 11, "f11", FPU);
+    public static final Register f12 = new Register(28, 12, "f12", FPU);
+    public static final Register f13 = new Register(29, 13, "f13", FPU);
+    public static final Register f14 = new Register(30, 14, "f14", FPU);
+    public static final Register f15 = new Register(31, 15, "f15", FPU);
 
     public static final Register[] fpuRegisters = {
         f0,  f1,  f2,  f3,  f4,  f5,  f6,  f7,
@@ -116,4 +119,44 @@
               8);
     }
     // @formatter:on
+
+    @Override
+    public boolean canStoreValue(RegisterCategory category, PlatformKind platformKind) {
+        if (!(platformKind instanceof Kind)) {
+            return false;
+        }
+
+        Kind kind = (Kind) platformKind;
+        if (category == CPU) {
+            switch (kind) {
+                case Boolean:
+                case Byte:
+                case Char:
+                case Short:
+                case Int:
+                case Long:
+                case Object:
+                    return true;
+            }
+        } else if (category == FPU) {
+            switch (kind) {
+                case Float:
+                case Double:
+                    return true;
+            }
+        }
+
+        return false;
+    }
+
+    @Override
+    public PlatformKind getLargestStorableKind(RegisterCategory category) {
+        if (category == CPU) {
+            return Kind.Long;
+        } else if (category == FPU) {
+            return Kind.Double;
+        } else {
+            return Kind.Illegal;
+        }
+    }
 }
--- a/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64ConvertSnippets.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64ConvertSnippets.java	Mon May 13 17:11:31 2013 +0200
@@ -28,6 +28,7 @@
 import java.util.*;
 
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
@@ -148,7 +149,7 @@
 
         private final EnumMap<Op, SnippetInfo> snippets;
 
-        public Templates(CodeCacheProvider runtime, Replacements replacements, TargetDescription target) {
+        public Templates(MetaAccessProvider runtime, Replacements replacements, TargetDescription target) {
             super(runtime, replacements, target);
 
             snippets = new EnumMap<>(Op.class);
@@ -164,7 +165,7 @@
                 return;
             }
 
-            StructuredGraph graph = (StructuredGraph) convert.graph();
+            StructuredGraph graph = convert.graph();
 
             // Insert a unique placeholder node in place of the Convert node so that the
             // Convert node can be used as an input to the snippet. All usage of the
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/CheckCastTest.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/CheckCastTest.java	Mon May 13 17:11:31 2013 +0200
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.replacements.test;
 
-
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.test.*;
 import com.oracle.graal.nodes.*;
@@ -37,7 +36,7 @@
     protected void replaceProfile(StructuredGraph graph, JavaTypeProfile profile) {
         CheckCastNode ccn = graph.getNodes(CheckCastNode.class).first();
         if (ccn != null) {
-            CheckCastNode ccnNew = graph.add(new CheckCastNode(ccn.type(), ccn.object(), profile));
+            CheckCastNode ccnNew = graph.add(new CheckCastNode(ccn.type(), ccn.object(), profile, false));
             graph.replaceFixedWithFixed(ccn, ccnNew);
         }
     }
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/CompiledExceptionHandlerTest.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/CompiledExceptionHandlerTest.java	Mon May 13 17:11:31 2013 +0200
@@ -64,6 +64,7 @@
         }
 
         test("test1Snippet", "a string");
+        test("test1Snippet", (String) null);
     }
 
     public static String test1Snippet(String message) {
@@ -76,4 +77,51 @@
         }
         return null;
     }
+
+    private static void raiseException(String m1, String m2, String m3, String m4, String m5) {
+        throw new RuntimeException(m1 + m2 + m3 + m4 + m5);
+    }
+
+    @Test
+    public void test2() {
+        // Ensure the profile shows a hot exception
+        for (int i = 0; i < 10000; i++) {
+            test2Snippet("m1", "m2", "m3", "m4", "m5");
+            test2Snippet(null, "m2", "m3", "m4", "m5");
+        }
+
+        test("test2Snippet", "m1", "m2", "m3", "m4", "m5");
+        test("test2Snippet", null, "m2", "m3", "m4", "m5");
+    }
+
+    public static String test2Snippet(String m1, String m2, String m3, String m4, String m5) {
+        if (m1 != null) {
+            try {
+                raiseException(m1, m2, m3, m4, m5);
+            } catch (Exception e) {
+                return m5 + m4 + m3 + m2 + m1;
+            }
+        }
+        return m4 + m3;
+    }
+
+    @Test
+    public void test3() {
+        // Ensure the profile shows a hot exception
+        for (int i = 0; i < 10000; i++) {
+            test3Snippet("object1", "object2");
+            test3Snippet(null, "object2");
+        }
+
+        test("test3Snippet", (Object) null, "object2");
+        test("test3Snippet", "object1", "object2");
+    }
+
+    public static String test3Snippet(Object o, Object o2) {
+        try {
+            return o.toString();
+        } catch (NullPointerException e) {
+            return String.valueOf(o2);
+        }
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/DeoptimizeOnExceptionTest.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.replacements.test;
+
+import org.junit.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.test.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.common.*;
+
+/**
+ * Tests that deoptimization upon exception handling works.
+ */
+public class DeoptimizeOnExceptionTest extends GraalCompilerTest {
+
+    @Override
+    protected void editPhasePlan(ResolvedJavaMethod method, StructuredGraph graph, PhasePlan phasePlan) {
+        phasePlan.disablePhase(InliningPhase.class);
+    }
+
+    private static void raiseException(String m1, String m2, String m3, String m4, String m5) {
+        throw new RuntimeException(m1 + m2 + m3 + m4 + m5);
+    }
+
+    @Test
+    public void test1() {
+        test("test1Snippet", "m1", "m2", "m3", "m4", "m5");
+    }
+
+    // no local exception handler - will deopt
+    public static String test1Snippet(String m1, String m2, String m3, String m4, String m5) {
+        if (m1 != null) {
+            raiseException(m1, m2, m3, m4, m5);
+        }
+        return m1 + m2 + m3 + m4 + m5;
+    }
+}
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java	Mon May 13 17:11:31 2013 +0200
@@ -33,6 +33,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.Snippet.*;
 import com.oracle.graal.word.*;
@@ -42,7 +43,7 @@
  */
 public class PointerTest extends GraalCompilerTest implements Snippets {
 
-    private static final Object ID = new Object();
+    private static final LocationIdentity ID = LocationNode.createLocation("ID");
     private static final Kind[] KINDS = new Kind[]{Kind.Byte, Kind.Char, Kind.Short, Kind.Int, Kind.Long, Kind.Float, Kind.Double, Kind.Object};
     private final TargetDescription target;
     private final ReplacementsImpl installer;
@@ -102,7 +103,7 @@
         }
     }
 
-    private void assertRead(StructuredGraph graph, Kind kind, boolean indexConvert, Object locationIdentity) {
+    private void assertRead(StructuredGraph graph, Kind kind, boolean indexConvert, LocationIdentity locationIdentity) {
         ReadNode read = (ReadNode) graph.start().next();
         Assert.assertEquals(kind.getStackKind(), read.kind());
 
@@ -112,22 +113,22 @@
 
         IndexedLocationNode location = (IndexedLocationNode) read.location();
         Assert.assertEquals(kind, location.getValueKind());
-        Assert.assertEquals(locationIdentity, location.locationIdentity());
-        Assert.assertEquals(1, location.indexScaling());
+        Assert.assertEquals(locationIdentity, location.getLocationIdentity());
+        Assert.assertEquals(1, location.getIndexScaling());
 
         if (indexConvert) {
-            ConvertNode convert = (ConvertNode) location.index();
+            ConvertNode convert = (ConvertNode) location.getIndex();
             Assert.assertEquals(ConvertNode.Op.I2L, convert.opcode);
             Assert.assertEquals(graph.getLocal(1), convert.value());
         } else {
-            Assert.assertEquals(graph.getLocal(1), location.index());
+            Assert.assertEquals(graph.getLocal(1), location.getIndex());
         }
 
         ReturnNode ret = (ReturnNode) read.next();
         Assert.assertEquals(read, ret.result());
     }
 
-    private void assertWrite(StructuredGraph graph, Kind kind, boolean indexConvert, Object locationIdentity) {
+    private void assertWrite(StructuredGraph graph, Kind kind, boolean indexConvert, LocationIdentity locationIdentity) {
         WriteNode write = (WriteNode) graph.start().next();
         Assert.assertEquals(graph.getLocal(2), write.value());
         Assert.assertEquals(Kind.Void, write.kind());
@@ -139,15 +140,15 @@
 
         IndexedLocationNode location = (IndexedLocationNode) write.location();
         Assert.assertEquals(kind, location.getValueKind());
-        Assert.assertEquals(locationIdentity, location.locationIdentity());
-        Assert.assertEquals(1, location.indexScaling());
+        Assert.assertEquals(locationIdentity, location.getLocationIdentity());
+        Assert.assertEquals(1, location.getIndexScaling());
 
         if (indexConvert) {
-            ConvertNode convert = (ConvertNode) location.index();
+            ConvertNode convert = (ConvertNode) location.getIndex();
             Assert.assertEquals(ConvertNode.Op.I2L, convert.opcode);
             Assert.assertEquals(graph.getLocal(1), convert.value());
         } else {
-            Assert.assertEquals(graph.getLocal(1), location.index());
+            Assert.assertEquals(graph.getLocal(1), location.getIndex());
         }
 
         AbstractStateSplit stateSplit = (AbstractStateSplit) write.next();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/UnwindExceptionToCallerTest.java	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.replacements.test;
+
+import org.junit.*;
+
+import com.oracle.graal.compiler.test.*;
+
+/**
+ * Tests exception throwing from Graal compiled code.
+ */
+public class UnwindExceptionToCallerTest extends GraalCompilerTest {
+
+    @Test
+    public void test1() {
+        NullPointerException npe = new NullPointerException();
+        test("test1Snippet", "a string", npe);
+        test("test1Snippet", (String) null, npe);
+    }
+
+    public static String test1Snippet(String message, NullPointerException npe) {
+        if (message == null) {
+            throw npe;
+        }
+        return message;
+    }
+}
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BoxingSnippets.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BoxingSnippets.java	Mon May 13 17:11:31 2013 +0200
@@ -205,7 +205,7 @@
         private final EnumMap<Kind, SnippetInfo> boxSnippets = new EnumMap<>(Kind.class);
         private final EnumMap<Kind, SnippetInfo> unboxSnippets = new EnumMap<>(Kind.class);
 
-        public Templates(CodeCacheProvider runtime, Replacements replacements, TargetDescription target) {
+        public Templates(MetaAccessProvider runtime, Replacements replacements, TargetDescription target) {
             super(runtime, replacements, target);
             for (Kind kind : new Kind[]{Kind.Boolean, Kind.Byte, Kind.Char, Kind.Double, Kind.Float, Kind.Int, Kind.Long, Kind.Short}) {
                 boxSnippets.put(kind, snippet(BoxingSnippets.class, kind.getJavaName() + "ValueOf"));
@@ -216,7 +216,7 @@
         public void lower(BoxNode box) {
             FloatingNode canonical = canonicalizeBoxing(box, runtime);
             if (canonical != null) {
-                ((StructuredGraph) box.graph()).replaceFixedWithFloating(box, canonical);
+                box.graph().replaceFixedWithFloating(box, canonical);
             } else {
                 Arguments args = new Arguments(boxSnippets.get(box.getBoxingKind()));
                 args.add("value", box.getValue());
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/InstanceOfSnippetsTemplates.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/InstanceOfSnippetsTemplates.java	Mon May 13 17:11:31 2013 +0200
@@ -97,8 +97,8 @@
      */
     protected InstanceOfUsageReplacer createReplacer(FloatingNode instanceOf, LoweringTool tool, int nUsages, Instantiation instantiation, Node usage, final StructuredGraph graph) {
         InstanceOfUsageReplacer replacer;
-        if (usage instanceof IfNode) {
-            replacer = new IfUsageReplacer(instantiation, ConstantNode.forInt(1, graph), ConstantNode.forInt(0, graph), instanceOf, (IfNode) usage);
+        if (usage instanceof IfNode || usage instanceof FixedGuardNode) {
+            replacer = new IfUsageReplacer(instantiation, ConstantNode.forInt(1, graph), ConstantNode.forInt(0, graph), instanceOf, (FixedNode) usage);
         } else {
             assert usage instanceof ConditionalNode : "unexpected usage of " + instanceOf + ": " + usage;
             ConditionalNode c = (ConditionalNode) usage;
@@ -193,9 +193,9 @@
      */
     public static class IfUsageReplacer extends InstanceOfUsageReplacer {
 
-        private final IfNode usage;
+        private final FixedNode usage;
 
-        public IfUsageReplacer(Instantiation instantiation, ValueNode trueValue, ValueNode falseValue, FloatingNode instanceOf, IfNode usage) {
+        public IfUsageReplacer(Instantiation instantiation, ValueNode trueValue, ValueNode falseValue, FloatingNode instanceOf, FixedNode usage) {
             super(instantiation, instanceOf, trueValue, falseValue);
             this.usage = usage;
         }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java	Mon May 13 17:11:31 2013 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.replacements;
 
+import static com.oracle.graal.api.meta.MetaUtil.*;
+
 import java.lang.reflect.*;
 import java.util.*;
 
@@ -178,7 +180,8 @@
         } else {
             result = runtime.lookupJavaType(intrinsic.value());
         }
-        assert runtime.lookupJavaType(ValueNode.class).isAssignableFrom(result);
+        assert runtime.lookupJavaType(ValueNode.class).isAssignableFrom(result) : "Node intrinsic class " + toJavaName(result, false) + " derived from @" + NodeIntrinsic.class.getSimpleName() +
+                        " annotation on " + format("%H.%n(%p)", target) + " is not a subclass of " + ValueNode.class;
         return result;
     }
 
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationVerificationPhase.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationVerificationPhase.java	Mon May 13 17:11:31 2013 +0200
@@ -57,7 +57,7 @@
     }
 
     private static void error(MethodCallTargetNode n, String failedAction) throws GraalInternalError {
-        String context = MetaUtil.format("%H.%n", ((StructuredGraph) n.graph()).method());
+        String context = MetaUtil.format("%H.%n", n.graph().method());
         String target = n.invoke().callTarget().targetName();
         throw new GraalInternalError(failedAction + " of call to '" + target + "' in '" + context + "' failed, most likely due to a parameter annotated with @" +
                         ConstantNodeParameter.class.getSimpleName() + " not being resolvable to a constant during compilation");
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Mon May 13 17:11:31 2013 +0200
@@ -282,6 +282,7 @@
             if (!SnippetTemplate.hasConstantParameter(method)) {
                 NodeIntrinsificationVerificationPhase.verify(graph);
             }
+            new ConvertDeoptimizeToGuardPhase().apply(graph);
 
             if (original == null) {
                 new SnippetFrameStateCleanupPhase().apply(graph);
@@ -295,7 +296,14 @@
         private StructuredGraph parseGraph(final ResolvedJavaMethod methodToParse, final SnippetInliningPolicy policy) {
             StructuredGraph graph = graphCache.get(methodToParse);
             if (graph == null) {
-                graphCache.putIfAbsent(methodToParse, buildGraph(methodToParse, policy == null ? inliningPolicy(methodToParse) : policy));
+                StructuredGraph newGraph = Debug.scope("ParseGraph", new Object[]{methodToParse}, new Callable<StructuredGraph>() {
+
+                    public StructuredGraph call() throws Exception {
+                        return buildGraph(methodToParse, policy == null ? inliningPolicy(methodToParse) : policy);
+                    }
+                });
+
+                graphCache.putIfAbsent(methodToParse, newGraph);
                 graph = graphCache.get(methodToParse);
                 assert graph != null;
             }
@@ -311,9 +319,11 @@
             GraphBuilderPhase graphBuilder = new GraphBuilderPhase(runtime, config, OptimisticOptimizations.NONE);
             graphBuilder.apply(graph);
 
-            Debug.dump(graph, "%s: %s", methodToParse.getName(), GraphBuilderPhase.class.getSimpleName());
-
             new WordTypeVerificationPhase(runtime, target.wordKind).apply(graph);
+            if (GraalOptions.OptCanonicalizer) {
+                new WordTypeRewriterPhase(runtime, target.wordKind).apply(graph);
+                new CanonicalizerPhase.Instance(runtime, assumptions).apply(graph);
+            }
 
             return graph;
         }
@@ -360,12 +370,18 @@
                     afterInline(graph, originalGraph);
                     substituteCallsOriginal = true;
                 } else {
-                    if ((callTarget.invokeKind() == InvokeKind.Static || callTarget.invokeKind() == InvokeKind.Special) && policy.shouldInline(callee, methodToParse)) {
+                    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;
-                        StructuredGraph intrinsicGraph = InliningUtil.getIntrinsicGraph(ReplacementsImpl.this, callee);
                         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);
                         }
                         InliningUtil.inline(callTarget.invoke(), targetGraph, true);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetFrameStateCleanupPhase.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetFrameStateCleanupPhase.java	Mon May 13 17:11:31 2013 +0200
@@ -45,33 +45,24 @@
 
     @Override
     protected void run(StructuredGraph graph) {
-        ReentrantNodeIterator.apply(new SnippetFrameStateCleanupClosure(), graph.start(), new CleanupState(false), null);
-    }
-
-    private static class CleanupState {
-
-        public boolean containsFrameState;
-
-        public CleanupState(boolean containsFrameState) {
-            this.containsFrameState = containsFrameState;
-        }
+        ReentrantNodeIterator.apply(new SnippetFrameStateCleanupClosure(), graph.start(), false, null);
     }
 
     /**
      * A proper (loop-aware) iteration over the graph is used to detect loops that contain invalid
      * frame states, so that they can be marked with an invalid frame state.
      */
-    private static class SnippetFrameStateCleanupClosure extends NodeIteratorClosure<CleanupState> {
+    private static class SnippetFrameStateCleanupClosure extends NodeIteratorClosure<Boolean> {
 
         @Override
-        protected void processNode(FixedNode node, CleanupState currentState) {
+        protected Boolean processNode(FixedNode node, Boolean currentState) {
             if (node instanceof StateSplit) {
                 StateSplit stateSplit = (StateSplit) node;
                 FrameState frameState = stateSplit.stateAfter();
                 if (frameState != null) {
                     if (stateSplit.hasSideEffect()) {
-                        currentState.containsFrameState = true;
                         stateSplit.setStateAfter(node.graph().add(new FrameState(FrameState.INVALID_FRAMESTATE_BCI)));
+                        return true;
                     } else {
                         stateSplit.setStateAfter(null);
                     }
@@ -80,36 +71,37 @@
                     }
                 }
             }
+            return currentState;
         }
 
         @Override
-        protected CleanupState merge(MergeNode merge, List<CleanupState> states) {
-            for (CleanupState state : states) {
-                if (state.containsFrameState) {
-                    return new CleanupState(true);
+        protected Boolean merge(MergeNode merge, List<Boolean> states) {
+            for (boolean state : states) {
+                if (state) {
+                    return true;
                 }
             }
-            return new CleanupState(false);
+            return false;
         }
 
         @Override
-        protected CleanupState afterSplit(BeginNode node, CleanupState oldState) {
-            return new CleanupState(oldState.containsFrameState);
+        protected Boolean afterSplit(AbstractBeginNode node, Boolean oldState) {
+            return oldState;
         }
 
         @Override
-        protected Map<LoopExitNode, CleanupState> processLoop(LoopBeginNode loop, CleanupState initialState) {
-            LoopInfo<CleanupState> info = ReentrantNodeIterator.processLoop(this, loop, new CleanupState(false));
+        protected Map<LoopExitNode, Boolean> processLoop(LoopBeginNode loop, Boolean initialState) {
+            LoopInfo<Boolean> info = ReentrantNodeIterator.processLoop(this, loop, false);
             boolean containsFrameState = false;
-            for (CleanupState state : info.endStates.values()) {
-                containsFrameState |= state.containsFrameState;
+            for (Boolean state : info.endStates.values()) {
+                containsFrameState |= state;
             }
             if (containsFrameState) {
                 loop.setStateAfter(loop.graph().add(new FrameState(FrameState.INVALID_FRAMESTATE_BCI)));
             }
-            if (containsFrameState || initialState.containsFrameState) {
-                for (CleanupState state : info.exitStates.values()) {
-                    state.containsFrameState = true;
+            if (containsFrameState || initialState) {
+                for (Map.Entry<?, Boolean> entry : info.exitStates.entrySet()) {
+                    entry.setValue(true);
                 }
             }
             return info.exitStates;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Mon May 13 17:11:31 2013 +0200
@@ -116,6 +116,10 @@
         public boolean isVarargsParameter(int paramIdx) {
             return varargsParameters[paramIdx];
         }
+
+        public String getParameterName(int paramIdx) {
+            return names[paramIdx];
+        }
     }
 
     /**
@@ -283,16 +287,20 @@
             this.templates = new ConcurrentHashMap<>();
         }
 
+        /**
+         * Finds the method in {@code declaringClass} annotated with {@link Snippet} named
+         * {@code methodName}. If {@code methodName} is null, then there must be exactly one snippet
+         * method in {@code declaringClass}.
+         */
         protected SnippetInfo snippet(Class<? extends Snippets> declaringClass, String methodName) {
             Method found = null;
             for (Method method : declaringClass.getDeclaredMethods()) {
-                if (method.getAnnotation(Snippet.class) != null && method.getName().equals(methodName)) {
-                    assert found == null : "found more than one @" + Snippet.class.getSimpleName() + " method " + methodName + " in " + declaringClass;
+                if (method.getAnnotation(Snippet.class) != null && (methodName == null || method.getName().equals(methodName))) {
+                    assert found == null : "found more than one @" + Snippet.class.getSimpleName() + " method in " + declaringClass + (methodName == null ? "" : " named " + methodName);
                     found = method;
                 }
             }
-            assert found != null : "did not find @" + Snippet.class.getSimpleName() + " method " + methodName + " in " + declaringClass;
-
+            assert found != null : "did not find @" + Snippet.class.getSimpleName() + " method in " + declaringClass + (methodName == null ? "" : " named " + methodName);
             return new SnippetInfo(runtime.lookupJavaMethod(found));
         }
 
@@ -432,7 +440,7 @@
                 if (loopBegin != null) {
                     LoopEx loop = new LoopsData(snippetCopy).loop(loopBegin);
                     int mark = snippetCopy.getMark();
-                    LoopTransformations.fullUnroll(loop, runtime, null);
+                    LoopTransformations.fullUnroll(loop, runtime, replacements.getAssumptions());
                     new CanonicalizerPhase.Instance(runtime, replacements.getAssumptions(), mark, null).apply(snippetCopy);
                 }
                 FixedNode explodeLoopNext = explodeLoop.next();
@@ -680,7 +688,7 @@
         StructuredGraph snippetCopy = new StructuredGraph(name, snippet.method());
         StartNode entryPointNode = snippet.start();
         FixedNode firstCFGNode = entryPointNode.next();
-        StructuredGraph replaceeGraph = (StructuredGraph) replacee.graph();
+        StructuredGraph replaceeGraph = replacee.graph();
         IdentityHashMap<Node, Node> replacements = bind(replaceeGraph, runtime, args);
         Map<Node, Node> duplicates = replaceeGraph.addDuplicates(nodes, replacements);
         Debug.dump(replaceeGraph, "After inlining snippet %s", snippetCopy.method());
@@ -756,7 +764,7 @@
         StructuredGraph snippetCopy = new StructuredGraph(name, snippet.method());
         StartNode entryPointNode = snippet.start();
         FixedNode firstCFGNode = entryPointNode.next();
-        StructuredGraph replaceeGraph = (StructuredGraph) replacee.graph();
+        StructuredGraph replaceeGraph = replacee.graph();
         IdentityHashMap<Node, Node> replacements = bind(replaceeGraph, runtime, args);
         Map<Node, Node> duplicates = replaceeGraph.addDuplicates(nodes, replacements);
         Debug.dump(replaceeGraph, "After inlining snippet %s", snippetCopy.method());
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BranchProbabilityNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BranchProbabilityNode.java	Mon May 13 17:11:31 2013 +0200
@@ -43,8 +43,8 @@
     public static final double FAST_PATH_PROBABILITY = 0.99;
     public static final double SLOW_PATH_PROBABILITY = 1 - FAST_PATH_PROBABILITY;
 
-    public static final double VERY_FAST_DEOPT_PATH_PROBABILITY = 0.999;
-    public static final double VERY_SLOW_PATH_PROBABILITY = 1 - VERY_FAST_DEOPT_PATH_PROBABILITY;
+    public static final double VERY_FAST_PATH_PROBABILITY = 0.999;
+    public static final double VERY_SLOW_PATH_PROBABILITY = 1 - VERY_FAST_PATH_PROBABILITY;
 
     @Input private ValueNode probability;
     @Input private ValueNode condition;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectObjectStoreNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectObjectStoreNode.java	Mon May 13 17:11:31 2013 +0200
@@ -62,9 +62,8 @@
 
     @Override
     public void lower(LoweringTool tool, LoweringType loweringType) {
-        StructuredGraph graph = (StructuredGraph) this.graph();
-        IndexedLocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, value.kind(), displacement, offset, graph, 1);
-        WriteNode write = graph.add(new WriteNode(object, value, location, WriteBarrierType.NONE));
-        graph.replaceFixedWithFixed(this, write);
+        IndexedLocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, value.kind(), displacement, offset, graph(), 1);
+        WriteNode write = graph().add(new WriteNode(object, value, location, WriteBarrierType.NONE));
+        graph().replaceFixedWithFixed(this, write);
     }
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Mon May 13 17:11:31 2013 +0200
@@ -80,7 +80,7 @@
 
     private InvokeNode replaceWithInvoke() {
         InvokeNode invoke = createInvoke();
-        ((StructuredGraph) graph()).replaceFixedWithFixed(this, invoke);
+        graph().replaceFixedWithFixed(this, invoke);
         return invoke;
     }
 
--- a/graal/com.oracle.graal.sparc/src/com/oracle/graal/sparc/SPARC.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.sparc/src/com/oracle/graal/sparc/SPARC.java	Mon May 13 17:11:31 2013 +0200
@@ -27,6 +27,8 @@
 import java.nio.*;
 
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.code.Register.RegisterCategory;
+import com.oracle.graal.api.meta.*;
 
 /**
  * Represents the SPARC architecture.
@@ -39,4 +41,16 @@
         super("AMD64", 8, ByteOrder.LITTLE_ENDIAN, null, LOAD_STORE | STORE_STORE, 1, 0, 8);
         // SPARC: Fix architecture parameters.
     }
+
+    @Override
+    public boolean canStoreValue(RegisterCategory category, PlatformKind kind) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public PlatformKind getLargestStorableKind(RegisterCategory category) {
+        // TODO Auto-generated method stub
+        return null;
+    }
 }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/nodes/CyclicMaterializeStoreNode.java	Mon May 13 16:46:39 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,96 +0,0 @@
-/*
- * 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.virtual.nodes;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.nodes.virtual.*;
-
-@NodeInfo(nameTemplate = "MaterializeStore#{p#target/s}")
-public final class CyclicMaterializeStoreNode extends FixedWithNextNode implements Lowerable, Virtualizable {
-
-    @Input private ValueNode object;
-    @Input private ValueNode value;
-    private final Object target;
-
-    public ValueNode object() {
-        return object;
-    }
-
-    public ValueNode value() {
-        return value;
-    }
-
-    public ResolvedJavaField targetField() {
-        return (ResolvedJavaField) target;
-    }
-
-    public int targetIndex() {
-        return (int) target;
-    }
-
-    public CyclicMaterializeStoreNode(ValueNode object, ValueNode value, ResolvedJavaField field) {
-        super(StampFactory.forVoid());
-        this.object = object;
-        this.value = value;
-        this.target = field;
-    }
-
-    public CyclicMaterializeStoreNode(ValueNode object, ValueNode value, int index) {
-        super(StampFactory.forVoid());
-        this.object = object;
-        this.value = value;
-        this.target = index;
-    }
-
-    @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
-        StructuredGraph graph = (StructuredGraph) graph();
-        ResolvedJavaType type = object.objectStamp().type();
-        FixedWithNextNode store;
-        if (target instanceof Integer) {
-            store = graph.add(new StoreIndexedNode(object, ConstantNode.forInt((int) target, graph), type.getComponentType().getKind(), value));
-        } else {
-            assert target instanceof ResolvedJavaField;
-            store = graph.add(new StoreFieldNode(object, (ResolvedJavaField) target, value));
-        }
-        graph.replaceFixedWithFixed(this, store);
-    }
-
-    @Override
-    public void virtualize(VirtualizerTool tool) {
-        State state = tool.getObjectState(object);
-        if (state != null && state.getState() == EscapeState.Virtual) {
-            if (state.getVirtualObject() instanceof VirtualArrayNode) {
-                tool.setVirtualEntry(state, targetIndex(), value());
-            } else {
-                tool.setVirtualEntry(state, ((VirtualInstanceNode) state.getVirtualObject()).fieldIndex(targetField()), value());
-            }
-            tool.delete();
-        }
-    }
-}
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/nodes/MaterializeObjectNode.java	Mon May 13 16:46:39 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,100 +0,0 @@
-/*
- * 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.virtual.nodes;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.nodes.virtual.*;
-
-@NodeInfo(nameTemplate = "Materialize {i#virtualObject}")
-public final class MaterializeObjectNode extends FixedWithNextNode implements VirtualizableAllocation, Lowerable, Node.IterableNodeType, Canonicalizable, ArrayLengthProvider {
-
-    @Input private final NodeInputList<ValueNode> values;
-    @Input private final VirtualObjectNode virtualObject;
-    private final int lockCount;
-
-    public MaterializeObjectNode(VirtualObjectNode virtualObject, int lockCount) {
-        super(StampFactory.exactNonNull(virtualObject.type()));
-        this.virtualObject = virtualObject;
-        this.lockCount = lockCount;
-        this.values = new NodeInputList<>(this, virtualObject.entryCount());
-    }
-
-    public NodeInputList<ValueNode> getValues() {
-        return values;
-    }
-
-    public VirtualObjectNode getVirtualObject() {
-        return virtualObject;
-    }
-
-    public int getLockCount() {
-        return lockCount;
-    }
-
-    @Override
-    public ValueNode length() {
-        assert virtualObject.type().isArray();
-        return ConstantNode.forInt(values.size(), graph());
-    }
-
-    /**
-     * @return true if the object that will be created is without locks and has only entries that
-     *         are {@link Constant#defaultForKind(Kind)}, false otherwise.
-     */
-    public boolean isDefault() {
-        if (lockCount > 0) {
-            return false;
-        } else {
-            for (ValueNode value : values) {
-                if (!value.isConstant() || !value.asConstant().isDefaultForKind()) {
-                    return false;
-                }
-            }
-        }
-        return true;
-    }
-
-    @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
-        virtualObject.materializeAt(this, values, isDefault(), lockCount);
-    }
-
-    @Override
-    public ValueNode canonical(CanonicalizerTool tool) {
-        if (usages().isEmpty()) {
-            return null;
-        } else {
-            return this;
-        }
-    }
-
-    @Override
-    public void virtualize(VirtualizerTool tool) {
-        tool.createVirtualObject(virtualObject, values.toArray(new ValueNode[values.size()]), lockCount);
-        tool.replaceWithVirtual(virtualObject);
-    }
-}
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/BlockState.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/BlockState.java	Mon May 13 17:11:31 2013 +0200
@@ -26,14 +26,12 @@
 
 import java.util.*;
 
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity;
 import com.oracle.graal.nodes.spi.Virtualizable.EscapeState;
 import com.oracle.graal.nodes.virtual.*;
-import com.oracle.graal.virtual.nodes.*;
 
 class BlockState {
 
@@ -44,10 +42,10 @@
 
     static class ReadCacheEntry {
 
-        public final Object identity;
+        public final LocationIdentity identity;
         public final ValueNode object;
 
-        public ReadCacheEntry(Object identity, ValueNode object) {
+        public ReadCacheEntry(LocationIdentity identity, ValueNode object) {
             this.identity = identity;
             this.object = object;
         }
@@ -85,7 +83,7 @@
         readCache = new HashMap<>(other.readCache);
     }
 
-    public void addReadCache(ValueNode object, Object identity, ValueNode value) {
+    public void addReadCache(ValueNode object, LocationIdentity identity, ValueNode value) {
         ValueNode cacheObject;
         ObjectState obj = getObjectState(object);
         if (obj != null) {
@@ -97,7 +95,7 @@
         readCache.put(new ReadCacheEntry(identity, cacheObject), value);
     }
 
-    public ValueNode getReadCache(ValueNode object, Object identity) {
+    public ValueNode getReadCache(ValueNode object, LocationIdentity identity) {
         ValueNode cacheObject;
         ObjectState obj = getObjectState(object);
         if (obj != null) {
@@ -117,7 +115,7 @@
         return cacheValue;
     }
 
-    public void killReadCache(Object identity) {
+    public void killReadCache(LocationIdentity identity) {
         if (identity == LocationNode.ANY_LOCATION) {
             readCache.clear();
         } else {
@@ -151,62 +149,51 @@
 
     public void materializeBefore(FixedNode fixed, VirtualObjectNode virtual, EscapeState state, GraphEffectList materializeEffects) {
         PartialEscapeClosure.METRIC_MATERIALIZATIONS.increment();
-        HashSet<VirtualObjectNode> deferred = new HashSet<>();
-        GraphEffectList deferredStores = new GraphEffectList();
-        materializeChangedBefore(fixed, virtual, state, deferred, deferredStores, materializeEffects);
-        materializeEffects.addAll(deferredStores);
+        List<AllocatedObjectNode> objects = new ArrayList<>(2);
+        List<ValueNode> values = new ArrayList<>(8);
+        List<int[]> locks = new ArrayList<>(2);
+        List<ValueNode> otherAllocations = new ArrayList<>(2);
+        materializeWithCommit(fixed, virtual, objects, locks, values, otherAllocations, state);
+
+        materializeEffects.addMaterializationBefore(fixed, objects, locks, values, otherAllocations);
     }
 
-    private void materializeChangedBefore(FixedNode fixed, VirtualObjectNode virtual, EscapeState state, HashSet<VirtualObjectNode> deferred, GraphEffectList deferredStores,
-                    GraphEffectList materializeEffects) {
-        trace("materializing %s at %s", virtual, fixed);
+    private void materializeWithCommit(FixedNode fixed, VirtualObjectNode virtual, List<AllocatedObjectNode> objects, List<int[]> locks, List<ValueNode> values, List<ValueNode> otherAllocations,
+                    EscapeState state) {
+        trace("materializing %s", virtual);
         ObjectState obj = getObjectState(virtual);
-        if (obj.getLockCount() > 0 && obj.virtual.type().isArray()) {
-            throw new BailoutException("array materialized with lock");
-        }
-
-        ValueNode[] fieldState = obj.getEntries();
 
-        MaterializeObjectNode materialize = new MaterializeObjectNode(virtual, obj.getLockCount());
-        ValueNode[] values = new ValueNode[obj.getEntries().length];
-        obj.escape(materialize, state);
-        deferred.add(virtual);
-        for (int i = 0; i < fieldState.length; i++) {
-            ObjectState valueObj = getObjectState(fieldState[i]);
-            if (valueObj != null) {
-                if (valueObj.isVirtual()) {
-                    materializeChangedBefore(fixed, valueObj.virtual, state, deferred, deferredStores, materializeEffects);
+        ValueNode[] entries = obj.getEntries();
+        ValueNode representation = virtual.getMaterializedRepresentation(fixed, entries, obj.getLocks());
+        obj.escape(representation, state);
+        if (representation instanceof AllocatedObjectNode) {
+            objects.add((AllocatedObjectNode) representation);
+            locks.add(obj.getLocks());
+            int pos = values.size();
+            while (values.size() < pos + entries.length) {
+                values.add(null);
+            }
+            for (int i = 0; i < entries.length; i++) {
+                ObjectState entryObj = getObjectState(entries[i]);
+                if (entryObj != null) {
+                    if (entryObj.isVirtual()) {
+                        materializeWithCommit(fixed, entryObj.getVirtualObject(), objects, locks, values, otherAllocations, state);
+                    }
+                    values.set(pos + i, entryObj.getMaterializedValue());
+                } else {
+                    values.set(pos + i, entries[i]);
                 }
-                if (deferred.contains(valueObj.virtual)) {
-                    Kind fieldKind;
-                    CyclicMaterializeStoreNode store;
-                    if (virtual instanceof VirtualArrayNode) {
-                        store = new CyclicMaterializeStoreNode(materialize, valueObj.getMaterializedValue(), i);
-                        fieldKind = ((VirtualArrayNode) virtual).componentType().getKind();
-                    } else {
-                        VirtualInstanceNode instanceObject = (VirtualInstanceNode) virtual;
-                        store = new CyclicMaterializeStoreNode(materialize, valueObj.getMaterializedValue(), instanceObject.field(i));
-                        fieldKind = instanceObject.field(i).getType().getKind();
-                    }
-                    deferredStores.addFixedNodeBefore(store, fixed);
-                    values[i] = ConstantNode.defaultForKind(fieldKind, fixed.graph());
-                } else {
-                    values[i] = valueObj.getMaterializedValue();
+            }
+            if (virtual instanceof VirtualInstanceNode) {
+                VirtualInstanceNode instance = (VirtualInstanceNode) virtual;
+                for (int i = 0; i < entries.length; i++) {
+                    readCache.put(new ReadCacheEntry((LocationIdentity) instance.field(i), representation), values.get(pos + i));
                 }
-            } else {
-                values[i] = fieldState[i];
             }
+        } else {
+            otherAllocations.add(representation);
+            assert obj.getLocks().length == 0;
         }
-        deferred.remove(virtual);
-
-        if (virtual instanceof VirtualInstanceNode) {
-            VirtualInstanceNode instance = (VirtualInstanceNode) virtual;
-            for (int i = 0; i < fieldState.length; i++) {
-                readCache.put(new ReadCacheEntry(instance.field(i), materialize), fieldState[i]);
-            }
-        }
-
-        materializeEffects.addMaterialization(materialize, fixed, values);
     }
 
     void addAndMarkAlias(VirtualObjectNode virtual, ValueNode node, NodeBitMap usages) {
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java	Mon May 13 17:11:31 2013 +0200
@@ -26,10 +26,10 @@
 
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.debug.*;
 import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.common.*;
-import com.oracle.graal.virtual.nodes.*;
 
 public class GraphEffectList extends EffectList {
 
@@ -118,33 +118,6 @@
     }
 
     /**
-     * Add the materialization node to the graph's control flow at the given position, and then sets
-     * its values.
-     * 
-     * @param node The materialization node that should be added.
-     * @param position The fixed node before which the materialization node should be added.
-     * @param values The values for the materialization node's entries.
-     */
-    public void addMaterialization(final MaterializeObjectNode node, final FixedNode position, final ValueNode[] values) {
-        add(new Effect() {
-
-            @Override
-            public String name() {
-                return "addMaterialization";
-            }
-
-            @Override
-            public void apply(StructuredGraph graph, ArrayList<Node> obsoleteNodes) {
-                assert !node.isAlive() && !node.isDeleted() && position.isAlive();
-                graph.addBeforeFixed(position, graph.add(node));
-                for (int i = 0; i < values.length; i++) {
-                    node.getValues().set(i, values[i]);
-                }
-            }
-        });
-    }
-
-    /**
      * Adds an value to the given phi node.
      * 
      * @param node The phi node to which the value should be added.
@@ -330,4 +303,68 @@
             }
         });
     }
+
+    /**
+     * Add the materialization node to the graph's control flow at the given position, and then sets
+     * its values.
+     * 
+     * @param position The fixed node before which the materialization node should be added.
+     * @param objects The allocated objects.
+     * @param locks The lock depths for each object.
+     * @param values The values (field, elements) of all objects.
+     * @param otherAllocations A list of allocations that need to be added before the rest (used for
+     *            boxing allocations).
+     */
+    public void addMaterializationBefore(final FixedNode position, final List<AllocatedObjectNode> objects, final List<int[]> locks, final List<ValueNode> values,
+                    final List<ValueNode> otherAllocations) {
+        add(new Effect() {
+
+            @Override
+            public String name() {
+                return "addMaterializationBefore";
+            }
+
+            @Override
+            public void apply(StructuredGraph graph, ArrayList<Node> obsoleteNodes) {
+                for (ValueNode otherAllocation : otherAllocations) {
+                    graph.add(otherAllocation);
+                    if (otherAllocation instanceof FixedWithNextNode) {
+                        graph.addBeforeFixed(position, (FixedWithNextNode) otherAllocation);
+                    } else {
+                        assert otherAllocation instanceof FloatingNode;
+                    }
+                }
+                if (!objects.isEmpty()) {
+                    CommitAllocationNode commit;
+                    if (position.predecessor() instanceof CommitAllocationNode) {
+                        commit = (CommitAllocationNode) position.predecessor();
+                    } else {
+                        commit = graph.add(new CommitAllocationNode());
+                        graph.addBeforeFixed(position, commit);
+                    }
+                    for (AllocatedObjectNode obj : objects) {
+                        graph.add(obj);
+                        commit.getVirtualObjects().add(obj.getVirtualObject());
+                        obj.setCommit(commit);
+                    }
+                    commit.getValues().addAll(values);
+                    commit.getLocks().addAll(locks);
+
+                    assert commit.usages().filter(AllocatedObjectNode.class).count() == commit.usages().count();
+                    HashSet<AllocatedObjectNode> materializedValues = new HashSet<>(commit.usages().filter(AllocatedObjectNode.class).snapshot());
+                    for (int i = 0; i < commit.getValues().size(); i++) {
+                        if (materializedValues.contains(commit.getValues().get(i))) {
+                            commit.getValues().set(i, ((AllocatedObjectNode) commit.getValues().get(i)).getVirtualObject());
+                        }
+                    }
+
+                }
+            }
+
+            @Override
+            public boolean isVisible() {
+                return true;
+            }
+        });
+    }
 }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ObjectState.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ObjectState.java	Mon May 13 17:11:31 2013 +0200
@@ -36,32 +36,69 @@
  */
 class ObjectState extends Virtualizable.State {
 
-    public final VirtualObjectNode virtual;
+    private static final int[] EMPTY_INT_ARRAY = new int[0];
+
+    public static final class LockState {
+
+        public final int depth;
+        public final LockState next;
+
+        private LockState(int depth, LockState next) {
+            this.depth = depth;
+            this.next = next;
+        }
+
+        @Override
+        public String toString() {
+            return next == null ? String.valueOf(depth) : depth + "," + next;
+        }
+
+        public static boolean equals(LockState a, LockState b) {
+            if ((a == null) != (b == null)) {
+                return false;
+            }
+            if (a != null) {
+                if (a.depth != b.depth) {
+                    return false;
+                }
+                return equals(a.next, b.next);
+            }
+            return true;
+        }
+    }
+
+    final VirtualObjectNode virtual;
 
     private EscapeState state;
     private ValueNode[] entries;
     private ValueNode materializedValue;
-    private int lockCount;
+    private LockState locks;
 
-    public ObjectState(VirtualObjectNode virtual, ValueNode[] entries, EscapeState state, int lockCount) {
+    public ObjectState(VirtualObjectNode virtual, ValueNode[] entries, EscapeState state, int[] locks) {
         this.virtual = virtual;
         this.entries = entries;
         this.state = state;
-        this.lockCount = lockCount;
+        if (locks == null) {
+            this.locks = null;
+        } else {
+            for (int i = locks.length - 1; i >= 0; i--) {
+                this.locks = new LockState(locks[i], this.locks);
+            }
+        }
     }
 
-    public ObjectState(VirtualObjectNode virtual, ValueNode materializedValue, EscapeState state, int lockCount) {
+    public ObjectState(VirtualObjectNode virtual, ValueNode materializedValue, EscapeState state, LockState locks) {
         this.virtual = virtual;
         this.materializedValue = materializedValue;
         this.state = state;
-        this.lockCount = lockCount;
+        this.locks = locks;
     }
 
     private ObjectState(ObjectState other) {
         virtual = other.virtual;
         entries = other.entries == null ? null : other.entries.clone();
         materializedValue = other.materializedValue;
-        lockCount = other.lockCount;
+        locks = other.locks;
         state = other.state;
     }
 
@@ -120,24 +157,56 @@
     }
 
     @Override
-    public int getLockCount() {
-        return lockCount;
+    public void addLock(int depth) {
+        locks = new LockState(depth, locks);
     }
 
     @Override
-    public void setLockCount(int lockCount) {
-        this.lockCount = lockCount;
+    public int removeLock() {
+        try {
+            return locks.depth;
+        } finally {
+            locks = locks.next;
+        }
+    }
+
+    public int[] getLocks() {
+        if (locks == null) {
+            return EMPTY_INT_ARRAY;
+        }
+        int cnt = 0;
+        LockState current = locks;
+        while (current != null) {
+            cnt++;
+            current = current.next;
+        }
+        int[] result = new int[cnt];
+        current = locks;
+        cnt = 0;
+        while (current != null) {
+            result[cnt++] = current.depth;
+            current = current.next;
+        }
+        return result;
+    }
+
+    public boolean hasLocks() {
+        return locks != null;
+    }
+
+    public boolean locksEqual(ObjectState other) {
+        return LockState.equals(locks, other.locks);
     }
 
     @Override
     public String toString() {
         StringBuilder str = new StringBuilder().append('{');
-        if (lockCount > 0) {
-            str.append('l').append(lockCount).append(' ');
+        if (locks != null) {
+            str.append('l').append(locks).append(' ');
         }
         if (entries != null) {
             for (int i = 0; i < entries.length; i++) {
-                str.append(virtual.fieldName(i)).append('=').append(entries[i]).append(' ');
+                str.append(virtual.entryName(i)).append('=').append(entries[i]).append(' ');
             }
         }
         if (materializedValue != null) {
@@ -152,7 +221,7 @@
         final int prime = 31;
         int result = 1;
         result = prime * result + Arrays.hashCode(entries);
-        result = prime * result + lockCount;
+        result = prime * result + (locks != null ? locks.depth : 0);
         result = prime * result + ((materializedValue == null) ? 0 : materializedValue.hashCode());
         result = prime * result + ((state == null) ? 0 : state.hashCode());
         result = prime * result + ((virtual == null) ? 0 : virtual.hashCode());
@@ -171,7 +240,7 @@
         if (!Arrays.equals(entries, other.entries)) {
             return false;
         }
-        if (lockCount != other.lockCount) {
+        if (!LockState.equals(locks, other.locks)) {
             return false;
         }
         if (materializedValue == null) {
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java	Mon May 13 17:11:31 2013 +0200
@@ -32,13 +32,13 @@
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.util.*;
+import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.common.CanonicalizerPhase.CustomCanonicalizer;
 import com.oracle.graal.phases.graph.*;
 import com.oracle.graal.phases.schedule.*;
 import com.oracle.graal.phases.tiers.*;
-import com.oracle.graal.virtual.nodes.*;
 
 public class PartialEscapeAnalysisPhase extends BasePhase<HighTierContext> {
 
@@ -126,8 +126,13 @@
 
     private static boolean matches(StructuredGraph graph, String filter) {
         if (filter != null) {
-            ResolvedJavaMethod method = graph.method();
-            return method != null && MetaUtil.format("%H.%n", method).contains(filter);
+            if (filter.startsWith("~")) {
+                ResolvedJavaMethod method = graph.method();
+                return method == null || !MetaUtil.format("%H.%n", method).contains(filter.substring(1));
+            } else {
+                ResolvedJavaMethod method = graph.method();
+                return method != null && MetaUtil.format("%H.%n", method).contains(filter);
+            }
         }
         return true;
     }
@@ -139,8 +144,8 @@
         IdentityHashMap<Node, Node> path = new IdentityHashMap<>();
         flood.add(graph.start());
         for (Node current : flood) {
-            if (current instanceof EndNode) {
-                EndNode end = (EndNode) current;
+            if (current instanceof AbstractEndNode) {
+                AbstractEndNode end = (AbstractEndNode) current;
                 flood.add(end.merge());
                 if (!path.containsKey(end.merge())) {
                     path.put(end.merge(), end);
@@ -203,32 +208,36 @@
     public static Map<Invoke, Double> getHints(StructuredGraph graph) {
         NodesToDoubles probabilities = new ComputeProbabilityClosure(graph).apply();
         Map<Invoke, Double> hints = null;
-        for (MaterializeObjectNode materialize : graph.getNodes(MaterializeObjectNode.class)) {
+        for (CommitAllocationNode commit : graph.getNodes(CommitAllocationNode.class)) {
             double sum = 0;
             double invokeSum = 0;
-            for (Node usage : materialize.usages()) {
-                if (usage instanceof FixedNode) {
-                    sum += probabilities.get((FixedNode) usage);
-                } else {
-                    if (usage instanceof MethodCallTargetNode) {
-                        invokeSum += probabilities.get(((MethodCallTargetNode) usage).invoke().asNode());
-                    }
-                    for (Node secondLevelUage : materialize.usages()) {
-                        if (secondLevelUage instanceof FixedNode) {
-                            sum += probabilities.get(((FixedNode) secondLevelUage));
+            for (Node commitUsage : commit.usages()) {
+                for (Node usage : commitUsage.usages()) {
+                    if (usage instanceof FixedNode) {
+                        sum += probabilities.get((FixedNode) usage);
+                    } else {
+                        if (usage instanceof MethodCallTargetNode) {
+                            invokeSum += probabilities.get(((MethodCallTargetNode) usage).invoke().asNode());
+                        }
+                        for (Node secondLevelUage : usage.usages()) {
+                            if (secondLevelUage instanceof FixedNode) {
+                                sum += probabilities.get(((FixedNode) secondLevelUage));
+                            }
                         }
                     }
                 }
             }
             // TODO(lstadler) get rid of this magic number
             if (sum > 100 && invokeSum > 0) {
-                for (Node usage : materialize.usages()) {
-                    if (usage instanceof MethodCallTargetNode) {
-                        if (hints == null) {
-                            hints = new HashMap<>();
+                for (Node commitUsage : commit.usages()) {
+                    for (Node usage : commitUsage.usages()) {
+                        if (usage instanceof MethodCallTargetNode) {
+                            if (hints == null) {
+                                hints = new HashMap<>();
+                            }
+                            Invoke invoke = ((MethodCallTargetNode) usage).invoke();
+                            hints.put(invoke, sum / invokeSum);
                         }
-                        Invoke invoke = ((MethodCallTargetNode) usage).invoke();
-                        hints.put(invoke, sum / invokeSum);
                     }
                 }
             }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Mon May 13 17:11:31 2013 +0200
@@ -34,6 +34,7 @@
 import com.oracle.graal.nodes.PhiNode.PhiType;
 import com.oracle.graal.nodes.VirtualState.NodeClosure;
 import com.oracle.graal.nodes.cfg.*;
+import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
@@ -91,7 +92,7 @@
 
     public List<Node> applyEffects(final StructuredGraph graph) {
         final ArrayList<Node> obsoleteNodes = new ArrayList<>();
-        BlockIteratorClosure<Object> closure = new BlockIteratorClosure<Object>() {
+        BlockIteratorClosure<Void> closure = new BlockIteratorClosure<Void>() {
 
             private void apply(GraphEffectList effects, Object context) {
                 if (!effects.isEmpty()) {
@@ -106,28 +107,29 @@
             }
 
             @Override
-            protected void processBlock(Block block, Object currentState) {
+            protected Void processBlock(Block block, Void currentState) {
                 apply(blockEffects.get(block), block);
+                return currentState;
             }
 
             @Override
-            protected Object merge(Block merge, List<Object> states) {
-                return new Object();
+            protected Void merge(Block merge, List<Void> states) {
+                return null;
             }
 
             @Override
-            protected Object cloneState(Object oldState) {
+            protected Void cloneState(Void oldState) {
                 return oldState;
             }
 
             @Override
-            protected List<Object> processLoop(Loop loop, Object initialState) {
-                LoopInfo<Object> info = ReentrantBlockIterator.processLoop(this, loop, initialState);
+            protected List<Void> processLoop(Loop loop, Void initialState) {
+                LoopInfo<Void> info = ReentrantBlockIterator.processLoop(this, loop, initialState);
                 apply(loopMergeEffects.get(loop), loop);
                 return info.exitStates;
             }
         };
-        ReentrantBlockIterator.apply(closure, schedule.getCFG().getStartBlock(), new Object(), null);
+        ReentrantBlockIterator.apply(closure, schedule.getCFG().getStartBlock(), null, null);
         return obsoleteNodes;
     }
 
@@ -136,7 +138,7 @@
     }
 
     @Override
-    protected void processBlock(Block block, BlockState state) {
+    protected BlockState processBlock(Block block, BlockState state) {
         GraphEffectList effects = blockEffects.get(block);
         tool.setEffects(effects);
 
@@ -158,18 +160,18 @@
                     if (node instanceof StoreFieldNode) {
                         METRIC_STOREFIELD_RECORDED.increment();
                         StoreFieldNode store = (StoreFieldNode) node;
-                        ValueNode cachedValue = state.getReadCache(store.object(), store.field());
-                        state.killReadCache(store.field());
+                        ValueNode cachedValue = state.getReadCache(store.object(), (LocationIdentity) store.field());
+                        state.killReadCache((LocationIdentity) store.field());
 
                         if (cachedValue == store.value()) {
                             effects.deleteFixedNode(store);
                             changed = true;
                         } else {
-                            state.addReadCache(store.object(), store.field(), store.value());
+                            state.addReadCache(store.object(), (LocationIdentity) store.field(), store.value());
                         }
                     } else if (node instanceof LoadFieldNode) {
                         LoadFieldNode load = (LoadFieldNode) node;
-                        ValueNode cachedValue = state.getReadCache(load.object(), load.field());
+                        ValueNode cachedValue = state.getReadCache(load.object(), (LocationIdentity) load.field());
                         if (cachedValue != null) {
                             METRIC_LOADFIELD_ELIMINATED.increment();
                             effects.replaceAtUsages(load, cachedValue);
@@ -177,12 +179,12 @@
                             changed = true;
                         } else {
                             METRIC_LOADFIELD_NOT_ELIMINATED.increment();
-                            state.addReadCache(load.object(), load.field(), load);
+                            state.addReadCache(load.object(), (LocationIdentity) load.field(), load);
                         }
                     } else if (node instanceof MemoryCheckpoint) {
                         METRIC_MEMORYCHECKOINT.increment();
                         MemoryCheckpoint checkpoint = (MemoryCheckpoint) node;
-                        for (Object identity : checkpoint.getLocationIdentities()) {
+                        for (LocationIdentity identity : checkpoint.getLocationIdentities()) {
                             state.killReadCache(identity);
                         }
                     }
@@ -193,15 +195,16 @@
             }
         }
         trace(")\n    end state: %s\n", state);
+        return state;
     }
 
     private boolean processNode(final ValueNode node, FixedNode insertBefore, final BlockState state, final GraphEffectList effects) {
-        tool.reset(state, node);
+        tool.reset(state, node, insertBefore);
         if (node instanceof Virtualizable) {
             ((Virtualizable) node).virtualize(tool);
         }
         if (tool.isDeleted()) {
-            if (tool.isCustomAction() || !(node instanceof VirtualizableAllocation || node instanceof CyclicMaterializeStoreNode)) {
+            if (!(node instanceof VirtualizableAllocation)) {
                 changed = true;
             }
             return true;
@@ -238,7 +241,7 @@
                     }
                 });
                 for (ObjectState obj : state.getStates()) {
-                    if (obj.isVirtual() && obj.getLockCount() > 0) {
+                    if (obj.isVirtual() && obj.hasLocks()) {
                         virtual.add(obj);
                     }
                 }
@@ -280,9 +283,6 @@
                 }
             }
         }
-        if (tool.isCustomAction()) {
-            return false;
-        }
         for (ValueNode input : node.inputs().filter(ValueNode.class)) {
             ObjectState obj = state.getObjectState(input);
             if (obj != null) {
@@ -502,7 +502,6 @@
                     }
                     int virtual = 0;
                     ObjectState startObj = objStates[0];
-                    int lockCount = startObj.getLockCount();
                     boolean locksMatch = true;
                     ValueNode singleValue = startObj.isVirtual() ? null : startObj.getMaterializedValue();
                     for (ObjectState obj : objStates) {
@@ -514,7 +513,7 @@
                                 singleValue = null;
                             }
                         }
-                        locksMatch &= obj.getLockCount() == lockCount;
+                        locksMatch &= obj.locksEqual(startObj);
                     }
 
                     assert virtual < states.size() || locksMatch : "mismatching lock counts at " + merge;
@@ -531,9 +530,9 @@
                                 ensureMaterialized(state, obj, predecessor.getEndNode(), blockEffects.get(predecessor), METRIC_MATERIALIZATIONS_MERGE);
                                 afterMergeEffects.addPhiInput(materializedValuePhi, obj.getMaterializedValue());
                             }
-                            newState.addObject(object, new ObjectState(object, materializedValuePhi, EscapeState.Global, lockCount));
+                            newState.addObject(object, new ObjectState(object, materializedValuePhi, EscapeState.Global, null));
                         } else {
-                            newState.addObject(object, new ObjectState(object, singleValue, EscapeState.Global, lockCount));
+                            newState.addObject(object, new ObjectState(object, singleValue, EscapeState.Global, null));
                         }
                     } else {
                         assert virtual == states.size();
@@ -567,7 +566,7 @@
                                 values[index] = phis[index];
                             }
                         }
-                        newState.addObject(object, new ObjectState(object, values, EscapeState.Virtual, lockCount));
+                        newState.addObject(object, new ObjectState(object, values, EscapeState.Virtual, startObj.getLocks()));
                     }
                 }
 
@@ -638,7 +637,7 @@
                             }
                         }
                         mergeEffects.addFloatingNode(virtual, "valueObjectNode");
-                        newState.addObject(virtual, new ObjectState(virtual, Arrays.copyOf(phis, phis.length, ValueNode[].class), EscapeState.Virtual, 0));
+                        newState.addObject(virtual, new ObjectState(virtual, Arrays.copyOf(phis, phis.length, ValueNode[].class), EscapeState.Virtual, null));
                         newState.addAndMarkAlias(virtual, virtual, usages);
                         newState.addAndMarkAlias(virtual, phi, usages);
                     } else {
@@ -704,7 +703,7 @@
             }
         }
 
-        private void mergeReadCachePhi(PhiNode phi, Object identity, List<BlockState> states) {
+        private void mergeReadCachePhi(PhiNode phi, LocationIdentity identity, List<BlockState> states) {
             ValueNode[] values = new ValueNode[phi.valueCount()];
             for (int i = 0; i < phi.valueCount(); i++) {
                 ValueNode value = states.get(i).getReadCache(phi.valueAt(i), identity);
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java	Mon May 13 17:11:31 2013 +0200
@@ -28,6 +28,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.Virtualizable.EscapeState;
 import com.oracle.graal.nodes.spi.Virtualizable.State;
 import com.oracle.graal.nodes.spi.*;
@@ -48,9 +49,9 @@
     }
 
     private boolean deleted;
-    private boolean customAction;
     private BlockState state;
     private ValueNode current;
+    private FixedNode position;
 
     @Override
     public MetaAccessProvider getMetaAccessProvider() {
@@ -66,21 +67,17 @@
         this.effects = effects;
     }
 
-    public void reset(BlockState newState, ValueNode newCurrent) {
+    public void reset(BlockState newState, ValueNode newCurrent, FixedNode newPosition) {
         deleted = false;
-        customAction = false;
-        this.state = newState;
-        this.current = newCurrent;
+        state = newState;
+        current = newCurrent;
+        position = newPosition;
     }
 
     public boolean isDeleted() {
         return deleted;
     }
 
-    public boolean isCustomAction() {
-        return customAction;
-    }
-
     @Override
     public State getObjectState(ValueNode value) {
         return state.getObjectState(value);
@@ -142,13 +139,16 @@
     }
 
     @Override
-    public void customAction(Runnable action) {
-        effects.customAction(action);
-        customAction = true;
+    public void addNode(ValueNode node) {
+        if (node instanceof FloatingNode) {
+            effects.addFloatingNode(node, "VirtualizerTool");
+        } else {
+            effects.addFixedNodeBefore((FixedWithNextNode) node, position);
+        }
     }
 
     @Override
-    public void createVirtualObject(VirtualObjectNode virtualObject, ValueNode[] entryState, int lockCount) {
+    public void createVirtualObject(VirtualObjectNode virtualObject, ValueNode[] entryState, int[] locks) {
         trace("{{%s}} ", current);
         if (virtualObject.isAlive()) {
             state.addAndMarkAlias(virtualObject, virtualObject, usages);
@@ -158,7 +158,7 @@
         for (int i = 0; i < entryState.length; i++) {
             entryState[i] = state.getScalarAlias(entryState[i]);
         }
-        state.addObject(virtualObject, new ObjectState(virtualObject, entryState, EscapeState.Virtual, lockCount));
+        state.addObject(virtualObject, new ObjectState(virtualObject, entryState, EscapeState.Virtual, locks));
         state.addAndMarkAlias(virtualObject, virtualObject, usages);
         PartialEscapeClosure.METRIC_ALLOCATION_REMOVED.increment();
     }
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/Pointer.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/Pointer.java	Mon May 13 17:11:31 2013 +0200
@@ -23,6 +23,7 @@
 package com.oracle.graal.word;
 
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity;
 
 public interface Pointer extends Unsigned {
 
@@ -47,7 +48,7 @@
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
      */
-    byte readByte(WordBase offset, Object locationIdentity);
+    byte readByte(WordBase offset, LocationIdentity locationIdentity);
 
     /**
      * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
@@ -61,7 +62,7 @@
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
      */
-    char readChar(WordBase offset, Object locationIdentity);
+    char readChar(WordBase offset, LocationIdentity locationIdentity);
 
     /**
      * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
@@ -75,7 +76,7 @@
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
      */
-    short readShort(WordBase offset, Object locationIdentity);
+    short readShort(WordBase offset, LocationIdentity locationIdentity);
 
     /**
      * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
@@ -89,7 +90,7 @@
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
      */
-    int readInt(WordBase offset, Object locationIdentity);
+    int readInt(WordBase offset, LocationIdentity locationIdentity);
 
     /**
      * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
@@ -103,7 +104,7 @@
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
      */
-    long readLong(WordBase offset, Object locationIdentity);
+    long readLong(WordBase offset, LocationIdentity locationIdentity);
 
     /**
      * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
@@ -117,7 +118,7 @@
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
      */
-    float readFloat(WordBase offset, Object locationIdentity);
+    float readFloat(WordBase offset, LocationIdentity locationIdentity);
 
     /**
      * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
@@ -131,7 +132,7 @@
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
      */
-    double readDouble(WordBase offset, Object locationIdentity);
+    double readDouble(WordBase offset, LocationIdentity locationIdentity);
 
     /**
      * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
@@ -145,7 +146,7 @@
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
      */
-    Word readWord(WordBase offset, Object locationIdentity);
+    Word readWord(WordBase offset, LocationIdentity locationIdentity);
 
     /**
      * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
@@ -159,7 +160,7 @@
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
      */
-    Object readObject(WordBase offset, Object locationIdentity);
+    Object readObject(WordBase offset, LocationIdentity locationIdentity);
 
     /**
      * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
@@ -169,7 +170,7 @@
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
      */
-    byte readByte(int offset, Object locationIdentity);
+    byte readByte(int offset, LocationIdentity locationIdentity);
 
     /**
      * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
@@ -179,7 +180,7 @@
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
      */
-    char readChar(int offset, Object locationIdentity);
+    char readChar(int offset, LocationIdentity locationIdentity);
 
     /**
      * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
@@ -189,7 +190,7 @@
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
      */
-    short readShort(int offset, Object locationIdentity);
+    short readShort(int offset, LocationIdentity locationIdentity);
 
     /**
      * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
@@ -199,7 +200,7 @@
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
      */
-    int readInt(int offset, Object locationIdentity);
+    int readInt(int offset, LocationIdentity locationIdentity);
 
     /**
      * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
@@ -209,7 +210,7 @@
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
      */
-    long readLong(int offset, Object locationIdentity);
+    long readLong(int offset, LocationIdentity locationIdentity);
 
     /**
      * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
@@ -219,7 +220,7 @@
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
      */
-    float readFloat(int offset, Object locationIdentity);
+    float readFloat(int offset, LocationIdentity locationIdentity);
 
     /**
      * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
@@ -229,7 +230,7 @@
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
      */
-    double readDouble(int offset, Object locationIdentity);
+    double readDouble(int offset, LocationIdentity locationIdentity);
 
     /**
      * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
@@ -239,7 +240,7 @@
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
      */
-    Word readWord(int offset, Object locationIdentity);
+    Word readWord(int offset, LocationIdentity locationIdentity);
 
     /**
      * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
@@ -249,7 +250,7 @@
      * @param locationIdentity the identity of the read (see {@link LocationNode})
      * @return the result of the memory access
      */
-    Object readObject(int offset, Object locationIdentity);
+    Object readObject(int offset, LocationIdentity locationIdentity);
 
     /**
      * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
@@ -263,7 +264,7 @@
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
      */
-    void writeByte(WordBase offset, byte val, Object locationIdentity);
+    void writeByte(WordBase offset, byte val, LocationIdentity locationIdentity);
 
     /**
      * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
@@ -277,7 +278,7 @@
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
      */
-    void writeChar(WordBase offset, char val, Object locationIdentity);
+    void writeChar(WordBase offset, char val, LocationIdentity locationIdentity);
 
     /**
      * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
@@ -291,7 +292,7 @@
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
      */
-    void writeShort(WordBase offset, short val, Object locationIdentity);
+    void writeShort(WordBase offset, short val, LocationIdentity locationIdentity);
 
     /**
      * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
@@ -305,7 +306,7 @@
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
      */
-    void writeInt(WordBase offset, int val, Object locationIdentity);
+    void writeInt(WordBase offset, int val, LocationIdentity locationIdentity);
 
     /**
      * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
@@ -319,7 +320,7 @@
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
      */
-    void writeLong(WordBase offset, long val, Object locationIdentity);
+    void writeLong(WordBase offset, long val, LocationIdentity locationIdentity);
 
     /**
      * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
@@ -333,7 +334,7 @@
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
      */
-    void writeFloat(WordBase offset, float val, Object locationIdentity);
+    void writeFloat(WordBase offset, float val, LocationIdentity locationIdentity);
 
     /**
      * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
@@ -347,7 +348,7 @@
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
      */
-    void writeDouble(WordBase offset, double val, Object locationIdentity);
+    void writeDouble(WordBase offset, double val, LocationIdentity locationIdentity);
 
     /**
      * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
@@ -361,7 +362,7 @@
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
      */
-    void writeWord(WordBase offset, WordBase val, Object locationIdentity);
+    void writeWord(WordBase offset, WordBase val, LocationIdentity locationIdentity);
 
     /**
      * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
@@ -375,7 +376,7 @@
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
      */
-    void writeObject(WordBase offset, Object val, Object locationIdentity);
+    void writeObject(WordBase offset, Object val, LocationIdentity locationIdentity);
 
     /**
      * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
@@ -385,7 +386,7 @@
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
      */
-    void writeByte(int offset, byte val, Object locationIdentity);
+    void writeByte(int offset, byte val, LocationIdentity locationIdentity);
 
     /**
      * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
@@ -395,7 +396,7 @@
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
      */
-    void writeChar(int offset, char val, Object locationIdentity);
+    void writeChar(int offset, char val, LocationIdentity locationIdentity);
 
     /**
      * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
@@ -405,7 +406,7 @@
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
      */
-    void writeShort(int offset, short val, Object locationIdentity);
+    void writeShort(int offset, short val, LocationIdentity locationIdentity);
 
     /**
      * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
@@ -415,7 +416,7 @@
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
      */
-    void writeInt(int offset, int val, Object locationIdentity);
+    void writeInt(int offset, int val, LocationIdentity locationIdentity);
 
     /**
      * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
@@ -425,7 +426,7 @@
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
      */
-    void writeLong(int offset, long val, Object locationIdentity);
+    void writeLong(int offset, long val, LocationIdentity locationIdentity);
 
     /**
      * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
@@ -435,7 +436,7 @@
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
      */
-    void writeFloat(int offset, float val, Object locationIdentity);
+    void writeFloat(int offset, float val, LocationIdentity locationIdentity);
 
     /**
      * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
@@ -445,7 +446,7 @@
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
      */
-    void writeDouble(int offset, double val, Object locationIdentity);
+    void writeDouble(int offset, double val, LocationIdentity locationIdentity);
 
     /**
      * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
@@ -455,7 +456,7 @@
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
      */
-    void writeWord(int offset, WordBase val, Object locationIdentity);
+    void writeWord(int offset, WordBase val, LocationIdentity locationIdentity);
 
     /**
      * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
@@ -465,7 +466,7 @@
      * @param locationIdentity the identity of the write (see {@link LocationNode})
      * @param val the value to be written to memory
      */
-    void writeObject(int offset, Object val, Object locationIdentity);
+    void writeObject(int offset, Object val, LocationIdentity locationIdentity);
 
     /**
      * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/Word.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/Word.java	Mon May 13 17:11:31 2013 +0200
@@ -30,6 +30,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity;
 
 public abstract class Word implements Signed, Unsigned, Pointer {
 
@@ -601,215 +602,215 @@
 
     @Override
     @Operation(opcode = Opcode.READ)
-    public byte readByte(WordBase offset, Object locationIdentity) {
+    public byte readByte(WordBase offset, LocationIdentity locationIdentity) {
         return unsafe.getByte(add((Word) offset).unbox());
     }
 
     @Override
     @Operation(opcode = Opcode.READ)
-    public char readChar(WordBase offset, Object locationIdentity) {
+    public char readChar(WordBase offset, LocationIdentity locationIdentity) {
         return unsafe.getChar(add((Word) offset).unbox());
     }
 
     @Override
     @Operation(opcode = Opcode.READ)
-    public short readShort(WordBase offset, Object locationIdentity) {
+    public short readShort(WordBase offset, LocationIdentity locationIdentity) {
         return unsafe.getShort(add((Word) offset).unbox());
     }
 
     @Override
     @Operation(opcode = Opcode.READ)
-    public int readInt(WordBase offset, Object locationIdentity) {
+    public int readInt(WordBase offset, LocationIdentity locationIdentity) {
         return unsafe.getInt(add((Word) offset).unbox());
     }
 
     @Override
     @Operation(opcode = Opcode.READ)
-    public long readLong(WordBase offset, Object locationIdentity) {
+    public long readLong(WordBase offset, LocationIdentity locationIdentity) {
         return unsafe.getLong(add((Word) offset).unbox());
     }
 
     @Override
     @Operation(opcode = Opcode.READ)
-    public float readFloat(WordBase offset, Object locationIdentity) {
+    public float readFloat(WordBase offset, LocationIdentity locationIdentity) {
         return unsafe.getFloat(add((Word) offset).unbox());
     }
 
     @Override
     @Operation(opcode = Opcode.READ)
-    public double readDouble(WordBase offset, Object locationIdentity) {
+    public double readDouble(WordBase offset, LocationIdentity locationIdentity) {
         return unsafe.getDouble(add((Word) offset).unbox());
     }
 
     @Override
     @Operation(opcode = Opcode.READ)
-    public Word readWord(WordBase offset, Object locationIdentity) {
+    public Word readWord(WordBase offset, LocationIdentity locationIdentity) {
         return box(unsafe.getAddress(add((Word) offset).unbox()));
     }
 
     @Override
     @Operation(opcode = Opcode.READ)
-    public Object readObject(WordBase offset, Object locationIdentity) {
+    public Object readObject(WordBase offset, LocationIdentity locationIdentity) {
         return unsafe.getObject(null, add((Word) offset).unbox());
     }
 
     @Override
     @Operation(opcode = Opcode.READ)
-    public byte readByte(int offset, Object locationIdentity) {
+    public byte readByte(int offset, LocationIdentity locationIdentity) {
         return readByte(signed(offset), locationIdentity);
     }
 
     @Override
     @Operation(opcode = Opcode.READ)
-    public char readChar(int offset, Object locationIdentity) {
+    public char readChar(int offset, LocationIdentity locationIdentity) {
         return readChar(signed(offset), locationIdentity);
     }
 
     @Override
     @Operation(opcode = Opcode.READ)
-    public short readShort(int offset, Object locationIdentity) {
+    public short readShort(int offset, LocationIdentity locationIdentity) {
         return readShort(signed(offset), locationIdentity);
     }
 
     @Override
     @Operation(opcode = Opcode.READ)
-    public int readInt(int offset, Object locationIdentity) {
+    public int readInt(int offset, LocationIdentity locationIdentity) {
         return readInt(signed(offset), locationIdentity);
     }
 
     @Override
     @Operation(opcode = Opcode.READ)
-    public long readLong(int offset, Object locationIdentity) {
+    public long readLong(int offset, LocationIdentity locationIdentity) {
         return readLong(signed(offset), locationIdentity);
     }
 
     @Override
     @Operation(opcode = Opcode.READ)
-    public float readFloat(int offset, Object locationIdentity) {
+    public float readFloat(int offset, LocationIdentity locationIdentity) {
         return readFloat(signed(offset), locationIdentity);
     }
 
     @Override
     @Operation(opcode = Opcode.READ)
-    public double readDouble(int offset, Object locationIdentity) {
+    public double readDouble(int offset, LocationIdentity locationIdentity) {
         return readDouble(signed(offset), locationIdentity);
     }
 
     @Override
     @Operation(opcode = Opcode.READ)
-    public Word readWord(int offset, Object locationIdentity) {
+    public Word readWord(int offset, LocationIdentity locationIdentity) {
         return readWord(signed(offset), locationIdentity);
     }
 
     @Override
     @Operation(opcode = Opcode.READ)
-    public Object readObject(int offset, Object locationIdentity) {
+    public Object readObject(int offset, LocationIdentity locationIdentity) {
         return readObject(signed(offset), locationIdentity);
     }
 
     @Override
     @Operation(opcode = Opcode.WRITE)
-    public void writeByte(WordBase offset, byte val, Object locationIdentity) {
+    public void writeByte(WordBase offset, byte val, LocationIdentity locationIdentity) {
         unsafe.putByte(add((Word) offset).unbox(), val);
     }
 
     @Override
     @Operation(opcode = Opcode.WRITE)
-    public void writeChar(WordBase offset, char val, Object locationIdentity) {
+    public void writeChar(WordBase offset, char val, LocationIdentity locationIdentity) {
         unsafe.putChar(add((Word) offset).unbox(), val);
     }
 
     @Override
     @Operation(opcode = Opcode.WRITE)
-    public void writeShort(WordBase offset, short val, Object locationIdentity) {
+    public void writeShort(WordBase offset, short val, LocationIdentity locationIdentity) {
         unsafe.putShort(add((Word) offset).unbox(), val);
     }
 
     @Override
     @Operation(opcode = Opcode.WRITE)
-    public void writeInt(WordBase offset, int val, Object locationIdentity) {
+    public void writeInt(WordBase offset, int val, LocationIdentity locationIdentity) {
         unsafe.putInt(add((Word) offset).unbox(), val);
     }
 
     @Override
     @Operation(opcode = Opcode.WRITE)
-    public void writeLong(WordBase offset, long val, Object locationIdentity) {
+    public void writeLong(WordBase offset, long val, LocationIdentity locationIdentity) {
         unsafe.putLong(add((Word) offset).unbox(), val);
     }
 
     @Override
     @Operation(opcode = Opcode.WRITE)
-    public void writeFloat(WordBase offset, float val, Object locationIdentity) {
+    public void writeFloat(WordBase offset, float val, LocationIdentity locationIdentity) {
         unsafe.putFloat(add((Word) offset).unbox(), val);
     }
 
     @Override
     @Operation(opcode = Opcode.WRITE)
-    public void writeDouble(WordBase offset, double val, Object locationIdentity) {
+    public void writeDouble(WordBase offset, double val, LocationIdentity locationIdentity) {
         unsafe.putDouble(add((Word) offset).unbox(), val);
     }
 
     @Override
     @Operation(opcode = Opcode.WRITE)
-    public void writeWord(WordBase offset, WordBase val, Object locationIdentity) {
+    public void writeWord(WordBase offset, WordBase val, LocationIdentity locationIdentity) {
         unsafe.putAddress(add((Word) offset).unbox(), ((Word) val).unbox());
     }
 
     @Override
     @Operation(opcode = Opcode.WRITE)
-    public native void writeObject(WordBase offset, Object val, Object locationIdentity);
+    public native void writeObject(WordBase offset, Object val, LocationIdentity locationIdentity);
 
     @Override
     @Operation(opcode = Opcode.WRITE)
-    public void writeByte(int offset, byte val, Object locationIdentity) {
+    public void writeByte(int offset, byte val, LocationIdentity locationIdentity) {
         writeByte(signed(offset), val, locationIdentity);
     }
 
     @Override
     @Operation(opcode = Opcode.WRITE)
-    public void writeChar(int offset, char val, Object locationIdentity) {
+    public void writeChar(int offset, char val, LocationIdentity locationIdentity) {
         writeChar(signed(offset), val, locationIdentity);
     }
 
     @Override
     @Operation(opcode = Opcode.WRITE)
-    public void writeShort(int offset, short val, Object locationIdentity) {
+    public void writeShort(int offset, short val, LocationIdentity locationIdentity) {
         writeShort(signed(offset), val, locationIdentity);
     }
 
     @Override
     @Operation(opcode = Opcode.WRITE)
-    public void writeInt(int offset, int val, Object locationIdentity) {
+    public void writeInt(int offset, int val, LocationIdentity locationIdentity) {
         writeInt(signed(offset), val, locationIdentity);
     }
 
     @Override
     @Operation(opcode = Opcode.WRITE)
-    public void writeLong(int offset, long val, Object locationIdentity) {
+    public void writeLong(int offset, long val, LocationIdentity locationIdentity) {
         writeLong(signed(offset), val, locationIdentity);
     }
 
     @Override
     @Operation(opcode = Opcode.WRITE)
-    public void writeFloat(int offset, float val, Object locationIdentity) {
+    public void writeFloat(int offset, float val, LocationIdentity locationIdentity) {
         writeFloat(signed(offset), val, locationIdentity);
     }
 
     @Override
     @Operation(opcode = Opcode.WRITE)
-    public void writeDouble(int offset, double val, Object locationIdentity) {
+    public void writeDouble(int offset, double val, LocationIdentity locationIdentity) {
         writeDouble(signed(offset), val, locationIdentity);
     }
 
     @Override
     @Operation(opcode = Opcode.WRITE)
-    public void writeWord(int offset, WordBase val, Object locationIdentity) {
+    public void writeWord(int offset, WordBase val, LocationIdentity locationIdentity) {
         writeWord(signed(offset), val, locationIdentity);
     }
 
     @Override
     @Operation(opcode = Opcode.WRITE)
-    public void writeObject(int offset, Object val, Object locationIdentity) {
+    public void writeObject(int offset, Object val, LocationIdentity locationIdentity) {
         writeObject(signed(offset), val, locationIdentity);
     }
 
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java	Mon May 13 17:11:31 2013 +0200
@@ -29,7 +29,8 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.extended.WriteNode.*;
+import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity;
+import com.oracle.graal.nodes.extended.WriteNode.WriteBarrierType;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
@@ -44,11 +45,13 @@
  */
 public class WordTypeRewriterPhase extends Phase {
 
+    private final MetaAccessProvider metaAccess;
     private final ResolvedJavaType wordBaseType;
     private final ResolvedJavaType wordImplType;
     private final Kind wordKind;
 
     public WordTypeRewriterPhase(MetaAccessProvider metaAccess, Kind wordKind) {
+        this.metaAccess = metaAccess;
         this.wordKind = wordKind;
         this.wordBaseType = metaAccess.lookupJavaType(WordBase.class);
         this.wordImplType = metaAccess.lookupJavaType(Word.class);
@@ -103,9 +106,27 @@
             }
         }
 
-        for (LoadIndexedNode load : graph.getNodes().filter(LoadIndexedNode.class).snapshot()) {
-            if (isWord(load)) {
-                load.setStamp(StampFactory.forKind(wordKind));
+        for (AccessIndexedNode node : graph.getNodes().filter(AccessIndexedNode.class).snapshot()) {
+            ValueNode array = node.array();
+            if (array.objectStamp().type() == null) {
+                // There are cases where the array does not have a known type yet. Assume it is not
+                // a word type.
+                continue;
+            }
+            assert array.objectStamp().type().isArray();
+            if (isWord(array.objectStamp().type().getComponentType())) {
+                /*
+                 * The elementKind of the node is a final field, and other information such as the
+                 * stamp depends on elementKind. Therefore, just create a new node and replace the
+                 * old one.
+                 */
+                if (node instanceof LoadIndexedNode) {
+                    graph.replaceFixedWithFixed(node, graph.add(new LoadIndexedNode(node.array(), node.index(), wordKind)));
+                } else if (node instanceof StoreIndexedNode) {
+                    graph.replaceFixedWithFixed(node, graph.add(new StoreIndexedNode(node.array(), node.index(), wordKind, ((StoreIndexedNode) node).value())));
+                } else {
+                    throw GraalInternalError.shouldNotReachHere();
+                }
             }
         }
 
@@ -138,20 +159,30 @@
                         replace(invoke, graph.unique(new XorNode(wordKind, arguments.get(0), ConstantNode.forIntegerKind(wordKind, -1, graph))));
                         break;
 
-                    case READ:
+                    case READ: {
                         assert arguments.size() == 2 || arguments.size() == 3;
                         Kind readKind = asKind(callTargetNode.returnType());
-                        Object readLocation = arguments.size() == 2 ? LocationNode.ANY_LOCATION : arguments.get(2).asConstant().asObject();
-                        replace(invoke, readOp(graph, arguments.get(0), arguments.get(1), invoke, readKind, readLocation));
+                        LocationNode location;
+                        if (arguments.size() == 2) {
+                            location = makeLocation(graph, arguments.get(1), readKind, LocationNode.ANY_LOCATION);
+                        } else {
+                            location = makeLocation(graph, arguments.get(1), readKind, arguments.get(2));
+                        }
+                        replace(invoke, readOp(graph, arguments.get(0), invoke, location));
                         break;
-
-                    case WRITE:
+                    }
+                    case WRITE: {
                         assert arguments.size() == 3 || arguments.size() == 4;
                         Kind writeKind = asKind(targetMethod.getSignature().getParameterType(1, targetMethod.getDeclaringClass()));
-                        Object writeLocation = arguments.size() == 3 ? LocationNode.ANY_LOCATION : arguments.get(3).asConstant().asObject();
-                        replace(invoke, writeOp(graph, arguments.get(0), arguments.get(1), arguments.get(2), invoke, writeKind, writeLocation));
+                        LocationNode location;
+                        if (arguments.size() == 3) {
+                            location = makeLocation(graph, arguments.get(1), writeKind, LocationNode.ANY_LOCATION);
+                        } else {
+                            location = makeLocation(graph, arguments.get(1), writeKind, arguments.get(3));
+                        }
+                        replace(invoke, writeOp(graph, arguments.get(0), arguments.get(2), invoke, location));
                         break;
-
+                    }
                     case ZERO:
                         assert arguments.size() == 0;
                         replace(invoke, ConstantNode.forIntegerKind(wordKind, 0L, graph));
@@ -266,18 +297,27 @@
         return materialize;
     }
 
-    private static ValueNode readOp(StructuredGraph graph, ValueNode base, ValueNode offset, Invoke invoke, Kind readKind, Object locationIdentity) {
-        IndexedLocationNode location = IndexedLocationNode.create(locationIdentity, readKind, 0, offset, graph, 1);
+    private LocationNode makeLocation(StructuredGraph graph, ValueNode offset, Kind readKind, ValueNode locationIdentity) {
+        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);
+    }
+
+    private static LocationNode makeLocation(StructuredGraph graph, ValueNode offset, Kind readKind, LocationIdentity locationIdentity) {
+        return IndexedLocationNode.create(locationIdentity, readKind, 0, offset, graph, 1);
+    }
+
+    private static ValueNode readOp(StructuredGraph graph, ValueNode base, Invoke invoke, LocationNode location) {
         ReadNode read = graph.add(new ReadNode(base, location, invoke.asNode().stamp()));
         graph.addBeforeFixed(invoke.asNode(), read);
         // The read must not float outside its block otherwise it may float above an explicit zero
         // check on its base address
-        read.dependencies().add(BeginNode.prevBegin(invoke.asNode()));
+        read.setGuard(AbstractBeginNode.prevBegin(invoke.asNode()));
         return read;
     }
 
-    private static ValueNode writeOp(StructuredGraph graph, ValueNode base, ValueNode offset, ValueNode value, Invoke invoke, Kind writeKind, Object locationIdentity) {
-        IndexedLocationNode location = IndexedLocationNode.create(locationIdentity, writeKind, 0, offset, graph, 1);
+    private static ValueNode writeOp(StructuredGraph graph, ValueNode base, ValueNode value, Invoke invoke, LocationNode location) {
         WriteNode write = graph.add(new WriteNode(base, value, location, WriteBarrierType.NONE));
         write.setStateAfter(invoke.stateAfter());
         graph.addBeforeFixed(invoke.asNode(), write);
@@ -309,16 +349,6 @@
         if (node.stamp() == StampFactory.forWord()) {
             return true;
         }
-        if (node instanceof LoadIndexedNode) {
-            ValueNode array = ((LoadIndexedNode) node).array();
-            if (array.objectStamp().type() == null) {
-                // There are cases where the array does not have a known type yet. Assume it is not
-                // a word type.
-                // TODO disallow LoadIndexedNode for word arrays?
-                return false;
-            }
-            return isWord(array.objectStamp().type().getComponentType());
-        }
         if (node.kind() == Kind.Object) {
             return isWord(node.objectStamp().type());
         }
@@ -344,7 +374,7 @@
         if (valueNode.isConstant() && valueNode.asConstant().getKind() == Kind.Object) {
             WordBase value = (WordBase) valueNode.asConstant().asObject();
             ConstantNode newConstant = ConstantNode.forIntegerKind(wordKind, value.rawValue(), valueNode.graph());
-            ((StructuredGraph) valueNode.graph()).replaceFloating((ConstantNode) valueNode, newConstant);
+            valueNode.graph().replaceFloating((ConstantNode) valueNode, newConstant);
         } else {
             assert !(valueNode instanceof ConstantNode) : "boxed Word constants should not appear in a snippet graph: " + valueNode + ", stamp: " + valueNode.stamp();
             valueNode.setStamp(StampFactory.forKind(wordKind));
--- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TypeSystemTest.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TypeSystemTest.java	Mon May 13 17:11:31 2013 +0200
@@ -115,7 +115,7 @@
         @Override
         public Object execute(VirtualFrame frame) {
             invocationCount++;
-            return ((TestArguments) frame.getArguments()).get(index);
+            return frame.getArguments(TestArguments.class).get(index);
         }
 
     }
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ArgumentsTest.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ArgumentsTest.java	Mon May 13 17:11:31 2013 +0200
@@ -35,7 +35,7 @@
  * A guest language can pass its own custom arguments when invoking a Truffle method by creating a
  * subclass of {@link Arguments}. When invoking a call target with
  * {@link CallTarget#call(Arguments)}, the arguments can be passed. A Truffle node can access the
- * arguments passed into the Truffle method by using {@link VirtualFrame#getArguments()}.
+ * arguments passed into the Truffle method by using {@link VirtualFrame#getArguments}.
  * </p>
  * 
  * <p>
@@ -97,7 +97,7 @@
         }
 
         int execute(VirtualFrame frame) {
-            return ((TestArguments) frame.getArguments()).values[index];
+            return frame.getArguments(TestArguments.class).values[index];
         }
     }
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CompilerDirectives.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CompilerDirectives.java	Mon May 13 17:11:31 2013 +0200
@@ -117,4 +117,13 @@
     @Target({ElementType.FIELD})
     public @interface CompilationFinal {
     }
+
+    /**
+     * Marks methods that are considered unsafe. Wrong usage of those methods can lead to unexpected
+     * behavior including a crash of the runtime. Therefore, special care should be taken.
+     */
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target({ElementType.METHOD})
+    public @interface Unsafe {
+    }
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/SourceSection.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/SourceSection.java	Mon May 13 17:11:31 2013 +0200
@@ -117,4 +117,10 @@
     public final String getCode() {
         return getSource().getCode().substring(charIndex, charLength);
     }
+
+    @Override
+    public String toString() {
+        return String.format("%s:%d", source.getName(), startLine);
+    }
+
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/Frame.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/Frame.java	Mon May 13 17:11:31 2013 +0200
@@ -36,9 +36,17 @@
     FrameDescriptor getFrameDescriptor();
 
     /**
+     * Retrieves the arguments object from this frame. The runtime assumes that the arguments object
+     * is never null. Additionally, the runtime may assume that the given parameter indicating the
+     * class of the arguments object is correct. The runtime is not required to actually check the
+     * type of the arguments object. The parameter must be a value that can be reduced to a compile
+     * time constant.
+     * 
+     * @param clazz the known type of the arguments object as a compile time constant
      * @return the arguments used when calling this method
      */
-    Arguments getArguments();
+    @CompilerDirectives.Unsafe
+    <T extends Arguments> T getArguments(Class<T> clazz);
 
     /**
      * Read access to a local variable of type {@link Object}.
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameDescriptor.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameDescriptor.java	Mon May 13 17:11:31 2013 +0200
@@ -50,7 +50,7 @@
     }
 
     public FrameSlot addFrameSlot(Object identifier) {
-        return addFrameSlot(identifier, null);
+        return addFrameSlot(identifier, FrameSlotKind.Illegal);
     }
 
     public FrameSlot addFrameSlot(Object identifier, FrameSlotKind kind) {
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/NativeFrame.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/NativeFrame.java	Mon May 13 17:11:31 2013 +0200
@@ -38,9 +38,10 @@
         this.arguments = arguments;
     }
 
+    @SuppressWarnings("unchecked")
     @Override
-    public Arguments getArguments() {
-        return arguments;
+    public <T extends Arguments> T getArguments(Class<T> clazz) {
+        return (T) arguments;
     }
 
     @Override
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultMaterializedFrame.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultMaterializedFrame.java	Mon May 13 17:11:31 2013 +0200
@@ -34,8 +34,8 @@
     }
 
     @Override
-    public Arguments getArguments() {
-        return wrapped.getArguments();
+    public <T extends Arguments> T getArguments(Class<T> clazz) {
+        return wrapped.getArguments(clazz);
     }
 
     @Override
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultVirtualFrame.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultVirtualFrame.java	Mon May 13 17:11:31 2013 +0200
@@ -43,9 +43,10 @@
         this.tags = new byte[descriptor.getSize()];
     }
 
+    @SuppressWarnings("unchecked")
     @Override
-    public Arguments getArguments() {
-        return arguments;
+    public <T extends Arguments> T getArguments(Class<T> clazz) {
+        return (T) arguments;
     }
 
     @Override
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/GraphPrintVisitor.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/GraphPrintVisitor.java	Mon May 13 17:11:31 2013 +0200
@@ -334,7 +334,7 @@
         // default handler
         createElementForNode(node);
 
-        List<Object> children = NodeUtil.findNodeChildren(node);
+        List<Node> children = NodeUtil.findNodeChildren((Node) node);
         for (Object child : children) {
             if (child == null) {
                 continue;
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java	Mon May 13 17:11:31 2013 +0200
@@ -29,6 +29,9 @@
 
 import sun.misc.*;
 
+import com.oracle.truffle.api.nodes.Node.Child;
+import com.oracle.truffle.api.nodes.Node.Children;
+
 /**
  * Utility class that manages the special access methods for node instances.
  */
@@ -73,15 +76,13 @@
                 }
 
                 // Node fields
-                if (Node.class.isAssignableFrom(field.getType())) {
-                    if (!field.getName().equals("parent")) {
-                        nodeFieldOffsetsList.add(unsafe.objectFieldOffset(field));
-                        nodeFieldClassesList.add(field.getType());
-                    } else {
-                        parentOffsetTemp = unsafe.objectFieldOffset(field);
-                        parentClassTmp = field.getType();
-                    }
-                } else if (field.getType().getComponentType() != null && Node.class.isAssignableFrom(field.getType().getComponentType())) {
+                if (Node.class.isAssignableFrom(field.getType()) && field.getName().equals("parent")) {
+                    parentOffsetTemp = unsafe.objectFieldOffset(field);
+                    parentClassTmp = field.getType();
+                } else if (Node.class.isAssignableFrom(field.getType()) && field.getAnnotation(Child.class) != null) {
+                    nodeFieldOffsetsList.add(unsafe.objectFieldOffset(field));
+                    nodeFieldClassesList.add(field.getType());
+                } else if (field.getType().getComponentType() != null && Node.class.isAssignableFrom(field.getType().getComponentType()) && field.getAnnotation(Children.class) != null) {
                     nodeArrayFieldOffsetsList.add(unsafe.objectFieldOffset(field));
                     nodeArrayFieldClassesList.add(field.getType());
                 } else {
@@ -234,7 +235,8 @@
         for (long fieldOffset : nodeClass.nodeArrayFieldOffsets) {
             Node[] children = (Node[]) unsafe.getObject(orig, fieldOffset);
             if (children != null) {
-                Node[] clonedChildren = new Node[children.length];
+                Node[] clonedChildren = children.clone();
+                Arrays.fill(clonedChildren, null);
                 for (int i = 0; i < children.length; i++) {
                     Node clonedChild = cloneNode(children[i]);
                     if (clonedChild == null) {
@@ -250,18 +252,18 @@
         return (T) clone;
     }
 
-    public static List<Object> findNodeChildren(Object node) {
-        List<Object> nodes = new ArrayList<>();
+    public static List<Node> findNodeChildren(Node node) {
+        List<Node> nodes = new ArrayList<>();
         NodeClass nodeClass = NodeClass.get(node.getClass());
 
         for (long fieldOffset : nodeClass.nodeFieldOffsets) {
             Object child = unsafe.getObject(node, fieldOffset);
             if (child != null) {
-                nodes.add(child);
+                nodes.add((Node) child);
             }
         }
         for (long fieldOffset : nodeClass.nodeArrayFieldOffsets) {
-            Object[] children = (Object[]) unsafe.getObject(node, fieldOffset);
+            Node[] children = (Node[]) unsafe.getObject(node, fieldOffset);
             if (children != null) {
                 nodes.addAll(Arrays.asList(children));
             }
@@ -385,14 +387,15 @@
     }
 
     @SuppressWarnings("unchecked")
-    public static <T> T findFirstNodeInstance(Object root, Class<T> clazz) {
-        List<Object> childNodes = findNodeChildren(root);
-
-        for (Object childNode : childNodes) {
+    public static <T> T findFirstNodeInstance(Node root, Class<T> clazz) {
+        for (Node childNode : findNodeChildren(root)) {
             if (clazz.isInstance(childNode)) {
                 return (T) childNode;
             } else {
-                return findFirstNodeInstance(childNode, clazz);
+                T node = findFirstNodeInstance(childNode, clazz);
+                if (node != null) {
+                    return node;
+                }
             }
         }
         return null;
@@ -470,8 +473,16 @@
     }
 
     public static String printTreeToString(Node node) {
+        return printTreeToString(node, false);
+    }
+
+    private static String printTreeToString(Node node, boolean compact) {
         ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
-        printTree(new PrintStream(byteOut), node);
+        if (compact) {
+            printCompactTree(new PrintStream(byteOut), node);
+        } else {
+            printTree(new PrintStream(byteOut), node);
+        }
         try {
             byteOut.flush();
         } catch (IOException e) {
@@ -490,6 +501,61 @@
         printTree(p, node, new NodeTreeResolver());
     }
 
+    public static String printCompactTreeToString(Node node) {
+        return printTreeToString(node, true);
+    }
+
+    public static void printCompactTree(PrintStream p, Node node) {
+        printCompactTree(p, null, node, 1);
+    }
+
+    private static void printCompactTree(PrintStream p, Node parent, Node node, int level) {
+        if (node == null) {
+            return;
+        }
+        for (int i = 0; i < level; i++) {
+            p.print("  ");
+        }
+        if (parent == null) {
+            p.println(node.getClass().getSimpleName());
+        } else {
+            String fieldName = null;
+            Field[] fields = NodeUtil.getAllFields(parent.getClass());
+            try {
+                for (Field field : fields) {
+                    field.setAccessible(true);
+                    Object value = field.get(parent);
+                    if (value == node) {
+                        fieldName = field.getName();
+                        break;
+                    } else if (value instanceof Node[]) {
+                        int index = 0;
+                        for (Node arrayNode : (Node[]) value) {
+                            if (arrayNode == node) {
+                                fieldName = field.getName() + "[" + index + "]";
+                                break;
+                            }
+                            index++;
+                        }
+                    }
+                }
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+
+            if (fieldName == null) {
+                fieldName = "unknownField";
+            }
+            p.print(fieldName);
+            p.print(" = ");
+            p.println(node.getClass().getSimpleName());
+        }
+
+        for (Node child : node.getChildren()) {
+            printCompactTree(p, node, child, level + 1);
+        }
+    }
+
     /**
      * Prints a human readable form of a tree to the given {@link PrintStream}. The
      * {@link TreeResolver} interface needs to be implemented to specify how the method can read the
@@ -635,12 +701,12 @@
 
         @Override
         public boolean isChildObject(Field f) {
-            return Node.class.isAssignableFrom(f.getType());
+            return Node.class.isAssignableFrom(f.getType()) && f.getAnnotation(Child.class) != null;
         }
 
         @Override
         public boolean isChildArrayObject(Field f) {
-            return f.getType().getComponentType() != null && Node.class.isAssignableFrom(f.getType().getComponentType());
+            return f.getType().getComponentType() != null && Node.class.isAssignableFrom(f.getType().getComponentType()) && f.getAnnotation(Children.class) != null;
         }
 
         @Override
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleTypes.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleTypes.java	Mon May 13 17:11:31 2013 +0200
@@ -48,6 +48,7 @@
     private final DeclaredType childAnnotation;
     private final DeclaredType childrenAnnotation;
     private final TypeMirror compilerDirectives;
+    private final TypeMirror compilerAsserts;
 
     private final List<String> errors = new ArrayList<>();
 
@@ -59,6 +60,7 @@
         childAnnotation = getRequired(context, Child.class);
         childrenAnnotation = getRequired(context, Children.class);
         compilerDirectives = getRequired(context, CompilerDirectives.class);
+        compilerAsserts = getRequired(context, CompilerAsserts.class);
         assumption = getRequired(context, Assumption.class);
         invalidAssumption = getRequired(context, InvalidAssumptionException.class);
     }
@@ -118,4 +120,8 @@
     public DeclaredType getChildrenAnnotation() {
         return childrenAnnotation;
     }
+
+    public TypeMirror getCompilerAsserts() {
+        return compilerAsserts;
+    }
 }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTreeBuilder.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTreeBuilder.java	Mon May 13 17:11:31 2013 +0200
@@ -475,6 +475,19 @@
         currentElement.registerAtEnd(callback);
     }
 
+    public CodeTreeBuilder defaultDeclaration(TypeMirror type, String name) {
+        if (!Utils.isVoid(type)) {
+            startStatement();
+            type(type);
+            string(" ");
+            string(name);
+            string(" = ");
+            defaultValue(type);
+            end(); // statement
+        }
+        return this;
+    }
+
     public CodeTreeBuilder declaration(TypeMirror type, String name, CodeTree init) {
         if (Utils.isVoid(type)) {
             startStatement();
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java	Mon May 13 17:11:31 2013 +0200
@@ -43,6 +43,9 @@
 
     private static final String THIS_NODE_LOCAL_VAR_NAME = "thisNode";
 
+    private static final String EXECUTE_GENERIC_NAME = "executeGeneric_";
+    private static final String EXECUTE_SPECIALIZE_NAME = "executeAndSpecialize_";
+
     public NodeCodeGenerator(ProcessorContext context) {
         super(context);
     }
@@ -243,41 +246,16 @@
         return builder.getRoot();
     }
 
-    private static String genClassName(NodeData node) {
+    private static String baseClassName(NodeData node) {
         String nodeid = node.getNodeId();
         if (nodeid.endsWith("Node") && !nodeid.equals("Node")) {
             nodeid = nodeid.substring(0, nodeid.length() - 4);
         }
         String name = Utils.firstLetterUpperCase(nodeid);
-        name += "GenNode";
+        name += "BaseNode";
         return name;
     }
 
-    private String generatedGenericMethodName(SpecializationData specialization) {
-        final String prefix = "generic";
-
-        if (specialization == null) {
-            return prefix;
-        }
-
-        if (!specialization.getNode().needsRewrites(context)) {
-            return prefix;
-        }
-
-        SpecializationData prev = null;
-        for (SpecializationData current : specialization.getNode().getSpecializations()) {
-            if (specialization == current) {
-                if (prev == null || prev.isUninitialized()) {
-                    return prefix;
-                } else {
-                    return prefix + current.getId();
-                }
-            }
-            prev = current;
-        }
-        return prefix;
-    }
-
     private static CodeTree createCallTypeSystemMethod(ProcessorContext context, CodeTreeBuilder parent, NodeData node, String methodName, CodeTree value) {
         CodeTreeBuilder builder = new CodeTreeBuilder(parent);
         startCallTypeSystemMethod(context, builder, node, methodName);
@@ -419,15 +397,9 @@
         String andOperator = conditionPrefix != null ? conditionPrefix + " && " : "";
 
         if (emitAssumptions) {
-            boolean isStatic = parent.findMethod().getModifiers().contains(STATIC);
-
             for (String assumption : guardedSpecialization.getAssumptions()) {
                 builder.string(andOperator);
-                if (isStatic) {
-                    builder.string(THIS_NODE_LOCAL_VAR_NAME);
-                } else {
-                    builder.string("this");
-                }
+                builder.string("this");
                 builder.string(".").string(assumption).string(".isValid()");
                 andOperator = " && ";
             }
@@ -599,6 +571,16 @@
         return true;
     }
 
+    private static CodeTree createReturnNewSpecialization(CodeTreeBuilder parent, SpecializationData specialization, String thisLocalVariableName, boolean hasCopyConstructor) {
+        CodeTreeBuilder builder = new CodeTreeBuilder(parent);
+        builder.startReturn().startNew(nodeSpecializationClassName(specialization));
+        if (hasCopyConstructor) {
+            builder.string(thisLocalVariableName);
+        }
+        builder.end().end();
+        return builder.getRoot();
+    }
+
     @Override
     protected void createChildren(NodeData node) {
         Map<NodeData, List<TypeElement>> childTypes = new LinkedHashMap<>();
@@ -614,15 +596,15 @@
         }
     }
 
-    private class NodeGenFactory extends ClassElementFactory<NodeData> {
+    private class NodeBaseFactory extends ClassElementFactory<NodeData> {
 
-        public NodeGenFactory(ProcessorContext context) {
+        public NodeBaseFactory(ProcessorContext context) {
             super(context);
         }
 
         @Override
         protected CodeTypeElement create(NodeData node) {
-            CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, ABSTRACT, STATIC), genClassName(node), node.getNodeType(), false);
+            CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, ABSTRACT, STATIC), baseClassName(node), node.getNodeType(), false);
 
             for (NodeChildData child : node.getChildren()) {
                 clazz.add(createChildField(child));
@@ -649,6 +631,19 @@
             return clazz;
         }
 
+        @Override
+        protected void createChildren(NodeData node) {
+            CodeTypeElement clazz = getElement();
+
+            if (node.needsRewrites(context)) {
+                clazz.add(createGenericExecute(node, EXECUTE_SPECIALIZE_NAME, true));
+            }
+
+            if (node.getGenericSpecialization() != null) {
+                clazz.add(createGenericExecute(node, EXECUTE_GENERIC_NAME, false));
+            }
+        }
+
         private void createConstructors(NodeData node, CodeTypeElement clazz) {
             List<ExecutableElement> constructors = findUserConstructors(node.getNodeType());
             if (constructors.isEmpty()) {
@@ -749,6 +744,162 @@
             var.getAnnotationMirrors().add(new CodeAnnotationMirror(annotationType));
             return var;
         }
+
+        private CodeExecutableElement createGenericExecute(NodeData node, String name, boolean specialize) {
+            TypeMirror genericReturnType = node.getGenericSpecialization().getReturnType().getType();
+
+            CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED), genericReturnType, name);
+            CodeTreeBuilder builder = method.createBuilder();
+
+            String prefix = null;
+            if (specialize) {
+                method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "minimumState"));
+
+                builder.startStatement();
+                builder.startStaticCall(getContext().getTruffleTypes().getCompilerAsserts(), "neverPartOfCompilation").end();
+                builder.end();
+
+                emitSpecializationListeners(builder, node);
+                builder.defaultDeclaration(node.getGenericSpecialization().getReturnSignature().getPrimitiveType(), "result");
+                if (node.getGenericSpecialization().isUseSpecializationsForGeneric()) {
+                    builder.defaultDeclaration(getContext().getType(boolean.class), "resultIsSet");
+                }
+                builder.startStatement().string("boolean allowed = (minimumState == ").string(nodeSpecializationClassName(node.getSpecializations().get(0))).string(".class)").end();
+                prefix = null;
+            }
+
+            addInternalValueParameters(method, node.getGenericSpecialization(), true);
+
+            List<SpecializationData> specializations = node.getSpecializations();
+            if (!specialize && !node.getGenericSpecialization().isUseSpecializationsForGeneric()) {
+                specializations = Arrays.asList(node.getGenericSpecialization());
+            }
+
+            // group specializations for reachabiltiy
+            List<SpecializationData> unreachableSpecializations = new ArrayList<>();
+            List<SpecializationData> filteredSpecializations = new ArrayList<>();
+            if (!specialize) {
+                unreachableSpecializations = new ArrayList<>();
+                filteredSpecializations = new ArrayList<>();
+                boolean unreachable = false;
+                for (SpecializationData specialization : specializations) {
+                    if (unreachable) {
+                        unreachableSpecializations.add(specialization);
+                    } else {
+                        filteredSpecializations.add(specialization);
+                        if (!specialization.isUninitialized() && !specialization.hasRewrite(getContext())) {
+                            unreachable = true;
+                        }
+                    }
+                }
+            } else {
+                unreachableSpecializations = Collections.emptyList();
+                filteredSpecializations = specializations;
+            }
+
+            for (SpecializationData current : filteredSpecializations) {
+                if (current.isUninitialized()) {
+                    continue;
+                }
+                CodeTreeBuilder execute = new CodeTreeBuilder(builder);
+
+                execute.tree(createGenericInvoke(builder, current, specialize));
+
+                if (specialize && !current.isGeneric()) {
+                    builder.startStatement().string("allowed = allowed || (minimumState == ").string(nodeSpecializationClassName(current)).string(".class)").end();
+                }
+
+                builder.tree(createGuardAndCast(builder, prefix, current.getNode().getGenericSpecialization(), current, true, execute.getRoot(), null, true));
+            }
+
+            for (SpecializationData specializationData : unreachableSpecializations) {
+                builder.string("// unreachable ").string(specializationData.getId()).newLine();
+            }
+
+            return method;
+        }
+
+        private CodeTree createGenericInvoke(CodeTreeBuilder parent, SpecializationData current, boolean specialize) {
+            CodeTreeBuilder builder = new CodeTreeBuilder(parent);
+
+            if (!current.getExceptions().isEmpty()) {
+                builder.startTryBlock();
+            }
+
+            CodeTree executeCall = null;
+            if (current.getMethod() != null) {
+                executeCall = createTemplateMethodCall(builder, null, current.getNode().getGenericSpecialization(), current, null);
+            }
+
+            if (specialize && executeCall == null && !current.getNode().getGenericSpecialization().isUseSpecializationsForGeneric()) {
+                emitEncounteredSynthetic(builder);
+            } else if (specialize) {
+
+                if (current.getNode().getGenericSpecialization().isUseSpecializationsForGeneric()) {
+                    builder.startIf().string("!resultIsSet").end().startBlock();
+                    if (executeCall != null) {
+                        if (current.getReturnSignature().isVoid()) {
+                            builder.statement(executeCall);
+                        } else {
+                            builder.startStatement().string("result = ").tree(executeCall).end();
+                        }
+                        builder.statement("resultIsSet = true");
+                    } else {
+                        emitEncounteredSynthetic(builder);
+                    }
+                    builder.end();
+                }
+
+                if (!current.isGeneric()) {
+                    builder.startIf().string("allowed").end().startBlock();
+                }
+
+                if (!current.getNode().getGenericSpecialization().isUseSpecializationsForGeneric()) {
+                    if (current.getReturnSignature().isVoid()) {
+                        builder.statement(executeCall);
+                    } else {
+                        builder.startStatement().string("result = ").tree(executeCall).end();
+                    }
+                }
+
+                builder.startStatement().startCall("super", "replace");
+                builder.startGroup().startNew(nodeSpecializationClassName(current)).string("this").end().end();
+                builder.end().end();
+
+                if (current.getReturnSignature().isVoid()) {
+                    builder.returnStatement();
+                } else {
+                    builder.startReturn().string("result").end();
+                }
+                if (!current.isGeneric()) {
+                    builder.end();
+                }
+            } else {
+                if (executeCall == null) {
+                    emitEncounteredSynthetic(builder);
+                } else {
+                    builder.startReturn().tree(executeCall).end();
+                }
+            }
+
+            if (!current.getExceptions().isEmpty()) {
+                for (SpecializationThrowsData exception : current.getExceptions()) {
+                    builder.end().startCatchBlock(exception.getJavaClass(), "rewriteEx");
+                    builder.string("// fall through").newLine();
+                }
+                builder.end();
+            }
+
+            return builder.getRoot();
+        }
+
+        private void emitSpecializationListeners(CodeTreeBuilder builder, NodeData node) {
+            for (TemplateMethod listener : node.getSpecializationListeners()) {
+                builder.startStatement();
+                builder.tree(createTemplateMethodCall(builder, null, listener, listener, null));
+                builder.end(); // statement
+            }
+        }
     }
 
     private class NodeFactoryFactory extends ClassElementFactory<NodeData> {
@@ -781,23 +932,15 @@
             Modifier createVisibility = Utils.getVisibility(clazz.getModifiers());
 
             if (node.needsFactory()) {
-                NodeGenFactory factory = new NodeGenFactory(context);
+                NodeBaseFactory factory = new NodeBaseFactory(context);
                 add(factory, node);
                 generatedNode = factory.getElement();
 
-                createFactoryMethods(node, clazz, createVisibility);
-
                 if (node.needsRewrites(context)) {
                     clazz.add(createCreateSpecializedMethod(node, createVisibility));
-                    clazz.add(createSpecializeMethod(node));
                 }
 
-                if (node.getGenericSpecialization() != null) {
-                    List<CodeExecutableElement> genericMethods = createGeneratedGenericMethod(node);
-                    for (CodeExecutableElement method : genericMethods) {
-                        clazz.add(method);
-                    }
-                }
+                createFactoryMethods(node, clazz, createVisibility);
 
                 for (SpecializationData specialization : node.getSpecializations()) {
                     add(new SpecializedNodeFactory(context, generatedNode), specialization);
@@ -1174,125 +1317,6 @@
             return method;
         }
 
-        private CodeExecutableElement createSpecializeMethod(NodeData node) {
-            CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE, STATIC), node.getNodeType(), "specialize");
-            method.addParameter(new CodeVariableElement(generatedNode.asType(), THIS_NODE_LOCAL_VAR_NAME));
-            method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "minimumState"));
-            addInternalValueParameters(method, node.getGenericSpecialization(), true);
-
-            CodeTreeBuilder body = method.createBuilder();
-            body.startStatement().string("boolean allowed = (minimumState == ").string(nodeSpecializationClassName(node.getSpecializations().get(0))).string(".class)").end();
-
-            boolean hasCopyConstructor = findCopyConstructor(generatedNode.asType()) != null;
-
-            for (int i = 1; i < node.getSpecializations().size(); i++) {
-                SpecializationData specialization = node.getSpecializations().get(i);
-                body.startStatement().string("allowed = allowed || (minimumState == ").string(nodeSpecializationClassName(specialization)).string(".class)").end();
-
-                CodeTree guarded = createReturnNewSpecialization(body, specialization, THIS_NODE_LOCAL_VAR_NAME, hasCopyConstructor);
-
-                body.tree(createGuardAndCast(body, "allowed", node.getGenericSpecialization(), specialization, false, guarded, null, true));
-            }
-            body.startThrow().startNew(getContext().getType(IllegalArgumentException.class)).end().end();
-
-            return method;
-        }
-
-        private CodeTree createReturnNewSpecialization(CodeTreeBuilder parent, SpecializationData specialization, String thisLocalVariableName, boolean hasCopyConstructor) {
-            CodeTreeBuilder builder = new CodeTreeBuilder(parent);
-            builder.startReturn().startNew(nodeSpecializationClassName(specialization));
-            if (hasCopyConstructor) {
-                builder.string(thisLocalVariableName);
-            }
-            builder.end().end();
-            return builder.getRoot();
-        }
-
-        private List<CodeExecutableElement> createGeneratedGenericMethod(NodeData node) {
-            TypeMirror genericReturnType = node.getGenericSpecialization().getReturnType().getType();
-            if (node.needsRewrites(context)) {
-                List<CodeExecutableElement> methods = new ArrayList<>();
-
-                List<SpecializationData> specializations = node.getSpecializations();
-                SpecializationData prev = null;
-                for (int i = 0; i < specializations.size(); i++) {
-                    SpecializationData current = specializations.get(i);
-                    SpecializationData next = i + 1 < specializations.size() ? specializations.get(i + 1) : null;
-                    if (prev == null || current.isUninitialized()) {
-                        prev = current;
-                        continue;
-                    } else {
-                        String methodName = generatedGenericMethodName(current);
-                        CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE, STATIC), genericReturnType, methodName);
-                        method.addParameter(new CodeVariableElement(generatedNode.asType(), THIS_NODE_LOCAL_VAR_NAME));
-                        addInternalValueParameters(method, node.getGenericSpecialization(), true);
-
-                        emitGeneratedGenericSpecialization(method.createBuilder(), current, next);
-
-                        methods.add(method);
-                    }
-                    prev = current;
-                }
-
-                return methods;
-            } else {
-                CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE, STATIC), genericReturnType, generatedGenericMethodName(null));
-                method.addParameter(new CodeVariableElement(generatedNode.asType(), THIS_NODE_LOCAL_VAR_NAME));
-                addInternalValueParameters(method, node.getGenericSpecialization(), true);
-                emitInvokeDoMethod(method.createBuilder(), node.getGenericSpecialization(), 0);
-                return Arrays.asList(method);
-            }
-        }
-
-        private void emitGeneratedGenericSpecialization(CodeTreeBuilder builder, SpecializationData current, SpecializationData next) {
-            CodeTreeBuilder invokeMethodBuilder = new CodeTreeBuilder(builder);
-            emitInvokeDoMethod(invokeMethodBuilder, current, 0);
-            CodeTree invokeMethod = invokeMethodBuilder.getRoot();
-
-            if (next != null) {
-                CodeTreeBuilder nextBuilder = builder.create();
-
-                nextBuilder.startReturn().startCall(generatedGenericMethodName(next));
-                nextBuilder.string(THIS_NODE_LOCAL_VAR_NAME);
-                addInternalValueParameterNames(nextBuilder, next, next, null, true, true);
-                nextBuilder.end().end();
-
-                invokeMethod = createGuardAndCast(builder, null, current.getNode().getGenericSpecialization(), current, true, invokeMethod, nextBuilder.getRoot(), true);
-            }
-
-            builder.tree(invokeMethod);
-
-            if (next != null) {
-                builder.end();
-            }
-        }
-
-        private void emitInvokeDoMethod(CodeTreeBuilder builder, SpecializationData specialization, int level) {
-            if (!specialization.getExceptions().isEmpty()) {
-                builder.startTryBlock();
-            }
-
-            if (specialization.getMethod() == null) {
-                emitEncounteredSynthetic(builder);
-            } else {
-                builder.startReturn();
-                builder.tree(createTemplateMethodCall(builder, null, specialization.getNode().getGenericSpecialization(), specialization, null));
-                builder.end(); // return
-            }
-
-            if (!specialization.getExceptions().isEmpty()) {
-                for (SpecializationThrowsData exception : specialization.getExceptions()) {
-                    builder.end().startCatchBlock(exception.getJavaClass(), "ex" + level);
-
-                    builder.startReturn().startCall(generatedGenericMethodName(exception.getTransitionTo()));
-                    builder.string(THIS_NODE_LOCAL_VAR_NAME);
-                    addInternalValueParameterNames(builder, exception.getTransitionTo(), exception.getTransitionTo(), null, true, true);
-                    builder.end().end();
-                }
-                builder.end();
-            }
-        }
-
     }
 
     private class SpecializedNodeFactory extends ClassElementFactory<SpecializationData> {
@@ -1342,10 +1366,6 @@
                     clazz.remove(executeMethod);
                 }
             }
-
-            if (specialization.hasRewrite(getContext())) {
-                buildSpecializeAndExecute(clazz, specialization);
-            }
         }
 
         private CodeTree createExecuteBody(CodeTreeBuilder parent, SpecializationData specialization, ExecutableTypeData execType) {
@@ -1440,8 +1460,7 @@
 
             List<ActualParameter> executeParameters = new ArrayList<>();
             for (ActualParameter sourceParameter : executable.getParameters()) {
-                NodeChildData field = specialization.getNode().findChild(sourceParameter.getSpecification().getName());
-                if (field == null) {
+                if (!sourceParameter.getSpecification().isSignature()) {
                     continue;
                 }
 
@@ -1474,14 +1493,14 @@
                     builder.string("// ignore").newLine();
                 } else {
                     builder.startReturn();
-                    builder.tree(createExpectType(node, castedType, CodeTreeBuilder.singleString("ex.getResult()")));
+                    builder.tree(createExpectExecutableType(node, specialization.getNode().getTypeSystem().getGenericTypeData(), castedType, CodeTreeBuilder.singleString("ex.getResult()")));
                     builder.end();
                 }
                 builder.end();
 
                 if (!returnVoid) {
                     builder.startReturn();
-                    builder.tree(createExpectType(node, castedType, CodeTreeBuilder.singleString("value")));
+                    builder.tree(createExpectExecutableType(node, castExecutable.getReturnSignature(), executable, CodeTreeBuilder.singleString("value")));
                     builder.end();
                 }
             } else {
@@ -1489,7 +1508,7 @@
                     builder.statement(primaryExecuteCall);
                 } else {
                     builder.startReturn();
-                    builder.tree(createExpectType(node, castedType, primaryExecuteCall));
+                    builder.tree(createExpectExecutableType(node, castExecutable.getReturnSignature(), executable, primaryExecuteCall));
                     builder.end();
                 }
             }
@@ -1497,21 +1516,24 @@
             return builder.getRoot();
         }
 
-        private CodeTree createExpectType(NodeData node, ExecutableTypeData castedType, CodeTree value) {
-            if (castedType == null) {
+        private CodeTree createExpectExecutableType(NodeData node, TypeData sourceType, ExecutableTypeData castedType, CodeTree value) {
+            boolean hasUnexpected = castedType.hasUnexpectedValue(getContext());
+            return createCastType(node, sourceType, castedType.getType(), hasUnexpected, value);
+        }
+
+        private CodeTree createCastType(NodeData node, TypeData sourceType, TypeData targetType, boolean expect, CodeTree value) {
+            if (targetType == null) {
                 return value;
-            } else if (castedType.getType().isVoid()) {
-                return value;
-            } else if (castedType.getType().isGeneric()) {
+            } else if (!sourceType.needsCastTo(getContext(), targetType)) {
                 return value;
             }
 
             CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
             String targetMethodName;
-            if (castedType.hasUnexpectedValue(getContext())) {
-                targetMethodName = TypeSystemCodeGenerator.expectTypeMethodName(castedType.getType());
+            if (expect) {
+                targetMethodName = TypeSystemCodeGenerator.expectTypeMethodName(targetType);
             } else {
-                targetMethodName = TypeSystemCodeGenerator.asTypeMethodName(castedType.getType());
+                targetMethodName = TypeSystemCodeGenerator.asTypeMethodName(targetType);
             }
             startCallTypeSystemMethod(getContext(), builder, node, targetMethodName);
 
@@ -1520,24 +1542,6 @@
             return builder.getRoot();
         }
 
-        private CodeTree createExpectType(NodeData node, TypeData castedType, CodeTree value) {
-            if (castedType == null) {
-                return value;
-            } else if (castedType.isVoid()) {
-                return value;
-            } else if (castedType.isGeneric()) {
-                return value;
-            }
-
-            CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
-            String targetMethodName = TypeSystemCodeGenerator.expectTypeMethodName(castedType);
-            startCallTypeSystemMethod(getContext(), builder, node, targetMethodName);
-
-            builder.tree(value);
-            builder.end().end();
-            return builder.getRoot();
-        }
-
         private CodeTree createFunctionalExecute(CodeTreeBuilder parent, SpecializationData specialization, ExecutableTypeData executable) {
             CodeTreeBuilder builder = new CodeTreeBuilder(parent);
             if (specialization.isUninitialized()) {
@@ -1547,15 +1551,15 @@
             builder.tree(createExecuteChildren(builder, executable, specialization, specialization.getParameters(), null, false));
 
             CodeTree executeNode;
-            if (specialization.isUninitialized()) {
-                builder.tree(createSpecializeCall(builder, specialization));
-            }
             executeNode = createExecute(builder, executable, specialization);
 
             SpecializationData next = specialization.findNextSpecialization();
             CodeTree returnSpecialized = null;
             if (next != null) {
-                returnSpecialized = createReturnSpecializeAndExecute(builder, executable, next, null);
+                CodeTreeBuilder returnBuilder = new CodeTreeBuilder(builder);
+                returnBuilder.tree(createDeoptimize(builder));
+                returnBuilder.tree(createReturnExecuteAndSpecialize(builder, executable, next, null));
+                returnSpecialized = returnBuilder.getRoot();
             }
             builder.tree(createGuardAndCast(builder, null, specialization, specialization, true, executeNode, returnSpecialized, false));
 
@@ -1570,28 +1574,6 @@
             return builder.getRoot();
         }
 
-        private CodeTree createSpecializeCall(CodeTreeBuilder parent, SpecializationData specialization) {
-            NodeData node = specialization.getNode();
-
-            CodeTreeBuilder builder = new CodeTreeBuilder(parent);
-            emitSpecializationListeners(builder, node);
-
-            builder.startStatement();
-            builder.startCall("replace");
-            if (node.needsRewrites(getContext())) {
-                builder.startCall(factoryClassName(node), "specialize");
-                builder.string("this");
-                builder.typeLiteral(builder.findMethod().getEnclosingElement().asType());
-                addInternalValueParameterNames(builder, specialization, specialization, null, true, true);
-                builder.end(); // call replace, call specialize
-            } else {
-                builder.startCall(factoryClassName(node), "createSpecialized").string("this").string("null").end();
-            }
-            builder.end().end();
-            emitSpecializationListeners(builder, node);
-            return builder.getRoot();
-        }
-
         private CodeTree createExecute(CodeTreeBuilder parent, ExecutableTypeData executable, SpecializationData specialization) {
             NodeData node = specialization.getNode();
             CodeTreeBuilder builder = new CodeTreeBuilder(parent);
@@ -1607,23 +1589,14 @@
 
             CodeTreeBuilder returnBuilder = new CodeTreeBuilder(parent);
             if (specialization.isUninitialized()) {
-                String genericMethodName = generatedGenericMethodName(null);
-                returnBuilder.startCall(factoryClassName(node), genericMethodName);
-                returnBuilder.string("this");
+                returnBuilder.startCall("super", EXECUTE_SPECIALIZE_NAME);
+                returnBuilder.startGroup().string(nodeSpecializationClassName(specialization)).string(".class").end();
                 addInternalValueParameterNames(returnBuilder, specialization, specialization, null, true, true);
                 returnBuilder.end();
             } else if (specialization.getMethod() == null && !node.needsRewrites(context)) {
                 emitEncounteredSynthetic(builder);
             } else if (specialization.isGeneric()) {
-                String genericMethodName;
-                if (!specialization.isUseSpecializationsForGeneric()) {
-                    genericMethodName = generatedGenericMethodName(specialization);
-                } else {
-                    genericMethodName = generatedGenericMethodName(null);
-                }
-
-                returnBuilder.startCall(factoryClassName(node), genericMethodName);
-                returnBuilder.string("this");
+                returnBuilder.startCall("super", EXECUTE_GENERIC_NAME);
                 addInternalValueParameterNames(returnBuilder, specialization, specialization, null, true, true);
                 returnBuilder.end();
             } else {
@@ -1649,13 +1622,14 @@
             if (!specialization.getExceptions().isEmpty()) {
                 for (SpecializationThrowsData exception : specialization.getExceptions()) {
                     builder.end().startCatchBlock(exception.getJavaClass(), "ex");
-                    builder.tree(createReturnSpecializeAndExecute(parent, executable, exception.getTransitionTo(), null));
+                    builder.tree(createDeoptimize(builder));
+                    builder.tree(createReturnExecuteAndSpecialize(parent, executable, exception.getTransitionTo(), null));
                 }
                 builder.end();
             }
             if (!specialization.getAssumptions().isEmpty()) {
                 builder.end().startCatchBlock(getContext().getTruffleTypes().getInvalidAssumption(), "ex");
-                builder.tree(createReturnSpecializeAndExecute(parent, executable, specialization.findNextSpecialization(), null));
+                builder.tree(createReturnExecuteAndSpecialize(parent, executable, specialization.findNextSpecialization(), null));
                 builder.end();
             }
 
@@ -1670,21 +1644,24 @@
 
             for (ActualParameter targetParameter : targetParameters) {
                 NodeChildData field = sourceNode.findChild(targetParameter.getSpecification().getName());
-                if (field == null) {
+                if (!targetParameter.getSpecification().isSignature()) {
                     continue;
                 }
+
                 TypeData targetType = targetParameter.getTypeSystemType();
-
-                ExecutableTypeData targetExecutable = field.findExecutableType(getContext(), targetType);
+                ExecutableTypeData targetExecutable = null;
+                if (field != null) {
+                    targetExecutable = field.findExecutableType(getContext(), targetType);
+                }
 
                 ActualParameter sourceParameter = sourceExecutable.findParameter(targetParameter.getLocalName());
 
                 String targetVariableName = valueName(targetParameter);
                 CodeTree executionExpression = null;
-                if (cast || sourceParameter != null) {
+                if ((sourceParameter != null && cast) || sourceParameter != null) {
                     TypeData sourceType = sourceParameter.getTypeSystemType();
-                    if (!sourceType.needsCastTo(getContext(), targetType)) {
-                        if (field.isShortCircuit() && sourceParameter != null) {
+                    if (targetExecutable == null || !sourceType.needsCastTo(getContext(), targetType)) {
+                        if (field != null && field.isShortCircuit() && sourceParameter != null) {
                             builder.tree(createShortCircuitValue(builder, specialization, field, targetParameter.getPreviousParameter(), unexpectedParameter));
                         }
                         builder.startStatement();
@@ -1692,8 +1669,10 @@
                         builder.string(valueName(targetParameter)).string(" = ");
                         builder.tree(CodeTreeBuilder.singleString(valueNameEvaluated(targetParameter)));
                         builder.end();
+                        continue;
                     } else {
-                        executionExpression = createExpectType(sourceNode, targetExecutable, CodeTreeBuilder.singleString(valueNameEvaluated(targetParameter)));
+                        CodeTree valueTree = CodeTreeBuilder.singleString(valueNameEvaluated(targetParameter));
+                        executionExpression = createExpectExecutableType(sourceNode, sourceType, targetExecutable, valueTree);
                     }
                 } else if (sourceParameter == null) {
                     executionExpression = createExecuteChildExpression(builder, field, targetParameter, unexpectedParameter);
@@ -1712,14 +1691,6 @@
             return builder.getRoot();
         }
 
-        private void emitSpecializationListeners(CodeTreeBuilder builder, NodeData node) {
-            for (TemplateMethod listener : node.getSpecializationListeners()) {
-                builder.startStatement();
-                builder.tree(createTemplateMethodCall(builder, null, listener, listener, null));
-                builder.end(); // statement
-            }
-        }
-
         private CodeTree createCatchUnexpectedTree(CodeTreeBuilder parent, CodeTree body, String targetVariableName, SpecializationData specialization, ExecutableTypeData currentExecutable,
                         ExecutableTypeData targetExecutable, ActualParameter param, boolean shortCircuit) {
             CodeTreeBuilder builder = new CodeTreeBuilder(parent);
@@ -1749,7 +1720,7 @@
             }
             builder.string(" = ");
             if (cast) {
-                builder.tree(createExpectType(specialization.getNode(), param.getTypeSystemType(), body));
+                builder.tree(createCastType(specialization.getNode(), targetExecutable.getType(), param.getTypeSystemType(), true, body));
             } else {
                 builder.tree(body);
             }
@@ -1761,8 +1732,9 @@
                 ActualParameter genericParameter = generic.findParameter(param.getLocalName());
 
                 List<ActualParameter> genericParameters = generic.getParametersAfter(genericParameter);
+                builder.tree(createDeoptimize(builder));
                 builder.tree(createExecuteChildren(parent, currentExecutable, generic, genericParameters, genericParameter, false));
-                builder.tree(createReturnSpecializeAndExecute(builder, currentExecutable, specialization.findNextSpecialization(), param));
+                builder.tree(createReturnExecuteAndSpecialize(builder, currentExecutable, specialization.findNextSpecialization(), param));
                 builder.end(); // catch block
             }
 
@@ -1878,71 +1850,24 @@
             return builder.getRoot();
         }
 
-        private CodeTree createReturnSpecializeAndExecute(CodeTreeBuilder parent, ExecutableTypeData executable, SpecializationData nextSpecialization, ActualParameter exceptionParam) {
+        private CodeTree createReturnExecuteAndSpecialize(CodeTreeBuilder parent, ExecutableTypeData executable, SpecializationData nextSpecialization, ActualParameter exceptionParam) {
+
+            SpecializationData generic = nextSpecialization.getNode().getGenericSpecialization();
             CodeTreeBuilder specializeCall = new CodeTreeBuilder(parent);
-            specializeCall.startCall("specializeAndExecute");
+            specializeCall.startCall(EXECUTE_SPECIALIZE_NAME);
             specializeCall.string(nodeSpecializationClassName(nextSpecialization) + ".class");
-            addInternalValueParameterNames(specializeCall, nextSpecialization.getNode().getGenericSpecialization(), nextSpecialization.getNode().getGenericSpecialization(),
-                            exceptionParam != null ? exceptionParam.getLocalName() : null, true, true);
+            addInternalValueParameterNames(specializeCall, generic, nextSpecialization.getNode().getGenericSpecialization(), exceptionParam != null ? exceptionParam.getLocalName() : null, true, true);
             specializeCall.end().end();
 
             CodeTreeBuilder builder = new CodeTreeBuilder(parent);
+
             builder.startReturn();
-            builder.tree(createExpectType(nextSpecialization.getNode(), executable, specializeCall.getRoot()));
+            builder.tree(createExpectExecutableType(nextSpecialization.getNode(), generic.getReturnSignature(), executable, specializeCall.getRoot()));
             builder.end();
 
             return builder.getRoot();
         }
 
-        private void buildSpecializeAndExecute(CodeTypeElement clazz, SpecializationData specialization) {
-            NodeData node = specialization.getNode();
-            TypeData returnType = node.getGenericSpecialization().getReturnType().getTypeSystemType();
-
-            CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE), returnType.getPrimitiveType(), "specializeAndExecute");
-            method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "minimumState"));
-            addInternalValueParameters(method, specialization.getNode().getGenericSpecialization(), true);
-            clazz.add(method);
-
-            CodeTreeBuilder builder = method.createBuilder();
-
-            builder.tree(createDeoptimize(builder));
-            emitSpecializationListeners(builder, specialization.getNode());
-
-            builder.startStatement();
-            builder.startCall("replace");
-            builder.startCall(factoryClassName(specialization.getNode()), "specialize").string("this").string("minimumState");
-            addInternalValueParameterNames(builder, specialization.getNode().getGenericSpecialization(), specialization.getNode().getGenericSpecialization(), null, true, true);
-            builder.end();
-            builder.end(); // call replace
-            builder.end(); // statement
-
-            String generatedMethodName;
-            if (specialization.getNode().getGenericSpecialization().isUseSpecializationsForGeneric()) {
-                generatedMethodName = generatedGenericMethodName(null);
-            } else {
-                generatedMethodName = generatedGenericMethodName(specialization.findNextSpecialization());
-            }
-            ExecutableElement generatedGeneric = clazz.getEnclosingClass().getMethod(generatedMethodName);
-
-            CodeTreeBuilder genericExecute = CodeTreeBuilder.createBuilder();
-            genericExecute.startCall(factoryClassName(specialization.getNode()), generatedMethodName);
-            genericExecute.string("this");
-            addInternalValueParameterNames(genericExecute, specialization.getNode().getGenericSpecialization(), specialization.getNode().getGenericSpecialization(), null, true, true);
-            genericExecute.end(); // call generated generic
-
-            CodeTree genericInvocation = genericExecute.getRoot();
-
-            if (generatedGeneric != null && Utils.isVoid(generatedGeneric.getReturnType())) {
-                builder.statement(genericInvocation);
-
-                if (!Utils.isVoid(builder.findMethod().asType())) {
-                    builder.startReturn().defaultValue(returnType.getPrimitiveType()).end();
-                }
-            } else {
-                builder.startReturn().tree(genericInvocation).end();
-            }
-        }
-
     }
 
 }
--- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/AbstractTest.java	Mon May 13 16:46:39 2013 +0200
+++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/AbstractTest.java	Mon May 13 17:11:31 2013 +0200
@@ -49,7 +49,7 @@
         return result.toString();
     }
 
-    protected void executeSL(String[] input, String[] expectedOutput, boolean useConsole) {
+    protected static void executeSL(String[] input, String[] expectedOutput, boolean useConsole) {
         InputStream in = new ByteArrayInputStream(concat(input).getBytes());
 
         ByteArrayOutputStream out = new ByteArrayOutputStream();
--- a/make/bsd/makefiles/buildtree.make	Mon May 13 16:46:39 2013 +0200
+++ b/make/bsd/makefiles/buildtree.make	Mon May 13 17:11:31 2013 +0200
@@ -243,7 +243,9 @@
 	echo "$(call gamma-path,altsrc,os/$(OS_FAMILY)/vm) \\"; \
 	echo "$(call gamma-path,commonsrc,os/$(OS_FAMILY)/vm) \\"; \
 	echo "$(call gamma-path,altsrc,os/posix/vm) \\"; \
-	echo "$(call gamma-path,commonsrc,os/posix/vm)"; \
+	echo "$(call gamma-path,commonsrc,os/posix/vm) \\"; \
+	echo "$(call gamma-path,altsrc,gpu/ptx) \\"; \
+	echo "$(call gamma-path,commonsrc,gpu/ptx)"; \
 	echo; \
 	echo "Src_Dirs_I = \\"; \
 	echo "$(call gamma-path,altsrc,share/vm/prims) \\"; \
@@ -259,7 +261,9 @@
 	echo "$(call gamma-path,altsrc,os/$(OS_FAMILY)/vm) \\"; \
 	echo "$(call gamma-path,commonsrc,os/$(OS_FAMILY)/vm) \\"; \
 	echo "$(call gamma-path,altsrc,os/posix/vm) \\"; \
-	echo "$(call gamma-path,commonsrc,os/posix/vm)"; \
+	echo "$(call gamma-path,commonsrc,os/posix/vm) \\"; \
+	echo "$(call gamma-path,altsrc,gpu) \\"; \
+	echo "$(call gamma-path,commonsrc,gpu)"; \
 	[ -n "$(CFLAGS_BROWSE)" ] && \
 	    echo && echo "CFLAGS_BROWSE = $(CFLAGS_BROWSE)"; \
 	[ -n "$(HOTSPOT_EXTRA_SYSDEFS)" ] && \
--- a/make/bsd/makefiles/launcher.make	Mon May 13 16:46:39 2013 +0200
+++ b/make/bsd/makefiles/launcher.make	Mon May 13 17:11:31 2013 +0200
@@ -67,7 +67,7 @@
   # framework libraries.
 
   ifeq ($(OS_VENDOR),Darwin)
-    LFLAGS_LAUNCHER         += -framework CoreFoundation
+    LFLAGS_LAUNCHER         += -framework CoreFoundation -framework ApplicationServices
   endif
 
   LIBS_LAUNCHER             += -l$(JVM) $(LIBS)
--- a/make/bsd/makefiles/vm.make	Mon May 13 16:46:39 2013 +0200
+++ b/make/bsd/makefiles/vm.make	Mon May 13 17:11:31 2013 +0200
@@ -128,6 +128,10 @@
 
 LIBS += -lm -pthread
 
+ifeq ($(OS_VENDOR),Darwin)
+  LIBS         += -framework ApplicationServices -framework IOKit
+endif
+
 # By default, link the *.o into the library, not the executable.
 LINK_INTO$(LINK_INTO) = LIBJVM
 
@@ -157,6 +161,7 @@
 SOURCE_PATHS+=$(HS_COMMON_SRC)/os/posix/vm
 SOURCE_PATHS+=$(HS_COMMON_SRC)/cpu/$(Platform_arch)/vm
 SOURCE_PATHS+=$(HS_COMMON_SRC)/os_cpu/$(Platform_os_arch)/vm
+SOURCE_PATHS+=$(HS_COMMON_SRC)/gpu/ptx
 
 ifndef JAVASE_EMBEDDED
 SOURCE_PATHS+=$(shell if [ -d $(HS_ALT_SRC)/share/vm/jfr ]; then \
@@ -179,7 +184,9 @@
 SHARK_PATHS := $(GAMMADIR)/src/share/vm/shark
 
 GRAAL_PATHS += $(call altsrc,$(HS_COMMON_SRC)/share/vm/graal)
+GRAAL_PATHS += $(call altsrc,$(HS_COMMON_SRC)/gpu/ptx)
 GRAAL_PATHS += $(HS_COMMON_SRC)/share/vm/graal
+GRAAL_PATHS += $(HS_COMMON_SRC)/gpu/ptx
 
 # Include dirs per type.
 Src_Dirs/CORE      := $(CORE_PATHS)
--- a/make/linux/makefiles/buildtree.make	Mon May 13 16:46:39 2013 +0200
+++ b/make/linux/makefiles/buildtree.make	Mon May 13 17:11:31 2013 +0200
@@ -238,7 +238,9 @@
 	echo "$(call gamma-path,altsrc,os/$(OS_FAMILY)/vm) \\"; \
 	echo "$(call gamma-path,commonsrc,os/$(OS_FAMILY)/vm) \\"; \
 	echo "$(call gamma-path,altsrc,os/posix/vm) \\"; \
-	echo "$(call gamma-path,commonsrc,os/posix/vm)"; \
+	echo "$(call gamma-path,commonsrc,os/posix/vm) \\"; \
+	echo "$(call gamma-path,altsrc,gpu/ptx) \\"; \
+	echo "$(call gamma-path,commonsrc,gpu/ptx)"; \
 	echo; \
 	echo "Src_Dirs_I = \\"; \
 	echo "$(call gamma-path,altsrc,share/vm/prims) \\"; \
@@ -253,8 +255,9 @@
 	echo "$(call gamma-path,commonsrc,os_cpu/$(OS_FAMILY)_$(SRCARCH)/vm) \\"; \
 	echo "$(call gamma-path,altsrc,os/$(OS_FAMILY)/vm) \\"; \
 	echo "$(call gamma-path,commonsrc,os/$(OS_FAMILY)/vm) \\"; \
-	echo "$(call gamma-path,altsrc,os/posix/vm) \\"; \
-	echo "$(call gamma-path,commonsrc,os/posix/vm)"; \
+	echo "$(call gamma-path,commonsrc,os/posix/vm) \\"; \
+	echo "$(call gamma-path,altsrc,gpu) \\"; \
+	echo "$(call gamma-path,commonsrc,gpu)"; \
 	[ -n "$(CFLAGS_BROWSE)" ] && \
 	    echo && echo "CFLAGS_BROWSE = $(CFLAGS_BROWSE)"; \
 	[ -n "$(ENABLE_FULL_DEBUG_SYMBOLS)" ] && \
--- a/make/linux/makefiles/vm.make	Mon May 13 16:46:39 2013 +0200
+++ b/make/linux/makefiles/vm.make	Mon May 13 17:11:31 2013 +0200
@@ -157,6 +157,7 @@
 SOURCE_PATHS+=$(HS_COMMON_SRC)/os/posix/vm
 SOURCE_PATHS+=$(HS_COMMON_SRC)/cpu/$(Platform_arch)/vm
 SOURCE_PATHS+=$(HS_COMMON_SRC)/os_cpu/$(Platform_os_arch)/vm
+SOURCE_PATHS+=$(HS_COMMON_SRC)/gpu/ptx
 
 ifndef JAVASE_EMBEDDED 
 ifneq (${ARCH},arm)
@@ -181,7 +182,9 @@
 SHARK_PATHS := $(GAMMADIR)/src/share/vm/shark
 
 GRAAL_PATHS += $(call altsrc,$(HS_COMMON_SRC)/share/vm/graal)
+GRAAL_PATHS += $(call altsrc,$(HS_COMMON_SRC)/gpu/ptx)
 GRAAL_PATHS += $(HS_COMMON_SRC)/share/vm/graal
+GRAAL_PATHS += $(HS_COMMON_SRC)/gpu/ptx
 
 # Include dirs per type.
 Src_Dirs/CORE      := $(CORE_PATHS)
--- a/make/windows/makefiles/projectcreator.make	Mon May 13 16:46:39 2013 +0200
+++ b/make/windows/makefiles/projectcreator.make	Mon May 13 17:11:31 2013 +0200
@@ -55,6 +55,7 @@
         -relativeInclude src\os\windows\vm \
         -relativeInclude src\os_cpu\windows_$(Platform_arch)\vm \
         -relativeInclude src\cpu\$(Platform_arch)\vm \
+        -relativeInclude src\gpu \
         -absoluteInclude $(HOTSPOTBUILDSPACE)/%f/generated \
         -relativeSrcInclude src \
         -absoluteSrcInclude $(HOTSPOTBUILDSPACE) \
--- a/mx/JUnitWrapper.java	Mon May 13 16:46:39 2013 +0200
+++ b/mx/JUnitWrapper.java	Mon May 13 17:11:31 2013 +0200
@@ -67,7 +67,11 @@
         }
 
         String[] strargs = tests.toArray(new String[tests.size()]);
-        System.out.printf("executing junit tests now... (%d test classes)\n", strargs.length);
+        if (strargs.length == 1) {
+            System.out.printf("executing junit test now... (%s)\n", strargs[0]);
+        } else {
+            System.out.printf("executing junit tests now... (%d test classes)\n", strargs.length);
+        }
         JUnitCore.main(strargs);
     }
 }
--- a/mx/commands.py	Mon May 13 16:46:39 2013 +0200
+++ b/mx/commands.py	Mon May 13 17:11:31 2013 +0200
@@ -749,7 +749,7 @@
             excludes += _find_classes_with_annotations(p, None, ['@Snippet', '@ClassSubstitution', '@Test'], includeInnerClasses=True).keys()
             excludes += p.find_classes_with_matching_source_line(None, lambda line: 'JaCoCo Exclude' in line, includeInnerClasses=True).keys()
             
-        includes = ['com.oracle.graal.*', 'com.oracle.max.*']
+        includes = ['com.oracle.graal.*']
         agentOptions = {
                         'append' : 'true' if _jacoco == 'append' else 'false',
                         'bootclasspath' : 'true',
@@ -788,6 +788,8 @@
 
     classes = []
     for p in mx.projects():
+        if mx.java().javaCompliance < p.javaCompliance:
+            continue
         classes += _find_classes_with_annotations(p, None, annotations).keys()
 
         if len(pos) != 0:
@@ -795,7 +797,7 @@
         if len(neg) != 0:
             classes = [c for c in classes if not containsAny(c, neg)]
 
-    projectscp = mx.classpath([pcp.name for pcp in mx.projects()])
+    projectscp = mx.classpath([pcp.name for pcp in mx.projects() if pcp.javaCompliance <= mx.java().javaCompliance])
 
     if len(classes) != 0:
         f_testfile = open(testfile, 'w')
@@ -829,30 +831,47 @@
         if os.environ.get('MX_TESTFILE') is None:
             os.remove(testfile)
 
-def unittest(args):
-    """run the JUnit tests (all testcases)
+_unittestHelpSuffix = """
 
     If filters are supplied, only tests whose fully qualified name
-    include a filter as a substring are run. Negative filters are
-    those with a '-' prefix. VM args should have a @ prefix."""
+    includes a filter as a substring are run. Negative filters are
+    those with a '-' prefix.
+    
+    Options with a '@' prefix are passed to the VM.
+    
+    For example, this command line:
+    
+       mx unittest BC_aload @-G:Dump= @-G:MethodFilter=BC_aload.* @-G:+PrintCFG
+    
+    will run all JUnit test classes that contain 'BC_aload' in their
+    fully qualified name and will pass these options to the VM: 
+    
+        -G:Dump= -G:MethodFilter=BC_aload.* -G:+PrintCFG
+
+    To get around command line length limitations on some OSes, the
+    JUnit class names to be executed are written to a file that a
+    custom JUnit wrapper reads and passes onto JUnit proper. The
+    MX_TESTFILE environment variable can be set to specify a
+    file which will not be deleted once the unittests are done
+    (unlike the temporary file otherwise used).
+
+    As with all other commands, using the global '-v' before 'unittest'
+    command will cause mx to show the complete shell command line
+    it uses to run the VM.
+""" 
+
+def unittest(args):
+    """run the JUnit tests (all testcases){0}"""
 
     _unittest(args, ['@Test', '@LongTest'])
 
 def shortunittest(args):
-    """run the JUnit tests (short testcases only)
-
-    If filters are supplied, only tests whose fully qualified name
-    include a filter as a substring are run. Negative filters are
-    those with a '-' prefix. VM args should have a @ prefix."""
+    """run the JUnit tests (short testcases only){0}"""
 
     _unittest(args, ['@Test'])
 
 def longunittest(args):
-    """run the JUnit tests (long testcases only)
-
-    If filters are supplied, only tests whose fully qualified name
-    include a filter as a substring are run. Negative filters are
-    those with a '-' prefix. VM args should have a @ prefix."""
+    """run the JUnit tests (long testcases only){0}"""
 
     _unittest(args, ['@LongTest'])
 
@@ -1341,9 +1360,9 @@
         'gate' : [gate, '[-options]'],
         'gv' : [gv, ''],
         'bench' : [bench, '[-resultfile file] [all(default)|dacapo|specjvm2008|bootstrap]'],
-        'unittest' : [unittest, '[filters...]'],
-        'longunittest' : [longunittest, '[filters...]'],
-        'shortunittest' : [shortunittest, '[filters...]'],
+        'unittest' : [unittest, '[filters...|@VM options]', _unittestHelpSuffix],
+        'longunittest' : [longunittest, '[filters...|@VM options]', _unittestHelpSuffix],
+        'shortunittest' : [shortunittest, '[filters...|@VM options]', _unittestHelpSuffix],
         'jacocoreport' : [jacocoreport, '[output directory]'],
         'site' : [site, '[-options]'],
         'vm': [vm, '[-options] class [args...]'],
--- a/mx/projects	Mon May 13 16:46:39 2013 +0200
+++ b/mx/projects	Mon May 13 17:11:31 2013 +0200
@@ -295,7 +295,7 @@
 # graal.compiler.ptx
 project@com.oracle.graal.compiler.ptx@subDir=graal
 project@com.oracle.graal.compiler.ptx@sourceDirs=src
-project@com.oracle.graal.compiler.ptx@dependencies=com.oracle.graal.compiler,com.oracle.graal.lir.ptx
+project@com.oracle.graal.compiler.ptx@dependencies=com.oracle.graal.lir.ptx,com.oracle.graal.hotspot
 project@com.oracle.graal.compiler.ptx@checkstyle=com.oracle.graal.graph
 project@com.oracle.graal.compiler.ptx@javaCompliance=1.7
 
--- a/mx/sanitycheck.py	Mon May 13 16:46:39 2013 +0200
+++ b/mx/sanitycheck.py	Mon May 13 17:11:31 2013 +0200
@@ -47,7 +47,8 @@
 }
 
 dacapoScalaSanityWarmup = {
-    'actors':     [0, 0, 2,  8, 10],
+# (tw) actors sometimes fails verification; hardly reproducible
+    'actors':     [0, 0, 0,  0,  0],
 # (lstadler) apparat was disabled due to a deadlock which I think is the benchmarks fault.
     'apparat':    [0, 0, 0,  0,  0],
     'factorie':   [0, 0, 2,  5,  5],
--- a/src/cpu/x86/vm/graalRuntime_x86.cpp	Mon May 13 16:46:39 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1177 +0,0 @@
-/*
- * Copyright (c) 1999, 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.
- *
- */
-
-#include "precompiled.hpp"
-#include "asm/assembler.hpp"
-#include "graal/graalRuntime.hpp"
-#include "interpreter/interpreter.hpp"
-#include "nativeInst_x86.hpp"
-#include "oops/compiledICHolder.hpp"
-#include "oops/oop.inline.hpp"
-#include "prims/jvmtiExport.hpp"
-#include "register_x86.hpp"
-#include "runtime/sharedRuntime.hpp"
-#include "runtime/signature.hpp"
-#include "runtime/vframeArray.hpp"
-#include "vmreg_x86.inline.hpp"
-
-static void restore_live_registers(GraalStubAssembler* sasm, bool restore_fpu_registers = true);
-
-// Implementation of GraalStubAssembler
-
-int GraalStubAssembler::call_RT(Register oop_result1, Register metadata_result, address entry, int args_size) {
-  // setup registers
-  const Register thread = NOT_LP64(rdi) LP64_ONLY(r15_thread); // is callee-saved register (Visual C++ calling conventions)
-  assert(!(oop_result1->is_valid() || metadata_result->is_valid()) || oop_result1 != metadata_result, "registers must be different");
-  assert(oop_result1 != thread && metadata_result != thread, "registers must be different");
-  assert(args_size >= 0, "illegal args_size");
-
-#ifdef _LP64
-  mov(c_rarg0, thread);
-  set_num_rt_args(0); // Nothing on stack
-#else
-  set_num_rt_args(1 + args_size);
-
-  // push java thread (becomes first argument of C function)
-  get_thread(thread);
-  push(thread);
-#endif // _LP64
-
-  int call_offset;
-  set_last_Java_frame(thread, rsp, noreg, NULL);
-
-  // do the call
-  call(RuntimeAddress(entry));
-  call_offset = offset();
-  // verify callee-saved register
-#ifdef ASSERT
-  guarantee(thread != rax, "change this code");
-  push(rax);
-  { Label L;
-    get_thread(rax);
-    cmpptr(thread, rax);
-    jcc(Assembler::equal, L);
-    int3();
-    stop("GraalStubAssembler::call_RT: rdi not callee saved?");
-    bind(L);
-  }
-  pop(rax);
-#endif
-  reset_last_Java_frame(thread, true, false);
-
-  // discard thread and arguments
-  NOT_LP64(addptr(rsp, num_rt_args()*BytesPerWord));
-
-  // check for pending exceptions
-  { Label L;
-    cmpptr(Address(thread, Thread::pending_exception_offset()), (int32_t)NULL_WORD);
-    jcc(Assembler::equal, L);
-    // exception pending => remove activation and forward to exception handler
-    movptr(rax, Address(thread, Thread::pending_exception_offset()));
-    // make sure that the vm_results are cleared
-    if (oop_result1->is_valid()) {
-      movptr(Address(thread, JavaThread::vm_result_offset()), NULL_WORD);
-    }
-    if (metadata_result->is_valid()) {
-      movptr(Address(thread, JavaThread::vm_result_2_offset()), NULL_WORD);
-    }
-    // (thomaswue) Deoptimize in case of an exception.
-    restore_live_registers(this, false);
-    movptr(Address(thread, Thread::pending_exception_offset()), NULL_WORD);
-    leave();
-    movl(Address(thread, ThreadShadow::pending_deoptimization_offset()), Deoptimization::make_trap_request(Deoptimization::Reason_constraint, Deoptimization::Action_reinterpret));
-    jump(RuntimeAddress(SharedRuntime::deopt_blob()->uncommon_trap()));
-    bind(L);
-  }
-  // get oop results if there are any and reset the values in the thread
-  if (oop_result1->is_valid()) {
-    get_vm_result(oop_result1, thread);
-  }
-  if (metadata_result->is_valid()) {
-    get_vm_result_2(metadata_result, thread);
-  }
-  return call_offset;
-}
-
-
-int GraalStubAssembler::call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1) {
-#ifdef _LP64
-  mov(c_rarg1, arg1);
-#else
-  push(arg1);
-#endif // _LP64
-  return call_RT(oop_result1, metadata_result, entry, 1);
-}
-
-
-int GraalStubAssembler::call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1, Register arg2) {
-#ifdef _LP64
-  if (c_rarg1 == arg2) {
-    if (c_rarg2 == arg1) {
-      xchgq(arg1, arg2);
-    } else {
-      mov(c_rarg2, arg2);
-      mov(c_rarg1, arg1);
-    }
-  } else {
-    mov(c_rarg1, arg1);
-    mov(c_rarg2, arg2);
-  }
-#else
-  push(arg2);
-  push(arg1);
-#endif // _LP64
-  return call_RT(oop_result1, metadata_result, entry, 2);
-}
-
-
-int GraalStubAssembler::call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1, Register arg2, Register arg3) {
-#ifdef _LP64
-  // if there is any conflict use the stack
-  if (arg1 == c_rarg2 || arg1 == c_rarg3 ||
-      arg2 == c_rarg1 || arg1 == c_rarg3 ||
-      arg3 == c_rarg1 || arg1 == c_rarg2) {
-    push(arg3);
-    push(arg2);
-    push(arg1);
-    pop(c_rarg1);
-    pop(c_rarg2);
-    pop(c_rarg3);
-  } else {
-    mov(c_rarg1, arg1);
-    mov(c_rarg2, arg2);
-    mov(c_rarg3, arg3);
-  }
-#else
-  push(arg3);
-  push(arg2);
-  push(arg1);
-#endif // _LP64
-  return call_RT(oop_result1, metadata_result, entry, 3);
-}
-
-int GraalStubAssembler::call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1, Register arg2, Register arg3, Register arg4) {
-#ifdef _LP64
-  #ifdef _WIN64
-    // on windows we only have the registers c_rarg0 to c_rarg3 for transferring parameters -> remaining parameters are on the stack
-    if (arg1 == c_rarg2 || arg1 == c_rarg3 || 
-        arg2 == c_rarg1 || arg2 == c_rarg3 || 
-        arg3 == c_rarg1 || arg3 == c_rarg2 || 
-        arg4 == c_rarg1 || arg4 == c_rarg2) {
-      push(arg4);
-      push(arg3);
-      push(arg2);
-      push(arg1);
-      pop(c_rarg1);
-      pop(c_rarg2);
-      pop(c_rarg3);
-    } else {
-      mov(c_rarg1, arg1);
-      mov(c_rarg2, arg2);
-      mov(c_rarg3, arg3);
-      push(arg4);
-    }
-  #else
-    // if there is any conflict use the stack
-    if (arg1 == c_rarg2 || arg1 == c_rarg3 || arg1 == c_rarg4 ||
-        arg2 == c_rarg1 || arg2 == c_rarg3 || arg2 == c_rarg4 ||
-        arg3 == c_rarg1 || arg3 == c_rarg2 || arg3 == c_rarg4 ||
-        arg4 == c_rarg1 || arg4 == c_rarg2 || arg4 == c_rarg3) {
-      push(arg4);
-      push(arg3);
-      push(arg2);
-      push(arg1);
-      pop(c_rarg1);
-      pop(c_rarg2);
-      pop(c_rarg3);
-      pop(c_rarg4);
-    } else {
-      mov(c_rarg1, arg1);
-      mov(c_rarg2, arg2);
-      mov(c_rarg3, arg3);
-      mov(c_rarg4, arg4);
-    }
-  #endif
-#else
-  push(arg4);
-  push(arg3);
-  push(arg2);
-  push(arg1);
-#endif // _LP64
-  return call_RT(oop_result1, metadata_result, entry, 4);
-}
-
-// Implementation of GraalStubFrame
-
-class GraalStubFrame: public StackObj {
- private:
-  GraalStubAssembler* _sasm;
-
- public:
-  GraalStubFrame(GraalStubAssembler* sasm, const char* name, bool must_gc_arguments);
-  ~GraalStubFrame();
-};
-
-
-#define __ _sasm->
-
-GraalStubFrame::GraalStubFrame(GraalStubAssembler* sasm, const char* name, bool must_gc_arguments) {
-  _sasm = sasm;
-  __ set_info(name, must_gc_arguments);
-  __ enter();
-}
-
-GraalStubFrame::~GraalStubFrame() {
-  __ leave();
-  __ ret(0);
-}
-
-#undef __
-
-
-// Implementation of GraalRuntime
-
-const int float_regs_as_doubles_size_in_slots = FloatRegisterImpl::number_of_registers * 2;
-const int xmm_regs_as_doubles_size_in_slots = XMMRegisterImpl::number_of_registers * 2;
-
-// Stack layout for saving/restoring  all the registers needed during a runtime
-// call (this includes deoptimization)
-// Note: note that users of this frame may well have arguments to some runtime
-// while these values are on the stack. These positions neglect those arguments
-// but the code in save_live_registers will take the argument count into
-// account.
-//
-#ifdef _LP64
-  #define SLOT2(x) x,
-  #define SLOT_PER_WORD 2
-#else
-  #define SLOT2(x)
-  #define SLOT_PER_WORD 1
-#endif // _LP64
-
-enum reg_save_layout {
-  // 64bit needs to keep stack 16 byte aligned. So we add some alignment dummies to make that
-  // happen and will assert if the stack size we create is misaligned
-#ifdef _LP64
-  align_dummy_0, align_dummy_1,
-#endif // _LP64
-#ifdef _WIN64
-  // Windows always allocates space for it's argument registers (see
-  // frame::arg_reg_save_area_bytes).
-  arg_reg_save_1, arg_reg_save_1H,                                                          // 0, 4
-  arg_reg_save_2, arg_reg_save_2H,                                                          // 8, 12
-  arg_reg_save_3, arg_reg_save_3H,                                                          // 16, 20
-  arg_reg_save_4, arg_reg_save_4H,                                                          // 24, 28
-#endif // _WIN64
-  xmm_regs_as_doubles_off,                                                                  // 32
-  float_regs_as_doubles_off = xmm_regs_as_doubles_off + xmm_regs_as_doubles_size_in_slots,  // 160
-  fpu_state_off = float_regs_as_doubles_off + float_regs_as_doubles_size_in_slots,          // 224
-  // fpu_state_end_off is exclusive
-  fpu_state_end_off = fpu_state_off + (FPUStateSizeInWords / SLOT_PER_WORD),                // 352
-  marker = fpu_state_end_off, SLOT2(markerH)                                                // 352, 356
-  extra_space_offset,                                                                       // 360
-#ifdef _LP64
-  r15_off = extra_space_offset, r15H_off,                                                   // 360, 364
-  r14_off, r14H_off,                                                                        // 368, 372
-  r13_off, r13H_off,                                                                        // 376, 380
-  r12_off, r12H_off,                                                                        // 384, 388
-  r11_off, r11H_off,                                                                        // 392, 396
-  r10_off, r10H_off,                                                                        // 400, 404
-  r9_off, r9H_off,                                                                          // 408, 412
-  r8_off, r8H_off,                                                                          // 416, 420
-  rdi_off, rdiH_off,                                                                        // 424, 428
-#else
-  rdi_off = extra_space_offset,
-#endif // _LP64
-  rsi_off, SLOT2(rsiH_off)                                                                  // 432, 436
-  rbp_off, SLOT2(rbpH_off)                                                                  // 440, 444
-  rsp_off, SLOT2(rspH_off)                                                                  // 448, 452
-  rbx_off, SLOT2(rbxH_off)                                                                  // 456, 460
-  rdx_off, SLOT2(rdxH_off)                                                                  // 464, 468
-  rcx_off, SLOT2(rcxH_off)                                                                  // 472, 476
-  rax_off, SLOT2(raxH_off)                                                                  // 480, 484
-  saved_rbp_off, SLOT2(saved_rbpH_off)                                                      // 488, 492
-  return_off, SLOT2(returnH_off)                                                            // 496, 500
-  reg_save_frame_size   // As noted: neglects any parameters to runtime                     // 504
-};
-
-// Save registers which might be killed by calls into the runtime.
-// Tries to smart about FP registers.  In particular we separate
-// saving and describing the FPU registers for deoptimization since we
-// have to save the FPU registers twice if we describe them and on P4
-// saving FPU registers which don't contain anything appears
-// expensive.  The deopt blob is the only thing which needs to
-// describe FPU registers.  In all other cases it should be sufficient
-// to simply save their current value.
-
-static OopMap* generate_oop_map(GraalStubAssembler* sasm, int num_rt_args,
-                                bool save_fpu_registers = true) {
-
-  // In 64bit all the args are in regs so there are no additional stack slots
-  LP64_ONLY(num_rt_args = 0);
-  LP64_ONLY(assert((reg_save_frame_size * VMRegImpl::stack_slot_size) % 16 == 0, "must be 16 byte aligned");)
-  int frame_size_in_slots = reg_save_frame_size + num_rt_args; // args + thread
-  sasm->set_frame_size(frame_size_in_slots / VMRegImpl::slots_per_word );
-
-  // record saved value locations in an OopMap
-  // locations are offsets from sp after runtime call; num_rt_args is number of arguments in call, including thread
-  OopMap* map = new OopMap(frame_size_in_slots, 0);
-  map->set_callee_saved(VMRegImpl::stack2reg(rax_off + num_rt_args), rax->as_VMReg());
-  map->set_callee_saved(VMRegImpl::stack2reg(rcx_off + num_rt_args), rcx->as_VMReg());
-  map->set_callee_saved(VMRegImpl::stack2reg(rdx_off + num_rt_args), rdx->as_VMReg());
-  map->set_callee_saved(VMRegImpl::stack2reg(rbx_off + num_rt_args), rbx->as_VMReg());
-  map->set_callee_saved(VMRegImpl::stack2reg(rbp_off + num_rt_args), rbp->as_VMReg());
-  map->set_callee_saved(VMRegImpl::stack2reg(rsi_off + num_rt_args), rsi->as_VMReg());
-  map->set_callee_saved(VMRegImpl::stack2reg(rdi_off + num_rt_args), rdi->as_VMReg());
-#ifdef _LP64
-  map->set_callee_saved(VMRegImpl::stack2reg(r8_off + num_rt_args),  r8->as_VMReg());
-  map->set_callee_saved(VMRegImpl::stack2reg(r9_off + num_rt_args),  r9->as_VMReg());
-  map->set_callee_saved(VMRegImpl::stack2reg(r10_off + num_rt_args), r10->as_VMReg());
-  map->set_callee_saved(VMRegImpl::stack2reg(r11_off + num_rt_args), r11->as_VMReg());
-  map->set_callee_saved(VMRegImpl::stack2reg(r12_off + num_rt_args), r12->as_VMReg());
-  map->set_callee_saved(VMRegImpl::stack2reg(r13_off + num_rt_args), r13->as_VMReg());
-  map->set_callee_saved(VMRegImpl::stack2reg(r14_off + num_rt_args), r14->as_VMReg());
-  map->set_callee_saved(VMRegImpl::stack2reg(r15_off + num_rt_args), r15->as_VMReg());
-
-  // This is stupid but needed.
-  map->set_callee_saved(VMRegImpl::stack2reg(raxH_off + num_rt_args), rax->as_VMReg()->next());
-  map->set_callee_saved(VMRegImpl::stack2reg(rcxH_off + num_rt_args), rcx->as_VMReg()->next());
-  map->set_callee_saved(VMRegImpl::stack2reg(rdxH_off + num_rt_args), rdx->as_VMReg()->next());
-  map->set_callee_saved(VMRegImpl::stack2reg(rbxH_off + num_rt_args), rbx->as_VMReg()->next());
-  map->set_callee_saved(VMRegImpl::stack2reg(rbpH_off + num_rt_args), rbp->as_VMReg()->next());
-  map->set_callee_saved(VMRegImpl::stack2reg(rsiH_off + num_rt_args), rsi->as_VMReg()->next());
-  map->set_callee_saved(VMRegImpl::stack2reg(rdiH_off + num_rt_args), rdi->as_VMReg()->next());
-
-  map->set_callee_saved(VMRegImpl::stack2reg(r8H_off + num_rt_args),  r8->as_VMReg()->next());
-  map->set_callee_saved(VMRegImpl::stack2reg(r9H_off + num_rt_args),  r9->as_VMReg()->next());
-  map->set_callee_saved(VMRegImpl::stack2reg(r10H_off + num_rt_args), r10->as_VMReg()->next());
-  map->set_callee_saved(VMRegImpl::stack2reg(r11H_off + num_rt_args), r11->as_VMReg()->next());
-  map->set_callee_saved(VMRegImpl::stack2reg(r12H_off + num_rt_args), r12->as_VMReg()->next());
-  map->set_callee_saved(VMRegImpl::stack2reg(r13H_off + num_rt_args), r13->as_VMReg()->next());
-  map->set_callee_saved(VMRegImpl::stack2reg(r14H_off + num_rt_args), r14->as_VMReg()->next());
-  map->set_callee_saved(VMRegImpl::stack2reg(r15H_off + num_rt_args), r15->as_VMReg()->next());
-#endif // _LP64
-
-  if (save_fpu_registers) {
-    if (UseSSE < 2) {
-      int fpu_off = float_regs_as_doubles_off;
-      for (int n = 0; n < FloatRegisterImpl::number_of_registers; n++) {
-        VMReg fpu_name_0 = as_FloatRegister(n)->as_VMReg();
-        map->set_callee_saved(VMRegImpl::stack2reg(fpu_off +     num_rt_args), fpu_name_0);
-        // %%% This is really a waste but we'll keep things as they were for now
-        if (true) {
-          map->set_callee_saved(VMRegImpl::stack2reg(fpu_off + 1 + num_rt_args), fpu_name_0->next());
-        }
-        fpu_off += 2;
-      }
-      assert(fpu_off == fpu_state_off, "incorrect number of fpu stack slots");
-    }
-
-    if (UseSSE >= 2) {
-      int xmm_off = xmm_regs_as_doubles_off;
-      for (int n = 0; n < XMMRegisterImpl::number_of_registers; n++) {
-        VMReg xmm_name_0 = as_XMMRegister(n)->as_VMReg();
-        map->set_callee_saved(VMRegImpl::stack2reg(xmm_off +     num_rt_args), xmm_name_0);
-        // %%% This is really a waste but we'll keep things as they were for now
-        if (true) {
-          map->set_callee_saved(VMRegImpl::stack2reg(xmm_off + 1 + num_rt_args), xmm_name_0->next());
-        }
-        xmm_off += 2;
-      }
-      assert(xmm_off == float_regs_as_doubles_off, "incorrect number of xmm registers");
-
-    } else if (UseSSE == 1) {
-      int xmm_off = xmm_regs_as_doubles_off;
-      for (int n = 0; n < XMMRegisterImpl::number_of_registers; n++) {
-        VMReg xmm_name_0 = as_XMMRegister(n)->as_VMReg();
-        map->set_callee_saved(VMRegImpl::stack2reg(xmm_off +     num_rt_args), xmm_name_0);
-        xmm_off += 2;
-      }
-      assert(xmm_off == float_regs_as_doubles_off, "incorrect number of xmm registers");
-    }
-  }
-
-  return map;
-}
-
-#define __ sasm->
-
-static OopMap* save_live_registers(GraalStubAssembler* sasm, int num_rt_args,
-                                   bool save_fpu_registers = true) {
-  __ block_comment("save_live_registers");
-
-  __ pusha();         // integer registers
-
-  // assert(float_regs_as_doubles_off % 2 == 0, "misaligned offset");
-  // assert(xmm_regs_as_doubles_off % 2 == 0, "misaligned offset");
-
-  __ subptr(rsp, extra_space_offset * VMRegImpl::stack_slot_size);
-
-#ifdef ASSERT
-  __ movptr(Address(rsp, marker * VMRegImpl::stack_slot_size), (int32_t)0xfeedbeef);
-#endif
-
-  if (save_fpu_registers) {
-    if (UseSSE < 2) {
-      // save FPU stack
-      __ fnsave(Address(rsp, fpu_state_off * VMRegImpl::stack_slot_size));
-      __ fwait();
-
-#ifdef ASSERT
-      Label ok;
-      __ cmpw(Address(rsp, fpu_state_off * VMRegImpl::stack_slot_size), StubRoutines::fpu_cntrl_wrd_std());
-      __ jccb(Assembler::equal, ok);
-      __ stop("corrupted control word detected");
-      __ bind(ok);
-#endif
-
-      // Reset the control word to guard against exceptions being unmasked
-      // since fstp_d can cause FPU stack underflow exceptions.  Write it
-      // into the on stack copy and then reload that to make sure that the
-      // current and future values are correct.
-      __ movw(Address(rsp, fpu_state_off * VMRegImpl::stack_slot_size), StubRoutines::fpu_cntrl_wrd_std());
-      __ frstor(Address(rsp, fpu_state_off * VMRegImpl::stack_slot_size));
-
-      // Save the FPU registers in de-opt-able form
-      __ fstp_d(Address(rsp, float_regs_as_doubles_off * VMRegImpl::stack_slot_size +  0));
-      __ fstp_d(Address(rsp, float_regs_as_doubles_off * VMRegImpl::stack_slot_size +  8));
-      __ fstp_d(Address(rsp, float_regs_as_doubles_off * VMRegImpl::stack_slot_size + 16));
-      __ fstp_d(Address(rsp, float_regs_as_doubles_off * VMRegImpl::stack_slot_size + 24));
-      __ fstp_d(Address(rsp, float_regs_as_doubles_off * VMRegImpl::stack_slot_size + 32));
-      __ fstp_d(Address(rsp, float_regs_as_doubles_off * VMRegImpl::stack_slot_size + 40));
-      __ fstp_d(Address(rsp, float_regs_as_doubles_off * VMRegImpl::stack_slot_size + 48));
-      __ fstp_d(Address(rsp, float_regs_as_doubles_off * VMRegImpl::stack_slot_size + 56));
-    }
-
-    if (UseSSE >= 2) {
-      // save XMM registers
-      // XMM registers can contain float or double values, but this is not known here,
-      // so always save them as doubles.
-      // note that float values are _not_ converted automatically, so for float values
-      // the second word contains only garbage data.
-      __ movdbl(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size +  0), xmm0);
-      __ movdbl(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size +  8), xmm1);
-      __ movdbl(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 16), xmm2);
-      __ movdbl(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 24), xmm3);
-      __ movdbl(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 32), xmm4);
-      __ movdbl(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 40), xmm5);
-      __ movdbl(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 48), xmm6);
-      __ movdbl(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 56), xmm7);
-#ifdef _LP64
-      __ movdbl(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 64), xmm8);
-      __ movdbl(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 72), xmm9);
-      __ movdbl(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 80), xmm10);
-      __ movdbl(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 88), xmm11);
-      __ movdbl(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 96), xmm12);
-      __ movdbl(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 104), xmm13);
-      __ movdbl(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 112), xmm14);
-      __ movdbl(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 120), xmm15);
-#endif // _LP64
-    } else if (UseSSE == 1) {
-      // save XMM registers as float because double not supported without SSE2
-      __ movflt(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size +  0), xmm0);
-      __ movflt(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size +  8), xmm1);
-      __ movflt(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 16), xmm2);
-      __ movflt(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 24), xmm3);
-      __ movflt(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 32), xmm4);
-      __ movflt(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 40), xmm5);
-      __ movflt(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 48), xmm6);
-      __ movflt(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 56), xmm7);
-    }
-  }
-
-  // FPU stack must be empty now
-  __ verify_FPU(0, "save_live_registers");
-
-  return generate_oop_map(sasm, num_rt_args, save_fpu_registers);
-}
-
-
-static void restore_fpu(GraalStubAssembler* sasm, bool restore_fpu_registers = true) {
-  if (restore_fpu_registers) {
-    if (UseSSE >= 2) {
-      // restore XMM registers
-      __ movdbl(xmm0, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size +  0));
-      __ movdbl(xmm1, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size +  8));
-      __ movdbl(xmm2, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 16));
-      __ movdbl(xmm3, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 24));
-      __ movdbl(xmm4, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 32));
-      __ movdbl(xmm5, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 40));
-      __ movdbl(xmm6, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 48));
-      __ movdbl(xmm7, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 56));
-#ifdef _LP64
-      __ movdbl(xmm8, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 64));
-      __ movdbl(xmm9, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 72));
-      __ movdbl(xmm10, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 80));
-      __ movdbl(xmm11, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 88));
-      __ movdbl(xmm12, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 96));
-      __ movdbl(xmm13, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 104));
-      __ movdbl(xmm14, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 112));
-      __ movdbl(xmm15, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 120));
-#endif // _LP64
-    } else if (UseSSE == 1) {
-      // restore XMM registers
-      __ movflt(xmm0, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size +  0));
-      __ movflt(xmm1, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size +  8));
-      __ movflt(xmm2, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 16));
-      __ movflt(xmm3, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 24));
-      __ movflt(xmm4, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 32));
-      __ movflt(xmm5, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 40));
-      __ movflt(xmm6, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 48));
-      __ movflt(xmm7, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 56));
-    }
-
-    if (UseSSE < 2) {
-      __ frstor(Address(rsp, fpu_state_off * VMRegImpl::stack_slot_size));
-    } else {
-      // check that FPU stack is really empty
-      __ verify_FPU(0, "restore_live_registers");
-    }
-
-  } else {
-    // check that FPU stack is really empty
-    __ verify_FPU(0, "restore_live_registers");
-  }
-
-#ifdef ASSERT
-  {
-    Label ok;
-    __ cmpptr(Address(rsp, marker * VMRegImpl::stack_slot_size), (int32_t)0xfeedbeef);
-    __ jcc(Assembler::equal, ok);
-    __ stop("bad offsets in frame");
-    __ bind(ok);
-  }
-#endif // ASSERT
-
-  __ addptr(rsp, extra_space_offset * VMRegImpl::stack_slot_size);
-}
-
-
-static void restore_live_registers(GraalStubAssembler* sasm, bool restore_fpu_registers/* = true*/) {
-  __ block_comment("restore_live_registers");
-
-  restore_fpu(sasm, restore_fpu_registers);
-  __ popa();
-}
-
-
-static void restore_live_registers_except_rax(GraalStubAssembler* sasm, bool restore_fpu_registers = true) {
-  __ block_comment("restore_live_registers_except_rax");
-
-  restore_fpu(sasm, restore_fpu_registers);
-
-#ifdef _LP64
-  __ movptr(r15, Address(rsp, 0));
-  __ movptr(r14, Address(rsp, wordSize));
-  __ movptr(r13, Address(rsp, 2 * wordSize));
-  __ movptr(r12, Address(rsp, 3 * wordSize));
-  __ movptr(r11, Address(rsp, 4 * wordSize));
-  __ movptr(r10, Address(rsp, 5 * wordSize));
-  __ movptr(r9,  Address(rsp, 6 * wordSize));
-  __ movptr(r8,  Address(rsp, 7 * wordSize));
-  __ movptr(rdi, Address(rsp, 8 * wordSize));
-  __ movptr(rsi, Address(rsp, 9 * wordSize));
-  __ movptr(rbp, Address(rsp, 10 * wordSize));
-  // skip rsp
-  __ movptr(rbx, Address(rsp, 12 * wordSize));
-  __ movptr(rdx, Address(rsp, 13 * wordSize));
-  __ movptr(rcx, Address(rsp, 14 * wordSize));
-
-  __ addptr(rsp, 16 * wordSize);
-#else
-
-  __ pop(rdi);
-  __ pop(rsi);
-  __ pop(rbp);
-  __ pop(rbx); // skip this value
-  __ pop(rbx);
-  __ pop(rdx);
-  __ pop(rcx);
-  __ addptr(rsp, BytesPerWord);
-#endif // _LP64
-}
-
-OopMapSet* GraalRuntime::generate_handle_exception(StubID id, GraalStubAssembler *sasm) {
-  __ block_comment("generate_handle_exception");
-
-  // incoming parameters
-  const Register exception_oop = rax;
-  const Register exception_pc  = rdx;
-  // other registers used in this stub
-  const Register thread = NOT_LP64(rdi) LP64_ONLY(r15_thread);
-
-  // Save registers, if required.
-  OopMapSet* oop_maps = new OopMapSet();
-  OopMap* oop_map = NULL;
-  switch (id) {
-    case handle_exception_nofpu_id:
-      // At this point all registers MAY be live.
-      oop_map = save_live_registers(sasm, 1 /*thread*/, id == handle_exception_nofpu_id);
-      break;
-    default:  ShouldNotReachHere();
-  }
-
-#ifdef TIERED
-  // C2 can leave the fpu stack dirty
-  if (UseSSE < 2) {
-    __ empty_FPU_stack();
-  }
-#endif // TIERED
-
-  // verify that only rax, and rdx is valid at this time
-#ifdef ASSERT
-  __ movptr(rbx, 0xDEAD);
-  __ movptr(rcx, 0xDEAD);
-  __ movptr(rsi, 0xDEAD);
-  __ movptr(rdi, 0xDEAD);
-#endif
-
-  // verify that rax, contains a valid exception
-  __ verify_not_null_oop(exception_oop);
-
-  // load address of JavaThread object for thread-local data
-  NOT_LP64(__ get_thread(thread);)
-
-#ifdef ASSERT
-  // check that fields in JavaThread for exception oop and issuing pc are
-  // empty before writing to them
-  Label oop_empty;
-  __ cmpptr(Address(thread, JavaThread::exception_oop_offset()), (int32_t) NULL_WORD);
-  __ jcc(Assembler::equal, oop_empty);
-  __ stop("exception oop already set");
-  __ bind(oop_empty);
-
-  Label pc_empty;
-  __ cmpptr(Address(thread, JavaThread::exception_pc_offset()), 0);
-  __ jcc(Assembler::equal, pc_empty);
-  __ stop("exception pc already set");
-  __ bind(pc_empty);
-#endif
-
-  // save exception oop and issuing pc into JavaThread
-  // (exception handler will load it from here)
-  __ movptr(Address(thread, JavaThread::exception_oop_offset()), exception_oop);
-  __ movptr(Address(thread, JavaThread::exception_pc_offset()),  exception_pc);
-
-  // patch throwing pc into return address (has bci & oop map)
-  __ movptr(Address(rbp, 1*BytesPerWord), exception_pc);
-
-  // compute the exception handler.
-  // the exception oop and the throwing pc are read from the fields in JavaThread
-  int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, exception_handler_for_pc));
-  oop_maps->add_gc_map(call_offset, oop_map);
-
-  // rax: handler address
-  //      will be the deopt blob if nmethod was deoptimized while we looked up
-  //      handler regardless of whether handler existed in the nmethod.
-
-  // only rax, is valid at this time, all other registers have been destroyed by the runtime call
-#ifdef ASSERT
-  __ movptr(rbx, 0xDEAD);
-  __ movptr(rcx, 0xDEAD);
-  __ movptr(rdx, 0xDEAD);
-  __ movptr(rsi, 0xDEAD);
-  __ movptr(rdi, 0xDEAD);
-#endif
-
-  // patch the return address, this stub will directly return to the exception handler
-  __ movptr(Address(rbp, 1*BytesPerWord), rax);
-
-  switch (id) {
-    case handle_exception_nofpu_id:
-      // Restore the registers that were saved at the beginning.
-      restore_live_registers(sasm, id == handle_exception_nofpu_id);
-      break;
-    default:  ShouldNotReachHere();
-  }
-
-  return oop_maps;
-}
-
-void GraalRuntime::generate_unwind_exception(GraalStubAssembler *sasm) {
-  // incoming parameters
-  const Register exception_oop = rax;
-  // callee-saved copy of exception_oop during runtime call
-  const Register exception_oop_callee_saved = NOT_LP64(rsi) LP64_ONLY(r14);
-  // other registers used in this stub
-  const Register exception_pc = rdx;
-  const Register handler_addr = rbx;
-  const Register thread = NOT_LP64(rdi) LP64_ONLY(r15_thread);
-
-  // verify that only rax is valid at this time
-#ifdef ASSERT
-  __ movptr(rbx, 0xDEAD);
-  __ movptr(rcx, 0xDEAD);
-  __ movptr(rdx, 0xDEAD);
-  __ movptr(rsi, 0xDEAD);
-  __ movptr(rdi, 0xDEAD);
-#endif
-
-#ifdef ASSERT
-  // check that fields in JavaThread for exception oop and issuing pc are empty
-  NOT_LP64(__ get_thread(thread);)
-  Label oop_empty;
-  __ cmpptr(Address(thread, JavaThread::exception_oop_offset()), 0);
-  __ jcc(Assembler::equal, oop_empty);
-  __ stop("exception oop must be empty");
-  __ bind(oop_empty);
-
-  Label pc_empty;
-  __ cmpptr(Address(thread, JavaThread::exception_pc_offset()), 0);
-  __ jcc(Assembler::equal, pc_empty);
-  __ stop("exception pc must be empty");
-  __ bind(pc_empty);
-#endif
-
-  // clear the FPU stack in case any FPU results are left behind
-  __ empty_FPU_stack();
-
-  // save exception_oop in callee-saved register to preserve it during runtime calls
-  __ verify_not_null_oop(exception_oop);
-  __ movptr(exception_oop_callee_saved, exception_oop);
-
-  NOT_LP64(__ get_thread(thread);)
-  // Get return address (is on top of stack after leave).
-  __ movptr(exception_pc, Address(rsp, 0));
-
-  // search the exception handler address of the caller (using the return address)
-  __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), thread, exception_pc);
-  // rax: exception handler address of the caller
-
-  // Only RAX and RSI are valid at this time, all other registers have been destroyed by the call.
-#ifdef ASSERT
-  __ movptr(rbx, 0xDEAD);
-  __ movptr(rcx, 0xDEAD);
-  __ movptr(rdx, 0xDEAD);
-  __ movptr(rdi, 0xDEAD);
-#endif
-
-  // move result of call into correct register
-  __ movptr(handler_addr, rax);
-
-  // Restore exception oop to RAX (required convention of exception handler).
-  __ movptr(exception_oop, exception_oop_callee_saved);
-
-  // verify that there is really a valid exception in rax
-  __ verify_not_null_oop(exception_oop);
-
-  // get throwing pc (= return address).
-  // rdx has been destroyed by the call, so it must be set again
-  // the pop is also necessary to simulate the effect of a ret(0)
-  __ pop(exception_pc);
-
-  // Restore SP from BP if the exception PC is a method handle call site.
-  NOT_LP64(__ get_thread(thread);)
-  __ cmpl(Address(thread, JavaThread::is_method_handle_return_offset()), 0);
-  __ cmovptr(Assembler::notEqual, rsp, rbp_mh_SP_save);
-
-  // continue at exception handler (return address removed)
-  // note: do *not* remove arguments when unwinding the
-  //       activation since the caller assumes having
-  //       all arguments on the stack when entering the
-  //       runtime to determine the exception handler
-  //       (GC happens at call site with arguments!)
-  // rax: exception oop
-  // rdx: throwing pc
-  // rbx: exception handler
-  __ jmp(handler_addr);
-}
-
-OopMapSet* GraalRuntime::generate_code_for(StubID id, GraalStubAssembler* sasm) {
-
-  // for better readability
-  const bool must_gc_arguments = true;
-  const bool dont_gc_arguments = false;
-
-  // default value; overwritten for some optimized stubs that are called from methods that do not use the fpu
-  bool save_fpu_registers = true;
-
-  // stub code & info for the different stubs
-  OopMapSet* oop_maps = NULL;
-  switch (id) {
-
-    case new_instance_id:
-      {
-        Register klass = rdx; // Incoming
-        Register obj   = rax; // Result
-        __ set_info("new_instance", dont_gc_arguments);
-        __ enter();
-        OopMap* map = save_live_registers(sasm, 2);
-        int call_offset = __ call_RT(obj, noreg, CAST_FROM_FN_PTR(address, new_instance), klass);
-        oop_maps = new OopMapSet();
-        oop_maps->add_gc_map(call_offset, map);
-        restore_live_registers_except_rax(sasm);
-        __ verify_oop(obj);
-        __ leave();
-        __ ret(0);
-
-        // rax,: new instance
-      }
-
-      break;
-
-    case new_array_id:
-      {
-        Register length   = rbx; // Incoming
-        Register klass    = rdx; // Incoming
-        Register obj      = rax; // Result
-
-        __ set_info("new_array", dont_gc_arguments);
-
-        __ enter();
-        OopMap* map = save_live_registers(sasm, 3);
-        int call_offset;
-        call_offset = __ call_RT(obj, noreg, CAST_FROM_FN_PTR(address, new_array), klass, length);
-
-        oop_maps = new OopMapSet();
-        oop_maps->add_gc_map(call_offset, map);
-        restore_live_registers_except_rax(sasm);
-
-        __ verify_oop(obj);
-        __ leave();
-        __ ret(0);
-
-        // rax,: new array
-      }
-      break;
-
-    case new_multi_array_id:
-      { GraalStubFrame f(sasm, "new_multi_array", dont_gc_arguments);
-        // rax,: klass
-        // rbx,: rank
-        // rcx: address of 1st dimension
-        OopMap* map = save_live_registers(sasm, 4);
-        int call_offset = __ call_RT(rax, noreg, CAST_FROM_FN_PTR(address, new_multi_array), rax, rbx, rcx);
-
-        oop_maps = new OopMapSet();
-        oop_maps->add_gc_map(call_offset, map);
-        restore_live_registers_except_rax(sasm);
-
-        // rax,: new multi array
-        __ verify_oop(rax);
-      }
-      break;
-
-    case register_finalizer_id:
-      {
-        __ set_info("register_finalizer", dont_gc_arguments);
-
-        // This is called via call_runtime so the arguments
-        // will be place in C abi locations
-        __ verify_oop(j_rarg0);
-        __ enter();
-        OopMap* oop_map = save_live_registers(sasm, 2 /*num_rt_args */);
-        int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, SharedRuntime::register_finalizer), j_rarg0);
-        oop_maps = new OopMapSet();
-        oop_maps->add_gc_map(call_offset, oop_map);
-
-        // Now restore all the live registers
-        restore_live_registers(sasm);
-
-        __ leave();
-        __ ret(0);
-      }
-      break;
-
-    case handle_exception_nofpu_id:
-      { GraalStubFrame f(sasm, "handle_exception", dont_gc_arguments);
-        oop_maps = generate_handle_exception(id, sasm);
-      }
-      break;
-
-    case unwind_exception_call_id: {
-      // remove the frame from the stack
-      __ movptr(rsp, rbp);
-      __ pop(rbp);
-
-      __ set_info("unwind_exception", dont_gc_arguments);
-      // note: no stubframe since we are about to leave the current
-      //       activation and we are calling a leaf VM function only.
-      generate_unwind_exception(sasm);
-      __ should_not_reach_here();
-      break;
-    }
-
-    case OSR_migration_end_id: {
-    __ enter();
-    save_live_registers(sasm, 0);
-    __ movptr(c_rarg0, j_rarg0);
-    __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::OSR_migration_end)));
-    restore_live_registers(sasm);
-    __ leave();
-    __ ret(0);
-      break;
-    }
-
-    case create_null_pointer_exception_id: {
-		__ enter();
-		oop_maps = new OopMapSet();
-		OopMap* oop_map = save_live_registers(sasm, 0);
-		int call_offset = __ call_RT(rax, noreg, (address)create_null_exception, 0);
-		oop_maps->add_gc_map(call_offset, oop_map);
-		restore_live_registers_except_rax(sasm);
-		__ leave();
-		__ ret(0);
-      break;
-    }
-
-    case create_out_of_bounds_exception_id: {
-		__ enter();
-		oop_maps = new OopMapSet();
-		OopMap* oop_map = save_live_registers(sasm, 1);
-		int call_offset = __ call_RT(rax, noreg, (address)create_out_of_bounds_exception, j_rarg0);
-		oop_maps->add_gc_map(call_offset, oop_map);
-		restore_live_registers_except_rax(sasm);
-		__ leave();
-		__ ret(0);
-      break;
-    }
-
-    case vm_error_id: {
-      __ enter();
-      oop_maps = new OopMapSet();
-      OopMap* oop_map = save_live_registers(sasm, 3);
-      int call_offset = __ call_RT(noreg, noreg, (address)vm_error, j_rarg0, j_rarg1, j_rarg2);
-      oop_maps->add_gc_map(call_offset, oop_map);
-      restore_live_registers(sasm);
-      __ leave();
-      __ ret(0);
-      break;
-    }
-
-    case log_printf_id: {
-      __ enter();
-      oop_maps = new OopMapSet();
-      OopMap* oop_map = save_live_registers(sasm, 4);
-      int call_offset = __ call_RT(noreg, noreg, (address)log_printf, j_rarg0, j_rarg1, j_rarg2, j_rarg3);
-      oop_maps->add_gc_map(call_offset, oop_map);
-      restore_live_registers(sasm);
-      __ leave();
-      __ ret(0);
-      break;
-    }
-
-    case stub_printf_id: {
-      __ enter();
-      oop_maps = new OopMapSet();
-      OopMap* oop_map = save_live_registers(sasm, 4);
-      int call_offset = __ call_RT(noreg, noreg, (address)stub_printf, j_rarg0, j_rarg1, j_rarg2, j_rarg3);
-      oop_maps->add_gc_map(call_offset, oop_map);
-      restore_live_registers(sasm);
-      __ leave();
-      __ ret(0);
-      break;
-    }
-
-    case log_primitive_id: {
-      __ enter();
-      oop_maps = new OopMapSet();
-      OopMap* oop_map = save_live_registers(sasm, 3);
-      int call_offset = __ call_RT(noreg, noreg, (address)log_primitive, j_rarg0, j_rarg1, j_rarg2);
-      oop_maps->add_gc_map(call_offset, oop_map);
-      restore_live_registers(sasm);
-      __ leave();
-      __ ret(0);
-      break;
-    }
-
-    case log_object_id: {
-      __ enter();
-      oop_maps = new OopMapSet();
-      OopMap* oop_map = save_live_registers(sasm, 2);
-      int call_offset = __ call_RT(noreg, noreg, (address)log_object, j_rarg0, j_rarg1);
-      oop_maps->add_gc_map(call_offset, oop_map);
-      restore_live_registers(sasm);
-      __ leave();
-      __ ret(0);
-      break;
-    }
-
-    case verify_oop_id: {
-      // We use enter & leave so that a better stack trace is produced in the hs_err file
-      __ enter();
-      __ verify_oop(r13, "Graal verify oop");
-      __ leave();
-      __ ret(0);
-      break;
-    }
-
-    case arithmetic_frem_id: {
-      __ subptr(rsp, 8);
-      __ movflt(Address(rsp, 0), xmm1);
-      __ fld_s(Address(rsp, 0));
-      __ movflt(Address(rsp, 0), xmm0);
-      __ fld_s(Address(rsp, 0));
-      Label L;
-      __ bind(L);
-      __ fprem();
-      __ fwait();
-      __ fnstsw_ax();
-      __ testl(rax, 0x400);
-      __ jcc(Assembler::notZero, L);
-      __ fxch(1);
-      __ fpop();
-      __ fstp_s(Address(rsp, 0));
-      __ movflt(xmm0, Address(rsp, 0));
-      __ addptr(rsp, 8);
-      __ ret(0);
-      break;
-    }
-    case arithmetic_drem_id: {
-      __ subptr(rsp, 8);
-      __ movdbl(Address(rsp, 0), xmm1);
-      __ fld_d(Address(rsp, 0));
-      __ movdbl(Address(rsp, 0), xmm0);
-      __ fld_d(Address(rsp, 0));
-      Label L;
-      __ bind(L);
-      __ fprem();
-      __ fwait();
-      __ fnstsw_ax();
-      __ testl(rax, 0x400);
-      __ jcc(Assembler::notZero, L);
-      __ fxch(1);
-      __ fpop();
-      __ fstp_d(Address(rsp, 0));
-      __ movdbl(xmm0, Address(rsp, 0));
-      __ addptr(rsp, 8);
-      __ ret(0);
-      break;
-    }
-    case monitorenter_id: {
-      Register obj = j_rarg0;
-      Register lock = j_rarg1;
-      {
-        GraalStubFrame f(sasm, "monitorenter", dont_gc_arguments);
-        OopMap* map = save_live_registers(sasm, 2, save_fpu_registers);
-
-        // Called with store_parameter and not C abi
-        int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, monitorenter), obj, lock);
-
-        oop_maps = new OopMapSet();
-        oop_maps->add_gc_map(call_offset, map);
-        restore_live_registers(sasm, save_fpu_registers);
-      }
-      __ ret(0);
-      break;
-    }
-    case monitorexit_id: {
-      Register obj = j_rarg0;
-      Register lock = j_rarg1;
-      {
-        GraalStubFrame f(sasm, "monitorexit", dont_gc_arguments);
-        OopMap* map = save_live_registers(sasm, 2, save_fpu_registers);
-
-        // note: really a leaf routine but must setup last java sp
-        //       => use call_RT for now (speed can be improved by
-        //       doing last java sp setup manually)
-        int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, monitorexit), obj, lock);
-
-        oop_maps = new OopMapSet();
-        oop_maps->add_gc_map(call_offset, map);
-        restore_live_registers(sasm, save_fpu_registers);
-      }
-      __ ret(0);
-      break;
-   }
-   case wb_pre_call_id: {
-      Register obj = j_rarg0;
-      {
-        GraalStubFrame f(sasm, "graal_wb_pre_call", dont_gc_arguments);
-        OopMap* map = save_live_registers(sasm, 2, save_fpu_registers);
-
-        // note: really a leaf routine but must setup last java sp
-        //       => use call_RT for now (speed can be improved by
-        //       doing last java sp setup manually)
-        int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, wb_pre_call), obj);
-
-        oop_maps = new OopMapSet();
-        oop_maps->add_gc_map(call_offset, map);
-        restore_live_registers(sasm);
-      }
-      __ ret(0);
-      break;
-   }
-   case wb_post_call_id: {
-      Register obj = j_rarg0;
-      Register caddr = j_rarg1;
-      {
-        GraalStubFrame f(sasm, "graal_wb_post_call", dont_gc_arguments);
-        OopMap* map = save_live_registers(sasm, 2, save_fpu_registers);
-
-        // note: really a leaf routine but must setup last java sp
-        //       => use call_RT for now (speed can be improved by
-        //       doing last java sp setup manually)
-        int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, wb_post_call), obj, caddr);
-
-        oop_maps = new OopMapSet();
-        oop_maps->add_gc_map(call_offset, map);
-        restore_live_registers(sasm);
-      }
-      __ ret(0);
-      break;
-   }
-
-
-    case identity_hash_code_id: {
-      Register obj = j_rarg0; // Incoming
-      __ set_info("identity_hash_code", dont_gc_arguments);
-      __ enter();
-      OopMap* map = save_live_registers(sasm, 1);
-      int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, identity_hash_code), obj);
-      oop_maps = new OopMapSet();
-      oop_maps->add_gc_map(call_offset, map);
-      restore_live_registers_except_rax(sasm);
-      __ leave();
-      __ ret(0);
-      break;
-    }
-    case thread_is_interrupted_id: {
-      Register thread = j_rarg0;
-      Register clear_interrupted = j_rarg1;
-
-      __ set_info("identity_hash_code", dont_gc_arguments);
-      __ enter();
-      OopMap* map = save_live_registers(sasm, 1);
-      int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, thread_is_interrupted), thread, clear_interrupted);
-      oop_maps = new OopMapSet();
-      oop_maps->add_gc_map(call_offset, map);
-      restore_live_registers_except_rax(sasm);
-      __ leave();
-      __ ret(0);
-      break;
-    }
-
-    default:
-      { GraalStubFrame f(sasm, "unimplemented entry", dont_gc_arguments);
-        __ movptr(rax, (int)id);
-        __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, unimplemented_entry), rax);
-        __ should_not_reach_here();
-      }
-      break;
-  }
-  return oop_maps;
-}
-
-#undef __
--- a/src/cpu/x86/vm/graalStubAssembler_x86.cpp	Mon May 13 16:46:39 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-/*
- * Copyright (c) 1999, 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.
- *
- */
-
-#include "precompiled.hpp"
-#include "graal/graalRuntime.hpp"
-#include "classfile/systemDictionary.hpp"
-#include "gc_interface/collectedHeap.hpp"
-#include "interpreter/interpreter.hpp"
-#include "oops/arrayOop.hpp"
-#include "oops/markOop.hpp"
-#include "runtime/basicLock.hpp"
-#include "runtime/biasedLocking.hpp"
-#include "runtime/os.hpp"
-#include "runtime/stubRoutines.hpp"
-
-#ifndef PRODUCT
-
-void GraalStubAssembler::verify_stack_oop(int stack_offset) {
-  if (!VerifyOops) return;
-  verify_oop_addr(Address(rsp, stack_offset));
-}
-
-void GraalStubAssembler::verify_not_null_oop(Register r) {
-  if (!VerifyOops) return;
-  Label not_null;
-  testptr(r, r);
-  jcc(Assembler::notZero, not_null);
-  stop("non-null oop required");
-  bind(not_null);
-  verify_oop(r);
-}
-
-#endif // ifndef PRODUCT
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gpu/ptx/gpu_ptx.cpp	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,168 @@
+/*
+ * 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.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "runtime/gpu.hpp"
+#include "utilities/globalDefinitions.hpp"
+#include "utilities/ostream.hpp"
+
+void * gpu::Ptx::_device_context;
+
+gpu::Ptx::cuda_cu_init_func_t gpu::Ptx::_cuda_cu_init;
+gpu::Ptx::cuda_cu_ctx_create_func_t gpu::Ptx::_cuda_cu_ctx_create;
+gpu::Ptx::cuda_cu_ctx_detach_func_t gpu::Ptx::_cuda_cu_ctx_detach;
+gpu::Ptx::cuda_cu_ctx_synchronize_func_t gpu::Ptx::_cuda_cu_ctx_synchronize;
+gpu::Ptx::cuda_cu_device_get_count_func_t gpu::Ptx::_cuda_cu_device_get_count;
+gpu::Ptx::cuda_cu_device_get_name_func_t gpu::Ptx::_cuda_cu_device_get_name;
+gpu::Ptx::cuda_cu_device_get_func_t gpu::Ptx::_cuda_cu_device_get;
+gpu::Ptx::cuda_cu_device_compute_capability_func_t gpu::Ptx::_cuda_cu_device_compute_capability;
+gpu::Ptx::cuda_cu_launch_kernel_func_t gpu::Ptx::_cuda_cu_launch_kernel;
+gpu::Ptx::cuda_cu_module_get_function_func_t gpu::Ptx::_cuda_cu_module_get_function;
+gpu::Ptx::cuda_cu_module_load_data_ex_func_t gpu::Ptx::_cuda_cu_module_load_data_ex;
+
+void gpu::probe_linkage() {
+#ifdef __APPLE__
+  set_gpu_linkage(gpu::Ptx::probe_linkage_apple());
+#else
+  set_gpu_linkage(false);
+#endif
+}
+
+void gpu::initialize_gpu() {
+  if (gpu::has_gpu_linkage()) {
+    set_initialized(gpu::Ptx::initialize_gpu());
+  }
+}
+
+void gpu::generate_kernel(unsigned char *code, int code_len, const char *name) {
+  if (gpu::has_gpu_linkage()) {
+    gpu::Ptx::generate_kernel(code, code_len, name);
+  }
+}
+
+#define __CUDA_API_VERSION 5000
+
+bool gpu::Ptx::initialize_gpu() {
+  int status = _cuda_cu_init(0, __CUDA_API_VERSION);
+  if (TraceWarpLoading) {
+    tty->print_cr("gpu_ptx::_cuda_cu_init: %d", status);
+  }
+
+  int device_count = 0;
+  status = _cuda_cu_device_get_count(&device_count);
+  if (TraceWarpLoading) {
+    tty->print_cr("gpu_ptx::_cuda_cu_device_get_count(%d): %d", device_count, status);
+  }
+
+  int device_id = 0, cu_device = 0;
+  status = _cuda_cu_device_get(&cu_device, device_id);
+  if (TraceWarpLoading) {
+    tty->print_cr("gpu_ptx::_cuda_cu_device_get(%d): %d", cu_device, status);
+  }
+
+  int major, minor;
+  status = _cuda_cu_device_compute_capability(&major, &minor, cu_device);
+  if (TraceWarpLoading) {
+    tty->print_cr("gpu_ptx::_cuda_cu_device_compute_capability(major %d, minor %d): %d",
+                  major, minor, status);
+  }
+
+  char device_name[256];
+  status = _cuda_cu_device_get_name(device_name, 256, cu_device);
+  if (TraceWarpLoading) {
+    tty->print_cr("gpu_ptx::_cuda_cu_device_get_name(%s): %d", device_name, status);
+  }
+
+  status = _cuda_cu_ctx_create(&_device_context, 0, cu_device);
+  if (TraceWarpLoading) {
+    tty->print_cr("gpu_ptx::_cuda_cu_ctx_create(%x): %d", _device_context, status);
+  }
+
+  return status == 0;  // CUDA_SUCCESS
+}
+
+void gpu::Ptx::generate_kernel(unsigned char *code, int code_len, const char *name) {
+
+  void *cu_module;
+  const unsigned int jit_num_options = 3;
+  int *jit_options = new int[jit_num_options];
+  void **jit_option_values = new void *[jit_num_options];
+
+  jit_options[0] = 4; // CU_JIT_INFO_LOG_BUFFER_SIZE_BYTES
+  int jit_log_buffer_size = 1024;
+  jit_option_values[0] = (void *)(size_t)jit_log_buffer_size;
+
+  jit_options[1] = 3; // CU_JIT_INFO_LOG_BUFFER
+  char *jit_log_buffer = new char[jit_log_buffer_size];
+  jit_option_values[1] = jit_log_buffer;
+
+  jit_options[2] = 0; // CU_JIT_MAX_REGISTERS
+  int jit_register_count = 32;
+  jit_option_values[2] = (void *)(size_t)jit_register_count;
+  
+  int status = _cuda_cu_module_load_data_ex(&cu_module, code,
+                                            jit_num_options, jit_options, (void **)jit_option_values);
+  if (TraceWarpLoading) {
+    tty->print_cr("gpu_ptx::_cuda_cu_module_load_data_ex(%x): %d", cu_module, status);
+    tty->print_cr("gpu_ptx::jit_log_buffer\n%s", jit_log_buffer);
+  }
+
+  void *cu_function;
+
+  status = _cuda_cu_module_get_function(&cu_function, cu_module, name);
+  if (TraceWarpLoading) {
+    tty->print_cr("gpu_ptx::_cuda_cu_module_get_function(%s):%x %d", name, cu_function, status);
+  }
+}
+
+
+#ifdef __APPLE__
+bool gpu::Ptx::probe_linkage_apple() {
+  void *handle = dlopen("/usr/local/cuda/lib/libcuda.dylib", RTLD_LAZY);
+  if (handle != NULL) {
+    _cuda_cu_init =
+        CAST_TO_FN_PTR(cuda_cu_init_func_t, dlsym(handle, "cuInit"));
+    _cuda_cu_ctx_create =
+        CAST_TO_FN_PTR(cuda_cu_ctx_create_func_t, dlsym(handle, "cuCtxCreate"));
+    _cuda_cu_ctx_detach =
+        CAST_TO_FN_PTR(cuda_cu_ctx_detach_func_t, dlsym(handle, "cuCtxDetach"));
+    _cuda_cu_ctx_synchronize =
+        CAST_TO_FN_PTR(cuda_cu_ctx_synchronize_func_t, dlsym(handle, "cuCtxSynchronize"));
+    _cuda_cu_device_get_count =
+        CAST_TO_FN_PTR(cuda_cu_device_get_count_func_t, dlsym(handle, "cuDeviceGetCount"));
+    _cuda_cu_device_get_name =
+        CAST_TO_FN_PTR(cuda_cu_device_get_name_func_t, dlsym(handle, "cuDeviceGetName"));
+    _cuda_cu_device_get =
+        CAST_TO_FN_PTR(cuda_cu_device_get_func_t, dlsym(handle, "cuDeviceGet"));
+    _cuda_cu_device_compute_capability =
+        CAST_TO_FN_PTR(cuda_cu_device_compute_capability_func_t, dlsym(handle, "cuDeviceComputeCapability"));
+    _cuda_cu_module_get_function =
+        CAST_TO_FN_PTR(cuda_cu_module_get_function_func_t, dlsym(handle, "cuModuleGetFunction"));
+    _cuda_cu_module_load_data_ex =
+        CAST_TO_FN_PTR(cuda_cu_module_load_data_ex_func_t, dlsym(handle, "cuModuleLoadDataEx"));
+    return true;
+  }
+  return false;
+}
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gpu/ptx/gpu_ptx.hpp	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef GPU_PTX_HPP
+#define GPU_PTX_HPP
+
+class Ptx {
+  friend class gpu;
+
+ protected:
+  static void probe_linkage();
+#ifdef __APPLE__
+  static bool probe_linkage_apple();
+#endif
+  static bool initialize_gpu();
+  static void generate_kernel(unsigned char *code, int code_len, const char *name);
+  
+private:
+  typedef int (*cuda_cu_init_func_t)(unsigned int, int);
+  typedef int (*cuda_cu_ctx_create_func_t)(void *, int, int);
+  typedef int (*cuda_cu_ctx_detach_func_t)(int *);
+  typedef int (*cuda_cu_ctx_synchronize_func_t)(int *);
+  typedef int (*cuda_cu_device_get_count_func_t)(int *);
+  typedef int (*cuda_cu_device_get_name_func_t)(char *, int, int);
+  typedef int (*cuda_cu_device_get_func_t)(int *, int);
+  typedef int (*cuda_cu_device_compute_capability_func_t)(int *, int *, int);
+  typedef int (*cuda_cu_launch_kernel_func_t)(int *, int *, int);
+  typedef int (*cuda_cu_module_get_function_func_t)(void *, void *, const char *);
+  typedef int (*cuda_cu_module_load_data_ex_func_t)(void *, void *, unsigned int, int *, void **);
+
+  static cuda_cu_init_func_t                      _cuda_cu_init;
+  static cuda_cu_ctx_create_func_t                _cuda_cu_ctx_create;
+  static cuda_cu_ctx_detach_func_t                _cuda_cu_ctx_detach;
+  static cuda_cu_ctx_synchronize_func_t           _cuda_cu_ctx_synchronize;
+  static cuda_cu_device_get_count_func_t          _cuda_cu_device_get_count;
+  static cuda_cu_device_get_name_func_t           _cuda_cu_device_get_name;
+  static cuda_cu_device_get_func_t                _cuda_cu_device_get;
+  static cuda_cu_device_compute_capability_func_t _cuda_cu_device_compute_capability;
+  static cuda_cu_launch_kernel_func_t             _cuda_cu_launch_kernel;
+  static cuda_cu_module_get_function_func_t       _cuda_cu_module_get_function;
+  static cuda_cu_module_load_data_ex_func_t       _cuda_cu_module_load_data_ex;
+
+protected:
+  static void * _device_context;
+};
+
+#endif // GPU_PTX_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/os/bsd/vm/gpu_bsd.cpp	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ *
+ */
+
+#include "runtime/gpu.hpp"
+#include "utilities/ostream.hpp"
+
+#ifdef __APPLE__
+#include <ApplicationServices/ApplicationServices.h>
+#include <IOKit/IOKitLib.h>
+#endif
+
+void gpu::probe_gpu() {
+#ifdef __APPLE__
+  set_available(gpu::Bsd::probe_gpu_apple());
+  if (TraceWarpLoading) {
+    tty->print_cr("gpu_bsd::probe_gpu(APPLE): %d", gpu::is_available());
+  }
+#else
+  if (TraceWarpLoading) {
+    tty->print_cr("gpu_bsd::probe_gpu(not APPLE)");
+  }
+  set_available(false);
+#endif
+}
+
+#ifdef __APPLE__
+/*
+ * This is rudimentary at best, but until we decide on a CUDA Compiler Compatibility
+ * level, this will have to suffice.
+ */
+bool gpu::Bsd::probe_gpu_apple() {
+  CGError             err = CGDisplayNoErr;
+  CGDisplayCount      displayCount = 0;
+  CFDataRef           vendorID, deviceID, model;
+  CGDirectDisplayID   *displays;
+  IOOptionBits        options = kIORegistryIterateRecursively | kIORegistryIterateParents;
+  io_registry_entry_t displayPort;
+
+  err = CGGetActiveDisplayList(0, NULL, &displayCount);
+  displays = (CGDirectDisplayID *)calloc((size_t)displayCount, sizeof(CGDirectDisplayID));
+  err = CGGetActiveDisplayList(displayCount, displays, &displayCount);
+
+  for (CGDisplayCount i = 0; i < displayCount; i++) {
+	displayPort = CGDisplayIOServicePort(displays[i]);
+	vendorID = (CFDataRef)IORegistryEntrySearchCFProperty(displayPort, kIOServicePlane, CFSTR("vendor-id"),
+                                               kCFAllocatorDefault, options);
+	deviceID = (CFDataRef)IORegistryEntrySearchCFProperty(displayPort, kIOServicePlane, CFSTR("device-id"),
+                                               kCFAllocatorDefault, options);
+	model = (CFDataRef)IORegistryEntrySearchCFProperty(displayPort, kIOServicePlane, CFSTR("model"),
+                                            kCFAllocatorDefault, options);
+    if (TraceWarpLoading) {
+      tty->print_cr("vendor: 0x%08X", *((UInt32*)CFDataGetBytePtr(vendorID)));
+      tty->print_cr("device: 0x%08X", *((UInt32*)CFDataGetBytePtr(deviceID)));
+      tty->print_cr("model: %s", CFDataGetBytePtr(model));
+    }
+    UInt32 vendor = *((UInt32*)CFDataGetBytePtr(vendorID));
+    if (vendor != 0x10DE) {
+      return false;
+    } else {
+      /*
+       * see https://developer.nvidia.com/cuda-gpus
+       * see http://en.wikipedia.org/wiki/CUDA#Supported_GPUs
+       * see http://www.pcidatabase.com/reports.php?type=csv
+       *
+       * Only supporting GK104, GK106, GK107 and GK110 GPUs for now,
+       * which is CUDA Computer Capability 3.0 and greater.
+       */
+      switch (*((UInt32*)CFDataGetBytePtr(deviceID))) {
+        case 0x11C0:
+          return true;  // NVIDIA GeForce GTX 660
+        default:
+          return false;
+      }
+    }
+  }
+  return false;
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/os/bsd/vm/gpu_bsd.hpp	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef OS_BSD_VM_GPU_BSD_HPP
+#define OS_BSD_VM_GPU_BSD_HPP
+
+
+class Bsd {
+  friend class gpu;
+
+ protected:
+  static bool probe_gpu();
+#ifdef __APPLE__
+  static bool probe_gpu_apple();
+#endif
+};
+
+#endif // OS_BSD_VM_GPU_BSD_HPP
--- a/src/share/tools/IdealGraphVisualizer/Filter/src/com/sun/hotspot/igv/filter/CustomFilter.java	Mon May 13 16:46:39 2013 +0200
+++ b/src/share/tools/IdealGraphVisualizer/Filter/src/com/sun/hotspot/igv/filter/CustomFilter.java	Mon May 13 17:11:31 2013 +0200
@@ -98,7 +98,12 @@
 
     private static String getJsHelperText() {
         InputStream is = null;
-        StringBuilder sb = new StringBuilder("importPackage(Packages.com.sun.hotspot.igv.filter);importPackage(Packages.com.sun.hotspot.igv.graph);importPackage(Packages.com.sun.hotspot.igv.data);importPackage(Packages.com.sun.hotspot.igv.util);importPackage(java.awt);");
+        StringBuilder sb = new StringBuilder("if (typeof importPackage === 'undefined') { try { load('nashorn:mozilla_compat.js'); } catch (e) {} }"
+                + "importPackage(Packages.com.sun.hotspot.igv.filter);"
+                + "importPackage(Packages.com.sun.hotspot.igv.graph);"
+                + "importPackage(Packages.com.sun.hotspot.igv.data);"
+                + "importPackage(Packages.com.sun.hotspot.igv.util);"
+                + "importPackage(java.awt);");
         try {
             FileObject fo = FileUtil.getConfigRoot().getFileObject(JAVASCRIPT_HELPER_ID);
             is = fo.getInputStream();
--- a/src/share/vm/classfile/systemDictionary.hpp	Mon May 13 16:46:39 2013 +0200
+++ b/src/share/vm/classfile/systemDictionary.hpp	Mon May 13 17:11:31 2013 +0200
@@ -183,7 +183,7 @@
   do_klass(Long_klass,                                  java_lang_Long,                            Pre                 ) \
                                                                                                                          \
   /* Support for Graal */                                                                                                \
-  do_klass(GraalBitMap_klass,                     java_util_BitSet,                                             Opt) \
+  do_klass(BitSet_klass,                          java_util_BitSet,                                             Opt) \
   /* graal.hotspot */                                                                                                \
   do_klass(HotSpotCompilationResult_klass,        com_oracle_graal_hotspot_HotSpotCompilationResult,            Opt) \
   do_klass(HotSpotRuntimeCallTarget_klass,        com_oracle_graal_hotspot_HotSpotRuntimeCallTarget,            Opt) \
@@ -205,6 +205,7 @@
   do_klass(Assumptions_CallSiteTargetValue_klass, com_oracle_graal_api_code_Assumptions_CallSiteTargetValue,    Opt) \
   do_klass(BytecodePosition_klass,                com_oracle_graal_api_code_BytecodePosition,                   Opt) \
   do_klass(DebugInfo_klass,                       com_oracle_graal_api_code_DebugInfo,                          Opt) \
+  do_klass(RegisterSaveLayout_klass,              com_oracle_graal_api_code_RegisterSaveLayout,                 Opt) \
   do_klass(BytecodeFrame_klass,                   com_oracle_graal_api_code_BytecodeFrame,                      Opt) \
   do_klass(CompilationResult_klass,               com_oracle_graal_api_code_CompilationResult,                  Opt) \
   do_klass(CompilationResult_Call_klass,          com_oracle_graal_api_code_CompilationResult_Call,             Opt) \
--- a/src/share/vm/classfile/vmSymbols.hpp	Mon May 13 16:46:39 2013 +0200
+++ b/src/share/vm/classfile/vmSymbols.hpp	Mon May 13 17:11:31 2013 +0200
@@ -341,6 +341,7 @@
   template(com_oracle_graal_api_code_RegisterValue,                  "com/oracle/graal/api/code/RegisterValue")                       \
   template(com_oracle_graal_api_code_StackSlot,                      "com/oracle/graal/api/code/StackSlot")                           \
   template(com_oracle_graal_api_code_VirtualObject,                  "com/oracle/graal/api/code/VirtualObject")                       \
+  template(com_oracle_graal_api_code_RegisterSaveLayout,             "com/oracle/graal/api/code/RegisterSaveLayout")                  \
   template(com_oracle_graal_api_code_InvalidInstalledCodeException,  "com/oracle/graal/api/code/InvalidInstalledCodeException")       \
   template(startCompiler_name,                    "startCompiler")                                                                    \
   template(bootstrap_name,                        "bootstrap")                                                                        \
--- a/src/share/vm/graal/graalCodeInstaller.cpp	Mon May 13 16:46:39 2013 +0200
+++ b/src/share/vm/graal/graalCodeInstaller.cpp	Mon May 13 17:11:31 2013 +0200
@@ -68,16 +68,16 @@
 
 const int MapWordBits = 64;
 
-static bool is_bit_set(oop bit_map, int i) {
-  jint extra_idx = i / MapWordBits;
-  arrayOop extra = (arrayOop) GraalBitMap::words(bit_map);
-  assert(extra_idx >= 0 && extra_idx < extra->length(), "unexpected index");
-  jlong word = ((jlong*) extra->base(T_LONG))[extra_idx];
+static bool is_bit_set(oop bitset, int i) {
+  jint words_idx = i / MapWordBits;
+  arrayOop words = (arrayOop) BitSet::words(bitset);
+  assert(words_idx >= 0 && words_idx < words->length(), "unexpected index");
+  jlong word = ((jlong*) words->base(T_LONG))[words_idx];
   return (word & (1LL << (i % MapWordBits))) != 0;
 }
 
-static int bitmap_size(oop bit_map) {
-  arrayOop arr = (arrayOop) GraalBitMap::words(bit_map);
+static int bitset_size(oop bitset) {
+  arrayOop arr = (arrayOop) BitSet::words(bitset);
   return arr->length() * MapWordBits;
 }
 
@@ -86,23 +86,24 @@
   OopMap* map = new OopMap(total_frame_size, parameter_count);
   oop register_map = (oop) DebugInfo::registerRefMap(debug_info);
   oop frame_map = (oop) DebugInfo::frameRefMap(debug_info);
+  oop callee_save_info = (oop) DebugInfo::calleeSaveInfo(debug_info);
 
   if (register_map != NULL) {
     for (jint i = 0; i < RegisterImpl::number_of_registers; i++) {
       bool is_oop = is_bit_set(register_map, i);
-      VMReg reg = get_hotspot_reg(i);
+      VMReg hotspot_reg = get_hotspot_reg(i);
       if (is_oop) {
-        map->set_oop(reg);
+        map->set_oop(hotspot_reg);
       } else {
-        map->set_value(reg);
+        map->set_value(hotspot_reg);
       }
     }
   }
 
-  for (jint i = 0; i < bitmap_size(frame_map); i++) {
+  for (jint i = 0; i < bitset_size(frame_map); i++) {
     bool is_oop = is_bit_set(frame_map, i);
     // HotSpot stack slots are 4 bytes
-    VMReg reg = VMRegImpl::stack2reg(i * 2);
+    VMReg reg = VMRegImpl::stack2reg(i * VMRegImpl::slots_per_word);
     if (is_oop) {
       map->set_oop(reg);
     } else {
@@ -110,6 +111,26 @@
     }
   }
 
+  if (callee_save_info != NULL) {
+    objArrayOop registers = (objArrayOop) RegisterSaveLayout::registers(callee_save_info);
+    arrayOop slots = (arrayOop) RegisterSaveLayout::slots(callee_save_info);
+    for (jint i = 0; i < slots->length(); i++) {
+      oop graal_reg = registers->obj_at(i);
+      jint graal_reg_number = code_Register::number(graal_reg);
+      VMReg hotspot_reg = get_hotspot_reg(graal_reg_number);
+      // HotSpot stack slots are 4 bytes
+      jint graal_slot = ((jint*) slots->base(T_INT))[i];
+      jint hotspot_slot = graal_slot * VMRegImpl::slots_per_word;
+      VMReg hotspot_slot_as_reg = VMRegImpl::stack2reg(hotspot_slot);
+      map->set_callee_saved(hotspot_slot_as_reg, hotspot_reg);
+#ifdef _LP64
+      // (copied from generate_oop_map() in c1_Runtime1_x86.cpp)
+      VMReg hotspot_slot_hi_as_reg = VMRegImpl::stack2reg(hotspot_slot + 1);
+      map->set_callee_saved(hotspot_slot_hi_as_reg, hotspot_reg->next());
+#endif
+    }
+  }
+
   return map;
 }
 
@@ -330,7 +351,7 @@
 }
 
 // constructor used to create a method
-CodeInstaller::CodeInstaller(Handle& comp_result, methodHandle method, GraalEnv::CodeInstallResult& result, nmethod*& nm, Handle installed_code, Handle triggered_deoptimizations) {
+CodeInstaller::CodeInstaller(Handle& comp_result, GraalEnv::CodeInstallResult& result, CodeBlob*& cb, Handle installed_code, Handle triggered_deoptimizations) {
   GraalCompiler::initialize_buffer_blob();
   CodeBuffer buffer(JavaThread::current()->get_buffer_blob());
   jobject comp_result_obj = JNIHandles::make_local(comp_result());
@@ -339,7 +360,7 @@
 
   {
     No_Safepoint_Verifier no_safepoint;
-    initialize_fields(JNIHandles::resolve(comp_result_obj), method);
+    initialize_fields(JNIHandles::resolve(comp_result_obj));
     initialize_buffer(buffer);
     process_exception_handlers();
   }
@@ -347,17 +368,36 @@
   int stack_slots = _total_frame_size / HeapWordSize; // conversion to words
   GrowableArray<jlong>* leaf_graph_ids = get_leaf_graph_ids(comp_result);
 
-  result = GraalEnv::register_method(method, nm, entry_bci, &_offsets, _custom_stack_area_offset, &buffer, stack_slots, _debug_recorder->_oopmaps, &_exception_handler_table,
-    GraalCompiler::instance(), _debug_recorder, _dependencies, NULL, -1, false, leaf_graph_ids, installed_code, triggered_deoptimizations);
+  if (_stubName != NULL) {
+    char* name = strdup(java_lang_String::as_utf8_string(_stubName));
+    cb = RuntimeStub::new_runtime_stub(name,
+                                       &buffer,
+                                       CodeOffsets::frame_never_safe,
+                                       stack_slots,
+                                       _debug_recorder->_oopmaps,
+                                       false);
+    result = GraalEnv::ok;
+  } else {
+    nmethod* nm = NULL;
+    methodHandle method = getMethodFromHotSpotMethod(HotSpotCompilationResult::method(comp_result));
+    result = GraalEnv::register_method(method, nm, entry_bci, &_offsets, _custom_stack_area_offset, &buffer, stack_slots, _debug_recorder->_oopmaps, &_exception_handler_table,
+        GraalCompiler::instance(), _debug_recorder, _dependencies, NULL, -1, false, leaf_graph_ids, installed_code, triggered_deoptimizations);
+    cb = nm;
+  }
 }
 
-void CodeInstaller::initialize_fields(oop comp_result, methodHandle method) {
+void CodeInstaller::initialize_fields(oop comp_result) {
   _comp_result = HotSpotCompilationResult::comp(comp_result);
-  if (!method.is_null()) {
+  oop hotspotJavaMethod = HotSpotCompilationResult::method(comp_result);
+  if (hotspotJavaMethod != NULL) {
+    methodHandle method = getMethodFromHotSpotMethod(hotspotJavaMethod);
     _parameter_count = method->size_of_parameters();
     TRACE_graal_1("installing code for %s", method->name_and_sig_as_C_string());
+  } else {
+    // TODO (ds) not sure if this is correct - only used in OopMap constructor for non-product builds
+    _parameter_count = 0;
   }
-  _name = HotSpotCompilationResult::name(comp_result);
+  _stubName = HotSpotCompilationResult::stubName(comp_result);
   _sites = (arrayOop) HotSpotCompilationResult::sites(comp_result);
   _exception_handlers = (arrayOop) HotSpotCompilationResult::exceptionHandlers(comp_result);
 
@@ -640,8 +680,14 @@
   if (target->is_a(SystemDictionary::HotSpotInstalledCode_klass())) {
     assert(inst->is_jump(), "jump expected");
 
-    nmethod* nm = (nmethod*) HotSpotInstalledCode::nmethod(target);
-    nativeJump_at((address)inst)->set_jump_destination(nm->verified_entry_point());
+    CodeBlob* cb = (CodeBlob*) (address) HotSpotInstalledCode::codeBlob(target);
+    assert(cb != NULL, "npe");
+    if (cb->is_nmethod()) {
+      nmethod* nm = (nmethod*) cb;
+      nativeJump_at((address)inst)->set_jump_destination(nm->verified_entry_point());
+    } else {
+      nativeJump_at((address)inst)->set_jump_destination(cb->code_begin());
+    }
     _instructions->relocate((address)inst, runtime_call_Relocation::spec(), Assembler::call32_operand);
 
     return;
--- a/src/share/vm/graal/graalCodeInstaller.hpp	Mon May 13 16:46:39 2013 +0200
+++ b/src/share/vm/graal/graalCodeInstaller.hpp	Mon May 13 17:11:31 2013 +0200
@@ -51,7 +51,7 @@
   Arena         _arena;
 
   oop           _comp_result;
-  oop           _name;
+  oop           _stubName;
   arrayOop      _sites;
   arrayOop      _exception_handlers;
   CodeOffsets   _offsets;
@@ -76,17 +76,13 @@
 
 public:
 
-  // constructor used to create a method
-  CodeInstaller(Handle& comp_result, methodHandle method, GraalEnv::CodeInstallResult& result, nmethod*& nm, Handle installed_code, Handle triggered_deoptimizations);
-
-  // constructor used to create a stub
-  CodeInstaller(Handle& target_method, BufferBlob*& blob, jlong& id);
+  CodeInstaller(Handle& comp_result, GraalEnv::CodeInstallResult& result, CodeBlob*& cb, Handle installed_code, Handle triggered_deoptimizations);
 
   static address runtime_call_target_address(oop runtime_call);
 
 private:
   // extract the fields of the CompilationResult
-  void initialize_fields(oop target_method, methodHandle method);
+  void initialize_fields(oop target_method);
   void initialize_assumptions(oop target_method);
 
   // perform data and call relocation on the CodeBuffer
--- a/src/share/vm/graal/graalCompiler.cpp	Mon May 13 16:46:39 2013 +0200
+++ b/src/share/vm/graal/graalCompiler.cpp	Mon May 13 17:11:31 2013 +0200
@@ -28,6 +28,7 @@
 #include "graal/graalJavaAccess.hpp"
 #include "graal/graalVMToCompiler.hpp"
 #include "graal/graalCompilerToVM.hpp"
+#include "graal/graalCompilerToGPU.hpp"
 #include "graal/graalEnv.hpp"
 #include "graal/graalRuntime.hpp"
 #include "runtime/arguments.hpp"
@@ -56,7 +57,6 @@
   _deopted_leaf_graph_count = 0;
 
   initialize_buffer_blob();
-  GraalRuntime::initialize(THREAD->get_buffer_blob());
 
   JNIEnv *env = ((JavaThread *) Thread::current())->jni_environment();
   jclass klass = env->FindClass("com/oracle/graal/hotspot/bridge/CompilerToVMImpl");
@@ -65,6 +65,13 @@
     vm_abort(false);
   }
   env->RegisterNatives(klass, CompilerToVM_methods, CompilerToVM_methods_count());
+  
+  klass = env->FindClass("com/oracle/graal/hotspot/bridge/CompilerToGPUImpl");
+  if (klass == NULL) {
+    tty->print_cr("graal CompilerToGPUImpl class not found");
+    vm_abort(false);
+  }
+  env->RegisterNatives(klass, CompilerToGPU_methods, CompilerToGPU_methods_count());
 
   ResourceMark rm;
   HandleMark hm;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/graal/graalCompilerToGPU.cpp	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,124 @@
+/*
+ * 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.
+ */
+
+#include "precompiled.hpp"
+
+#include "graal/graalCompiler.hpp"
+#include "graal/graalEnv.hpp"
+#include "runtime/gpu.hpp"
+
+
+// Entry to native method implementation that transitions current thread to '_thread_in_vm'.
+#define C2V_VMENTRY(result_type, name, signature) \
+  JNIEXPORT result_type JNICALL c2v_ ## name signature { \
+  TRACE_graal_3("CompilerToGPU::" #name); \
+  GRAAL_VM_ENTRY_MARK; \
+
+// Entry to native method implementation that calls a JNI function
+// and hence cannot transition current thread to '_thread_in_vm'.
+#define C2V_ENTRY(result_type, name, signature) \
+  JNIEXPORT result_type JNICALL c2v_ ## name signature { \
+  TRACE_graal_3("CompilerToGPU::" #name); \
+
+#define C2V_END }
+
+
+C2V_VMENTRY(jlong, generateKernel, (JNIEnv *env, jobject, jbyteArray code, jstring name))
+  if (gpu::is_available() == false || gpu::has_gpu_linkage() == false && gpu::is_initialized()) {
+    tty->print_cr("generateKernel - not available / no linkage / not initialized");
+    return 0;
+  }
+  jboolean is_copy;
+  jbyte *bytes = env->GetByteArrayElements(code, &is_copy);
+  jint len = env->GetArrayLength(code);
+  const char *namestr = env->GetStringUTFChars(name, &is_copy);
+  gpu::generate_kernel((unsigned char *)bytes, len, namestr);
+  env->ReleaseByteArrayElements(code, bytes, 0);
+  env->ReleaseStringUTFChars(name, namestr);
+
+  return 42;
+C2V_END
+
+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");
+    return false;
+  }
+  if (gpu::is_initialized()) {
+    tty->print_cr("deviceInit - already initialized");
+    return true;
+  }
+  gpu::initialize_gpu();
+  return gpu::is_initialized();
+C2V_END
+
+C2V_VMENTRY(jboolean, deviceDetach, (JNIEnv *env, jobject))
+return true;
+C2V_END
+
+
+#define CC (char*)  /*cast a literal from (const char*)*/
+#define FN_PTR(f) CAST_FROM_FN_PTR(void*, &(c2v_ ## f))
+
+#define RESOLVED_TYPE         "Lcom/oracle/graal/api/meta/ResolvedJavaType;"
+#define TYPE                  "Lcom/oracle/graal/api/meta/JavaType;"
+#define METHOD                "Lcom/oracle/graal/api/meta/JavaMethod;"
+#define FIELD                 "Lcom/oracle/graal/api/meta/JavaField;"
+#define SIGNATURE             "Lcom/oracle/graal/api/meta/Signature;"
+#define CONSTANT_POOL         "Lcom/oracle/graal/api/meta/ConstantPool;"
+#define CONSTANT              "Lcom/oracle/graal/api/meta/Constant;"
+#define KIND                  "Lcom/oracle/graal/api/meta/Kind;"
+#define LOCAL                  "Lcom/oracle/graal/api/meta/Local;"
+#define RUNTIME_CALL          "Lcom/oracle/graal/api/code/RuntimeCall;"
+#define EXCEPTION_HANDLERS    "[Lcom/oracle/graal/api/meta/ExceptionHandler;"
+#define REFLECT_METHOD        "Ljava/lang/reflect/Method;"
+#define REFLECT_CONSTRUCTOR   "Ljava/lang/reflect/Constructor;"
+#define REFLECT_FIELD         "Ljava/lang/reflect/Field;"
+#define STRING                "Ljava/lang/String;"
+#define OBJECT                "Ljava/lang/Object;"
+#define CLASS                 "Ljava/lang/Class;"
+#define STACK_TRACE_ELEMENT   "Ljava/lang/StackTraceElement;"
+#define HS_RESOLVED_TYPE      "Lcom/oracle/graal/hotspot/meta/HotSpotResolvedObjectType;"
+#define HS_RESOLVED_JAVA_TYPE "Lcom/oracle/graal/hotspot/meta/HotSpotResolvedJavaType;"
+#define HS_RESOLVED_METHOD    "Lcom/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod;"
+#define HS_RESOLVED_FIELD     "Lcom/oracle/graal/hotspot/meta/HotSpotResolvedJavaField;"
+#define HS_COMP_RESULT        "Lcom/oracle/graal/hotspot/HotSpotCompilationResult;"
+#define HS_CONFIG             "Lcom/oracle/graal/hotspot/HotSpotVMConfig;"
+#define HS_METHOD             "Lcom/oracle/graal/hotspot/meta/HotSpotMethod;"
+#define HS_INSTALLED_CODE     "Lcom/oracle/graal/hotspot/meta/HotSpotInstalledCode;"
+#define METHOD_DATA           "Lcom/oracle/graal/hotspot/meta/HotSpotMethodData;"
+#define METASPACE_METHOD      "J"
+#define METASPACE_METHOD_DATA "J"
+#define NMETHOD               "J"
+#define GPUSPACE_METHOD       "J"
+
+JNINativeMethod CompilerToGPU_methods[] = {
+  {CC"generateKernel", CC"([B" STRING ")"GPUSPACE_METHOD, FN_PTR(generateKernel)},
+  {CC"deviceInit",     CC"()Z",                           FN_PTR(deviceInit)},
+  {CC"deviceDetach",   CC"()Z",                           FN_PTR(deviceDetach)},
+};
+
+int CompilerToGPU_methods_count() {
+  return sizeof(CompilerToGPU_methods) / sizeof(JNINativeMethod);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/graal/graalCompilerToGPU.hpp	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef SHARE_VM_GRAAL_GRAAL_COMPILER_TO_GPU_HPP
+#define SHARE_VM_GRAAL_GRAAL_COMPILER_TO_GPU_HPP
+
+#include "prims/jni.h"
+
+extern JNINativeMethod CompilerToGPU_methods[];
+int CompilerToGPU_methods_count();
+
+
+#endif // SHARE_VM_GRAAL_GRAAL_COMPILER_TO_GPU_HPP
--- a/src/share/vm/graal/graalCompilerToVM.cpp	Mon May 13 16:46:39 2013 +0200
+++ b/src/share/vm/graal/graalCompilerToVM.cpp	Mon May 13 17:11:31 2013 +0200
@@ -276,6 +276,10 @@
   HotSpotResolvedJavaMethod::set_name(hotspot_method, name());
   HotSpotResolvedJavaMethod::set_codeSize(hotspot_method, method->code_size());
   HotSpotResolvedJavaMethod::set_exceptionHandlerCount(hotspot_method, method->exception_table_length());
+  HotSpotResolvedJavaMethod::set_callerSensitive(hotspot_method, method->caller_sensitive());
+  HotSpotResolvedJavaMethod::set_forceInline(hotspot_method, method->force_inline());
+  HotSpotResolvedJavaMethod::set_dontInline(hotspot_method, method->dont_inline());
+  HotSpotResolvedJavaMethod::set_ignoredBySecurityStackWalk(hotspot_method, method->is_ignored_by_security_stack_walk());
 C2V_END
 
 C2V_VMENTRY(jboolean, isMethodCompilable,(JNIEnv *, jobject, jlong metaspace_method))
@@ -387,35 +391,52 @@
 
   oop result = NULL;
   constantTag tag = cp->tag_at(index);
-  if (tag.is_int()) {
-    result = VMToCompiler::createConstant(Kind::Int(), cp->int_at(index), CHECK_0);
-  } else if (tag.is_long()) {
-    result = VMToCompiler::createConstant(Kind::Long(), cp->long_at(index), CHECK_0);
-  } else if (tag.is_float()) {
-    result = VMToCompiler::createConstantFloat(cp->float_at(index), CHECK_0);
-  } else if (tag.is_double()) {
-    result = VMToCompiler::createConstantDouble(cp->double_at(index), CHECK_0);
-  } else if (tag.is_string()) {
-    oop string = NULL;
-    if (cp->is_pseudo_string_at(index)) {
-      int obj_index = cp->cp_to_object_index(index);
-      string = cp->pseudo_string_at(index, obj_index);
-    } else {
-      string = cp->string_at(index, THREAD);
-      if (HAS_PENDING_EXCEPTION) {
-        CLEAR_PENDING_EXCEPTION;
-        // TODO: Gracefully exit compilation.
-        fatal("out of memory during compilation!");
-        return NULL;
-      }
+
+  switch (tag.value()) {
+  case JVM_CONSTANT_Integer:
+    result = VMToCompiler::createConstant(Kind::Int(), cp->int_at(index), CHECK_NULL);
+    break;
+
+  case JVM_CONSTANT_Long:
+    result = VMToCompiler::createConstant(Kind::Long(), cp->long_at(index), CHECK_NULL);
+    break;
+
+  case JVM_CONSTANT_Float:
+    result = VMToCompiler::createConstantFloat(cp->float_at(index), CHECK_NULL);
+    break;
+
+  case JVM_CONSTANT_Double:
+    result = VMToCompiler::createConstantDouble(cp->double_at(index), CHECK_NULL);
+    break;
+
+  case JVM_CONSTANT_Class:
+  case JVM_CONSTANT_UnresolvedClass:
+  case JVM_CONSTANT_UnresolvedClassInError:
+    {
+      Handle type = GraalCompiler::get_JavaType(cp, index, cp->pool_holder(), CHECK_NULL);
+      result = type();
+      break;
     }
-    result = VMToCompiler::createConstantObject(string, CHECK_0);
-  } else if (tag.is_klass() || tag.is_unresolved_klass()) {
-    Handle type = GraalCompiler::get_JavaType(cp, index, cp->pool_holder(), CHECK_NULL);
-    result = type();
-  } else {
-    tty->print("unknown constant pool tag (%s) at cpi %d in %s: ", tag.internal_name(), index, cp->pool_holder()->name()->as_C_string());
-    ShouldNotReachHere();
+
+  case JVM_CONSTANT_String:
+    {
+      oop result_oop = cp->resolve_possibly_cached_constant_at(index, CHECK_NULL);
+      result = VMToCompiler::createConstantObject(result_oop, CHECK_NULL);
+      break;
+    }
+
+  case JVM_CONSTANT_MethodHandle:
+  case JVM_CONSTANT_MethodHandleInError:
+  case JVM_CONSTANT_MethodType:
+  case JVM_CONSTANT_MethodTypeInError:
+    {
+      oop result_oop = cp->resolve_constant_at(index, CHECK_NULL);
+      result = VMToCompiler::createConstantObject(result_oop, CHECK_NULL);
+      break;
+    }
+
+  default:
+    fatal(err_msg_res("unknown constant pool tag %s at cpi %d in %s", tag.internal_name(), index, cp->pool_holder()->name()->as_C_string()));
   }
 
   return JNIHandles::make_local(THREAD, result);
@@ -585,8 +606,8 @@
   return JNIHandles::make_local(field_array());
 C2V_END
 
-C2V_VMENTRY(jlong, getMaxCallTargetOffset, (JNIEnv *env, jobject, jlong stub))
-  address target_addr = (address) stub;
+C2V_VMENTRY(jlong, getMaxCallTargetOffset, (JNIEnv *env, jobject, jlong addr))
+  address target_addr = (address) addr;
   if (target_addr != 0x0) {
     int64_t off_low = (int64_t)target_addr - ((int64_t)CodeCache::low_bound() + sizeof(int));
     int64_t off_high = (int64_t)target_addr - ((int64_t)CodeCache::high_bound() + sizeof(int));
@@ -612,24 +633,18 @@
   return id;
 }
 
-BasicType basicTypes[] = { T_BOOLEAN, T_BYTE, T_SHORT, T_CHAR, T_INT, T_FLOAT, T_LONG, T_DOUBLE, T_OBJECT };
-int basicTypeCount = sizeof(basicTypes) / sizeof(BasicType);
-
 C2V_ENTRY(void, initializeConfiguration, (JNIEnv *env, jobject, jobject config))
 
 #define set_boolean(name, value) do { env->SetBooleanField(config, getFieldID(env, config, name, "Z"), value); } while (0)
 #define set_int(name, value) do { env->SetIntField(config, getFieldID(env, config, name, "I"), value); } while (0)
 #define set_long(name, value) do { env->SetLongField(config, getFieldID(env, config, name, "J"), value); } while (0)
-#define set_stub(name, value) do { set_long(name, (jlong) value); } while (0)
+#define set_address(name, value) do { set_long(name, (jlong) value); } while (0)
 #define set_object(name, value) do { env->SetObjectField(config, getFieldID(env, config, name, "Ljava/lang/Object;"), value); } while (0)
 #define set_int_array(name, value) do { env->SetObjectField(config, getFieldID(env, config, name, "[I"), value); } while (0)
 
   guarantee(HeapWordSize == sizeof(char*), "Graal assumption that HeadWordSize == machine word size is wrong");
-#ifdef _WIN64
-  set_boolean("windowsOs", true);
-#else
-  set_boolean("windowsOs", false);
-#endif
+
+  set_boolean("cAssertions", DEBUG_ONLY(true) NOT_DEBUG(false));
   set_boolean("verifyOops", VerifyOops);
   set_boolean("ciTime", CITime);
   set_boolean("compileTheWorld", CompileTheWorld);
@@ -661,6 +676,7 @@
   set_int("threadTlabTopOffset", in_bytes(JavaThread::tlab_top_offset()));
   set_int("threadTlabEndOffset", in_bytes(JavaThread::tlab_end_offset()));
   set_int("threadObjectOffset", in_bytes(JavaThread::threadObj_offset()));
+  set_int("threadIsMethodHandleReturnOffset", in_bytes(JavaThread::is_method_handle_return_offset()));
   set_int("osThreadOffset", in_bytes(JavaThread::osthread_offset()));
   set_int("osThreadInterruptedOffset", in_bytes(OSThread::interrupted_offset()));
   set_int("unlockedMask", (int) markOopDesc::unlocked_value);
@@ -699,6 +715,7 @@
   set_int("arrayKlassComponentMirrorOffset", in_bytes(ArrayKlass::component_mirror_offset()));
 
 
+  set_int("pendingExceptionOffset", in_bytes(ThreadShadow::pending_exception_offset()));
   set_int("pendingDeoptimizationOffset", in_bytes(ThreadShadow::pending_deoptimization_offset()));
 
   set_int("metaspaceArrayLengthOffset", Array<Klass*>::length_offset_in_bytes());
@@ -721,6 +738,10 @@
   set_int("threadTlabStartOffset", in_bytes(JavaThread::tlab_start_offset()));
   set_int("threadTlabSizeOffset", in_bytes(JavaThread::tlab_size_offset()));
   set_int("threadAllocatedBytesOffset", in_bytes(JavaThread::allocated_bytes_offset()));
+  set_int("threadLastJavaSpOffset", in_bytes(JavaThread::last_Java_sp_offset()));
+  set_int("threadLastJavaFpOffset", in_bytes(JavaThread::last_Java_fp_offset()));
+  set_int("threadLastJavaPcOffset", in_bytes(JavaThread::last_Java_pc_offset()));
+  set_int("threadObjectResultOffset", in_bytes(JavaThread::vm_result_offset()));
   set_int("tlabSlowAllocationsOffset", in_bytes(JavaThread::tlab_slow_allocations_offset()));
   set_int("tlabFastRefillWasteOffset", in_bytes(JavaThread::tlab_fast_refill_waste_offset()));
   set_int("tlabNumberOfRefillsOffset", in_bytes(JavaThread::tlab_number_of_refills_offset()));
@@ -730,6 +751,10 @@
   set_boolean("tlabStats", TLABStats);
   set_boolean("inlineContiguousAllocationSupported", !CMSIncrementalMode && Universe::heap()->supports_inline_contig_alloc());
 
+  set_long("verifyOopCounterAddress", (jlong)(address) StubRoutines::verify_oop_count_addr());
+  set_long("verifyOopMask", Universe::verify_oop_mask());
+  set_long("verifyOopBits", Universe::verify_oop_bits());
+
   set_long("arrayPrototypeMarkWord", (intptr_t)markOopDesc::prototype());
   set_int("layoutHelperLog2ElementSizeShift", Klass::_lh_log2_element_size_shift);
   set_int("layoutHelperLog2ElementSizeMask", Klass::_lh_log2_element_size_mask);
@@ -741,43 +766,39 @@
   set_int("layoutHelperHeaderSizeMask", Klass::_lh_header_size_mask);
   set_int("layoutHelperOffset", in_bytes(Klass::layout_helper_offset()));
 
-
-  set_stub("wbPreCallStub", GraalRuntime::entry_for(GraalRuntime::wb_pre_call_id));
-  set_stub("wbPostCallStub", GraalRuntime::entry_for(GraalRuntime::wb_post_call_id));
+  set_address("inlineCacheMissStub", SharedRuntime::get_ic_miss_stub());
+  set_address("handleDeoptStub", SharedRuntime::deopt_blob()->unpack());
+  set_address("javaTimeMillisStub", CAST_FROM_FN_PTR(address, os::javaTimeMillis));
+  set_address("javaTimeNanosStub", CAST_FROM_FN_PTR(address, os::javaTimeNanos));
+  set_address("arithmeticSinStub", CAST_FROM_FN_PTR(address, SharedRuntime::dsin));
+  set_address("arithmeticCosStub", CAST_FROM_FN_PTR(address, SharedRuntime::dcos));
+  set_address("arithmeticTanStub", CAST_FROM_FN_PTR(address, SharedRuntime::dtan));
+  set_address("aescryptEncryptBlockStub", StubRoutines::aescrypt_encryptBlock());
+  set_address("aescryptDecryptBlockStub", StubRoutines::aescrypt_decryptBlock());
+  set_address("cipherBlockChainingEncryptAESCryptStub", StubRoutines::cipherBlockChaining_encryptAESCrypt());
+  set_address("cipherBlockChainingDecryptAESCryptStub", StubRoutines::cipherBlockChaining_decryptAESCrypt());
 
-  set_stub("newInstanceStub", GraalRuntime::entry_for(GraalRuntime::new_instance_id));
-  set_stub("newArrayStub", GraalRuntime::entry_for(GraalRuntime::new_array_id));
-  set_stub("newMultiArrayStub", GraalRuntime::entry_for(GraalRuntime::new_multi_array_id));
-  set_stub("identityHashCodeStub", GraalRuntime::entry_for(GraalRuntime::identity_hash_code_id));
-  set_stub("threadIsInterruptedStub", GraalRuntime::entry_for(GraalRuntime::thread_is_interrupted_id));
-  set_stub("inlineCacheMissStub", SharedRuntime::get_ic_miss_stub());
-  set_stub("handleExceptionStub", GraalRuntime::entry_for(GraalRuntime::handle_exception_nofpu_id));
-  set_stub("handleDeoptStub", SharedRuntime::deopt_blob()->unpack());
-  set_stub("monitorEnterStub", GraalRuntime::entry_for(GraalRuntime::monitorenter_id));
-  set_stub("monitorExitStub", GraalRuntime::entry_for(GraalRuntime::monitorexit_id));
-  set_stub("verifyOopStub", GraalRuntime::entry_for(GraalRuntime::verify_oop_id));
-  set_stub("vmErrorStub", GraalRuntime::entry_for(GraalRuntime::vm_error_id));
-  set_stub("deoptimizeStub", SharedRuntime::deopt_blob()->uncommon_trap());
-  set_stub("unwindExceptionStub", GraalRuntime::entry_for(GraalRuntime::unwind_exception_call_id));
-  set_stub("osrMigrationEndStub", GraalRuntime::entry_for(GraalRuntime::OSR_migration_end_id));
-  set_stub("registerFinalizerStub", GraalRuntime::entry_for(GraalRuntime::register_finalizer_id));
-  set_stub("createNullPointerExceptionStub", GraalRuntime::entry_for(GraalRuntime::create_null_pointer_exception_id));
-  set_stub("createOutOfBoundsExceptionStub", GraalRuntime::entry_for(GraalRuntime::create_out_of_bounds_exception_id));
-  set_stub("javaTimeMillisStub", CAST_FROM_FN_PTR(address, os::javaTimeMillis));
-  set_stub("javaTimeNanosStub", CAST_FROM_FN_PTR(address, os::javaTimeNanos));
-  set_stub("arithmeticFremStub", GraalRuntime::entry_for(GraalRuntime::arithmetic_frem_id));
-  set_stub("arithmeticDremStub", GraalRuntime::entry_for(GraalRuntime::arithmetic_drem_id));
-  set_stub("arithmeticSinStub", CAST_FROM_FN_PTR(address, SharedRuntime::dsin));
-  set_stub("arithmeticCosStub", CAST_FROM_FN_PTR(address, SharedRuntime::dcos));
-  set_stub("arithmeticTanStub", CAST_FROM_FN_PTR(address, SharedRuntime::dtan));
-  set_stub("logPrimitiveStub", GraalRuntime::entry_for(GraalRuntime::log_primitive_id));
-  set_stub("logObjectStub", GraalRuntime::entry_for(GraalRuntime::log_object_id));
-  set_stub("logPrintfStub", GraalRuntime::entry_for(GraalRuntime::log_printf_id));
-  set_stub("stubPrintfStub", GraalRuntime::entry_for(GraalRuntime::stub_printf_id));
-  set_stub("aescryptEncryptBlockStub", StubRoutines::aescrypt_encryptBlock());
-  set_stub("aescryptDecryptBlockStub", StubRoutines::aescrypt_decryptBlock());
-  set_stub("cipherBlockChainingEncryptAESCryptStub", StubRoutines::cipherBlockChaining_encryptAESCrypt());
-  set_stub("cipherBlockChainingDecryptAESCryptStub", StubRoutines::cipherBlockChaining_decryptAESCrypt());
+  set_address("newInstanceAddress", GraalRuntime::new_instance);
+  set_address("newArrayAddress", GraalRuntime::new_array);
+  set_address("newMultiArrayAddress", GraalRuntime::new_multi_array);
+  set_address("registerFinalizerAddress", SharedRuntime::register_finalizer);
+  set_address("threadIsInterruptedAddress", GraalRuntime::thread_is_interrupted);
+  set_address("uncommonTrapStub", SharedRuntime::deopt_blob()->uncommon_trap());
+  set_address("vmMessageAddress", GraalRuntime::vm_message);
+  set_address("identityHashCodeAddress", GraalRuntime::identity_hash_code);
+  set_address("exceptionHandlerForPcAddress", GraalRuntime::exception_handler_for_pc);
+  set_address("exceptionHandlerForReturnAddressAddress", SharedRuntime::exception_handler_for_return_address);
+  set_address("osrMigrationEndAddress", SharedRuntime::OSR_migration_end);
+  set_address("monitorenterAddress", GraalRuntime::monitorenter);
+  set_address("monitorexitAddress", GraalRuntime::monitorexit);
+  set_address("createNullPointerExceptionAddress", GraalRuntime::create_null_exception);
+  set_address("createOutOfBoundsExceptionAddress", GraalRuntime::create_out_of_bounds_exception);
+  set_address("logPrimitiveAddress", GraalRuntime::log_primitive);
+  set_address("logObjectAddress", GraalRuntime::log_object);
+  set_address("logPrintfAddress", GraalRuntime::log_printf);
+  set_address("vmErrorAddress", GraalRuntime::vm_error);
+  set_address("writeBarrierPreAddress", GraalRuntime::write_barrier_pre);
+  set_address("writeBarrierPostAddress", GraalRuntime::write_barrier_post);
 
   set_int("deoptReasonNone", Deoptimization::Reason_none);
   set_int("deoptReasonNullCheck", Deoptimization::Reason_null_check);
@@ -792,6 +813,7 @@
   set_int("deoptReasonJsrMismatch", Deoptimization::Reason_jsr_mismatch);
   set_int("deoptReasonDiv0Check", Deoptimization::Reason_div0_check);
   set_int("deoptReasonConstraint", Deoptimization::Reason_constraint);
+  set_int("deoptReasonLoopLimitCheck", Deoptimization::Reason_loop_limit_check);
 
   set_int("deoptActionNone", Deoptimization::Action_none);
   set_int("deoptActionMaybeRecompile", Deoptimization::Action_maybe_recompile);
@@ -849,12 +871,12 @@
   ResourceMark rm;
   HandleMark hm;
   Handle compResultHandle = JNIHandles::resolve(compResult);
-  nmethod* nm = NULL;
-  methodHandle method = getMethodFromHotSpotMethod(HotSpotCompilationResult::method(compResult));
+  CodeBlob* cb = NULL;
   Handle installed_code_handle = JNIHandles::resolve(installed_code);
   Handle triggered_deoptimizations_handle = JNIHandles::resolve(triggered_deoptimizations);
   GraalEnv::CodeInstallResult result;
-  CodeInstaller installer(compResultHandle, method, result, nm, installed_code_handle, triggered_deoptimizations_handle);
+
+  CodeInstaller installer(compResultHandle, result, cb, installed_code_handle, triggered_deoptimizations_handle);
 
   if (PrintCodeCacheOnCompilation) {
     stringStream s;
@@ -868,13 +890,14 @@
   }
 
   if (result != GraalEnv::ok) {
-    assert(nm == NULL, "should be");
+    assert(cb == NULL, "should be");
   } else {
     if (!installed_code_handle.is_null()) {
       assert(installed_code_handle->is_a(HotSpotInstalledCode::klass()), "wrong type");
-      HotSpotInstalledCode::set_nmethod(installed_code_handle, (jlong) nm);
+      HotSpotInstalledCode::set_codeBlob(installed_code_handle, (jlong) cb);
       HotSpotInstalledCode::set_method(installed_code_handle, HotSpotCompilationResult::method(compResult));
-      HotSpotInstalledCode::set_start(installed_code_handle, (jlong) nm->code_begin());
+      HotSpotInstalledCode::set_start(installed_code_handle, (jlong) cb->code_begin());
+      nmethod* nm = cb->as_nmethod_or_null();
       assert(nm == NULL || !installed_code_handle->is_scavengable() || nm->on_scavenge_root_list(), "nm should be scavengable if installed_code is scavengable");
     }
   }
@@ -886,30 +909,53 @@
   method->clear_queued_for_compilation();
 C2V_END
 
-C2V_VMENTRY(jobject, getCode, (JNIEnv *jniEnv, jobject,  jlong metaspace_nmethod))
+C2V_VMENTRY(jobject, getCode, (JNIEnv *jniEnv, jobject,  jlong codeBlob))
+  ResourceMark rm;
+  HandleMark hm;
+
+  CodeBlob* cb = (CodeBlob*) (address) codeBlob;
+  if (cb == NULL) {
+    return NULL;
+  }
+  if (cb->is_nmethod()) {
+    nmethod* nm = (nmethod*) cb;
+    if (!nm->is_alive()) {
+      return NULL;
+    }
+  }
+  int length = cb->code_size();
+  arrayOop codeCopy = oopFactory::new_byteArray(length, CHECK_0);
+  memcpy(codeCopy->base(T_BYTE), cb->code_begin(), length);
+  return JNIHandles::make_local(codeCopy);
+C2V_END
+
+C2V_VMENTRY(jobject, disassembleCodeBlob, (JNIEnv *jniEnv, jobject, jlong codeBlob))
   ResourceMark rm;
   HandleMark hm;
 
-  nmethod* nm = (nmethod*) (address) metaspace_nmethod;
-  if (nm == NULL || !nm->is_alive()) {
+  CodeBlob* cb = (CodeBlob*) (address) codeBlob;
+  if (cb == NULL) {
     return NULL;
   }
-  int length = nm->code_size();
-  arrayOop codeCopy = oopFactory::new_byteArray(length, CHECK_0);
-  memcpy(codeCopy->base(T_BYTE), nm->code_begin(), length);
-  return JNIHandles::make_local(codeCopy);
-C2V_END
 
-C2V_VMENTRY(jobject, disassembleNMethod, (JNIEnv *jniEnv, jobject, jlong metaspace_nmethod))
-  ResourceMark rm;
-  HandleMark hm;
-
-  nmethod* nm = (nmethod*) (address) metaspace_nmethod;
-  if (nm == NULL || !nm->is_alive()) {
-    return NULL;
+  // We don't want the stringStream buffer to resize during disassembly as it
+  // uses scoped resource memory. If a nested function called during disassembly uses
+  // a ResourceMark and the buffer expands within the scope of the mark,
+  // the buffer becomes garbage when that scope is exited. Experience shows that
+  // the disassembled code is typically about 10x the code size so a fixed buffer
+  // sized to 20x code size should be sufficient.
+  int bufferSize = cb->code_size() * 20;
+  char* buffer = NEW_RESOURCE_ARRAY(char, bufferSize);
+  stringStream st(buffer, bufferSize);
+  if (cb->is_nmethod()) {
+    nmethod* nm = (nmethod*) cb;
+    if (!nm->is_alive()) {
+      return NULL;
+    }
+    Disassembler::decode(nm, &st);
+  } else {
+    Disassembler::decode(cb, &st);
   }
-  stringStream(st);
-  Disassembler::decode(nm, &st);
 
   Handle result = java_lang_String::create_from_platform_dependent_str(st.as_string(), CHECK_NULL);
   return JNIHandles::make_local(result());
@@ -924,11 +970,11 @@
   return JNIHandles::make_local(element);
 C2V_END
 
-C2V_VMENTRY(jobject, executeCompiledMethodVarargs, (JNIEnv *env, jobject, jobject args, jlong nativeMethod))
+C2V_VMENTRY(jobject, executeCompiledMethodVarargs, (JNIEnv *env, jobject, jobject args, jlong nmethodValue))
   ResourceMark rm;
   HandleMark hm;
 
-  nmethod* nm = (nmethod*) (address) nativeMethod;
+  nmethod* nm = (nmethod*) (address) nmethodValue;
   methodHandle mh = nm->method();
   Symbol* signature = mh->signature();
   JavaCallArguments jca(mh->size_of_parameters());
@@ -953,6 +999,7 @@
   Method* method = asMethod(metaspace_method);
   assert(!InstanceKlass::cast(method->method_holder())->is_interface(), "vtableEntryOffset cannot be called for interface methods");
   assert(InstanceKlass::cast(method->method_holder())->is_linked(), "vtableEntryOffset cannot be called is holder is not linked");
+  assert(method->vtable_index() >= 0, "vtable entry offset should not be used");
 
   // get entry offset in words
   int vtable_entry_offset = InstanceKlass::vtable_start_offset() + method->vtable_index() * vtableEntry::size();
@@ -962,6 +1009,11 @@
   return vtable_entry_offset;
 C2V_END
 
+C2V_VMENTRY(jboolean, hasVtableEntry, (JNIEnv *, jobject, jlong metaspace_method))
+  Method* method = asMethod(metaspace_method);
+  return method->vtable_index() >= 0;
+C2V_END
+
 C2V_VMENTRY(jobject, getDeoptedLeafGraphIds, (JNIEnv *, jobject))
 
   // the contract for this method is as follows:
@@ -1129,6 +1181,7 @@
   {CC"getInvocationCount",            CC"("METASPACE_METHOD")I",                                        FN_PTR(getInvocationCount)},
   {CC"getCompiledCodeSize",           CC"("METASPACE_METHOD")I",                                        FN_PTR(getCompiledCodeSize)},
   {CC"getVtableEntryOffset",          CC"("METASPACE_METHOD")I",                                        FN_PTR(getVtableEntryOffset)},
+  {CC"hasVtableEntry",                CC"("METASPACE_METHOD")Z",                                        FN_PTR(hasVtableEntry)},
   {CC"constantPoolLength",            CC"("HS_RESOLVED_TYPE")I",                                        FN_PTR(constantPoolLength)},
   {CC"lookupType",                    CC"("STRING HS_RESOLVED_TYPE"Z)"TYPE,                             FN_PTR(lookupType)},
   {CC"lookupConstantInPool",          CC"("HS_RESOLVED_TYPE"I)"OBJECT,                                  FN_PTR(lookupConstantInPool)},
@@ -1150,7 +1203,7 @@
   {CC"initializeConfiguration",       CC"("HS_CONFIG")V",                                               FN_PTR(initializeConfiguration)},
   {CC"installCode0",                  CC"("HS_COMP_RESULT HS_INSTALLED_CODE"[Z)I",                      FN_PTR(installCode0)},
   {CC"getCode",                       CC"(J)[B",                                                        FN_PTR(getCode)},
-  {CC"disassembleNMethod",            CC"(J)"STRING,                                                    FN_PTR(disassembleNMethod)},
+  {CC"disassembleCodeBlob",           CC"(J)"STRING,                                                    FN_PTR(disassembleCodeBlob)},
   {CC"executeCompiledMethodVarargs",  CC"(["OBJECT NMETHOD")"OBJECT,                                    FN_PTR(executeCompiledMethodVarargs)},
   {CC"getDeoptedLeafGraphIds",        CC"()[J",                                                         FN_PTR(getDeoptedLeafGraphIds)},
   {CC"getLineNumberTable",            CC"("HS_RESOLVED_METHOD")[J",                                     FN_PTR(getLineNumberTable)},
--- a/src/share/vm/graal/graalJavaAccess.cpp	Mon May 13 16:46:39 2013 +0200
+++ b/src/share/vm/graal/graalJavaAccess.cpp	Mon May 13 17:11:31 2013 +0200
@@ -31,13 +31,8 @@
 void compute_offset(int &dest_offset, Klass* klass, const char* name, const char* signature, bool static_field) {
   Symbol* name_symbol = SymbolTable::probe(name, (int)strlen(name));
   Symbol* signature_symbol = SymbolTable::probe(signature, (int)strlen(signature));
-#ifndef PRODUCT
-  if (name_symbol == NULL) {
-    tty->print_cr("symbol with name %s was not found in symbol table (klass=%s)", name, klass->name()->as_C_string());
-  }
-#endif
   if (name_symbol == NULL || signature_symbol == NULL) {
-    guarantee(false, err_msg("symbol not found - class layout of %s changed?", klass->name()->as_C_string()));
+    guarantee(false, err_msg("symbol with name %s and signature %s was not found in symbol table (klass=%s)", name, signature, klass->name()->as_C_string()));
   }
 
   InstanceKlass* ik = InstanceKlass::cast(klass);
--- a/src/share/vm/graal/graalJavaAccess.hpp	Mon May 13 16:46:39 2013 +0200
+++ b/src/share/vm/graal/graalJavaAccess.hpp	Mon May 13 17:11:31 2013 +0200
@@ -58,6 +58,10 @@
     long_field(HotSpotResolvedJavaMethod, metaspaceMethod)                                                                                                     \
     int_field(HotSpotResolvedJavaMethod, codeSize)                                                                                                             \
     int_field(HotSpotResolvedJavaMethod, exceptionHandlerCount)                                                                                                \
+    boolean_field(HotSpotResolvedJavaMethod, callerSensitive)                                                                                                  \
+    boolean_field(HotSpotResolvedJavaMethod, forceInline)                                                                                                      \
+    boolean_field(HotSpotResolvedJavaMethod, dontInline)                                                                                                       \
+    boolean_field(HotSpotResolvedJavaMethod, ignoredBySecurityStackWalk)                                                                                       \
   end_class                                                                                                                                                    \
   start_class(HotSpotMethodData)                                                                                                                               \
     long_field(HotSpotMethodData, metaspaceMethodData)                                                                                                         \
@@ -73,7 +77,7 @@
     int_field(HotSpotResolvedJavaField, flags)                                                                                                                 \
   end_class                                                                                                                                                    \
   start_class(HotSpotInstalledCode)                                                                                                                            \
-    long_field(HotSpotInstalledCode, nmethod)                                                                                                                  \
+    long_field(HotSpotInstalledCode, codeBlob)                                                                                                                 \
     oop_field(HotSpotInstalledCode, method, "Lcom/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod;")                                                       \
     long_field(HotSpotInstalledCode, start)                                                                                                                    \
     boolean_field(HotSpotInstalledCode, isDefault)                                                                                                             \
@@ -81,7 +85,7 @@
   start_class(HotSpotCompilationResult)                                                                                                                        \
     oop_field(HotSpotCompilationResult, comp, "Lcom/oracle/graal/api/code/CompilationResult;")                                                                 \
     oop_field(HotSpotCompilationResult, method, "Lcom/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod;")                                                   \
-    oop_field(HotSpotCompilationResult, name, "Ljava/lang/String;")                                                                                            \
+    oop_field(HotSpotCompilationResult, stubName, "Ljava/lang/String;")                                                                                        \
     int_field(HotSpotCompilationResult, entryBCI)                                                                                                              \
     oop_field(HotSpotCompilationResult, sites, "[Lcom/oracle/graal/api/code/CompilationResult$Site;")                                                          \
     oop_field(HotSpotCompilationResult, exceptionHandlers, "[Lcom/oracle/graal/api/code/CompilationResult$ExceptionHandler;")                                  \
@@ -162,9 +166,14 @@
     oop_field(DebugInfo, bytecodePosition, "Lcom/oracle/graal/api/code/BytecodePosition;")                                                                     \
     oop_field(DebugInfo, registerRefMap, "Ljava/util/BitSet;")                                                                                                 \
     oop_field(DebugInfo, frameRefMap, "Ljava/util/BitSet;")                                                                                                    \
+    oop_field(DebugInfo, calleeSaveInfo, "Lcom/oracle/graal/api/code/RegisterSaveLayout;")                                                                     \
   end_class                                                                                                                                                    \
-  start_class(GraalBitMap)                                                                                                                                     \
-    oop_field(GraalBitMap, words, "[J")                                                                                                                        \
+  start_class(RegisterSaveLayout)                                                                                                                              \
+    oop_field(RegisterSaveLayout, registers, "[Lcom/oracle/graal/api/code/Register;")                                                                          \
+    oop_field(RegisterSaveLayout, slots, "[I")                                                                                                                 \
+  end_class                                                                                                                                                    \
+  start_class(BitSet)                                                                                                                                          \
+    oop_field(BitSet, words, "[J")                                                                                                                             \
   end_class                                                                                                                                                    \
   start_class(BytecodeFrame)                                                                                                                                   \
     oop_field(BytecodeFrame, values, "[Lcom/oracle/graal/api/meta/Value;")                                                                                     \
--- a/src/share/vm/graal/graalRuntime.cpp	Mon May 13 16:46:39 2013 +0200
+++ b/src/share/vm/graal/graalRuntime.cpp	Mon May 13 17:11:31 2013 +0200
@@ -30,44 +30,6 @@
 #include "runtime/biasedLocking.hpp"
 #include "runtime/interfaceSupport.hpp"
 #include "utilities/debug.hpp"
-// Implementation of GraalStubAssembler
-
-GraalStubAssembler::GraalStubAssembler(CodeBuffer* code, const char * name, int stub_id) : MacroAssembler(code) {
-  _name = name;
-  _must_gc_arguments = false;
-  _frame_size = no_frame_size;
-  _num_rt_args = 0;
-  _stub_id = stub_id;
-}
-
-
-void GraalStubAssembler::set_info(const char* name, bool must_gc_arguments) {
-  _name = name;
-  _must_gc_arguments = must_gc_arguments;
-}
-
-
-void GraalStubAssembler::set_frame_size(int size) {
-  if (_frame_size == no_frame_size) {
-    _frame_size = size;
-  }
-  assert(_frame_size == size, "can't change the frame size");
-}
-
-
-void GraalStubAssembler::set_num_rt_args(int args) {
-  if (_num_rt_args == 0) {
-    _num_rt_args = args;
-  }
-  assert(_num_rt_args == args, "can't change the number of args");
-}
-
-// Implementation of GraalRuntime
-
-CodeBlob* GraalRuntime::_blobs[GraalRuntime::number_of_ids];
-const char *GraalRuntime::_blob_names[] = {
-  GRAAL_STUBS(STUB_NAME, LAST_STUB_NAME)
-};
 
 // Simple helper to see if the caller of a runtime stub which
 // entered the VM has been deoptimized
@@ -93,145 +55,6 @@
   }
 }
 
-static bool setup_code_buffer(CodeBuffer* code) {
-  // Preinitialize the consts section to some large size:
-  int locs_buffer_size = 1 * (relocInfo::length_limit + sizeof(relocInfo));
-  char* locs_buffer = NEW_RESOURCE_ARRAY(char, locs_buffer_size);
-  code->insts()->initialize_shared_locs((relocInfo*)locs_buffer,
-                                        locs_buffer_size / sizeof(relocInfo));
-
-  // Global stubs have neither constants nor local stubs
-  code->initialize_consts_size(0);
-  code->initialize_stubs_size(0);
-
-  return true;
-}
-
-void GraalRuntime::generate_blob_for(BufferBlob* buffer_blob, StubID id) {
-  assert(0 <= id && id < number_of_ids, "illegal stub id");
-  ResourceMark rm;
-  // create code buffer for code storage
-  CodeBuffer code(buffer_blob);
-
-  setup_code_buffer(&code);
-
-  // create assembler for code generation
-  GraalStubAssembler* sasm = new GraalStubAssembler(&code, name_for(id), id);
-  // generate code for runtime stub
-  OopMapSet* oop_maps;
-  oop_maps = generate_code_for(id, sasm);
-  assert(oop_maps == NULL || sasm->frame_size() != GraalStubAssembler::no_frame_size,
-         "if stub has an oop map it must have a valid frame size");
-
-#ifdef ASSERT
-  // Make sure that stubs that need oopmaps have them
-  switch (id) {
-    // These stubs don't need to have an oopmap
-#if defined(SPARC) || defined(PPC)
-    case handle_exception_nofpu_id:  // Unused on sparc
-#endif
-    case verify_oop_id:
-    case unwind_exception_call_id:
-    case OSR_migration_end_id:
-    case arithmetic_frem_id:
-    case arithmetic_drem_id:
-      break;
-    // All other stubs should have oopmaps
-    default:
-      assert(oop_maps != NULL, "must have an oopmap");
-  }
-#endif
-
-  // align so printing shows nop's instead of random code at the end (SimpleStubs are aligned)
-  sasm->align(BytesPerWord);
-  // make sure all code is in code buffer
-  sasm->flush();
-  // create blob - distinguish a few special cases
-  CodeBlob* blob = RuntimeStub::new_runtime_stub(name_for(id),
-                                                 &code,
-                                                 CodeOffsets::frame_never_safe,
-                                                 sasm->frame_size(),
-                                                 oop_maps,
-                                                 sasm->must_gc_arguments());
-  // install blob
-  assert(blob != NULL, "blob must exist");
-  _blobs[id] = blob;
-}
-
-
-void GraalRuntime::initialize(BufferBlob* blob) {
-  // generate stubs
-  for (int id = 0; id < number_of_ids; id++) generate_blob_for(blob, (StubID)id);
-  // printing
-#ifndef PRODUCT
-  if (GraalPrintSimpleStubs) {
-    ResourceMark rm;
-    for (int id = 0; id < number_of_ids; id++) {
-      _blobs[id]->print();
-      if (_blobs[id]->oop_maps() != NULL) {
-        _blobs[id]->oop_maps()->print();
-      }
-    }
-  }
-#endif
-}
-
-
-CodeBlob* GraalRuntime::blob_for(StubID id) {
-  assert(0 <= id && id < number_of_ids, "illegal stub id");
-  return _blobs[id];
-}
-
-
-const char* GraalRuntime::name_for(StubID id) {
-  assert(0 <= id && id < number_of_ids, "illegal stub id");
-  return _blob_names[id];
-}
-
-const char* GraalRuntime::name_for_address(address entry) {
-  for (int id = 0; id < number_of_ids; id++) {
-    if (entry == entry_for((StubID)id)) return name_for((StubID)id);
-  }
-
-#define FUNCTION_CASE(a, f) \
-  if ((intptr_t)a == CAST_FROM_FN_PTR(intptr_t, f))  return #f
-
-  FUNCTION_CASE(entry, os::javaTimeMillis);
-  FUNCTION_CASE(entry, os::javaTimeNanos);
-  FUNCTION_CASE(entry, SharedRuntime::OSR_migration_end);
-  FUNCTION_CASE(entry, SharedRuntime::d2f);
-  FUNCTION_CASE(entry, SharedRuntime::d2i);
-  FUNCTION_CASE(entry, SharedRuntime::d2l);
-  FUNCTION_CASE(entry, SharedRuntime::dcos);
-  FUNCTION_CASE(entry, SharedRuntime::dexp);
-  FUNCTION_CASE(entry, SharedRuntime::dlog);
-  FUNCTION_CASE(entry, SharedRuntime::dlog10);
-  FUNCTION_CASE(entry, SharedRuntime::dpow);
-  FUNCTION_CASE(entry, SharedRuntime::drem);
-  FUNCTION_CASE(entry, SharedRuntime::dsin);
-  FUNCTION_CASE(entry, SharedRuntime::dtan);
-  FUNCTION_CASE(entry, SharedRuntime::f2i);
-  FUNCTION_CASE(entry, SharedRuntime::f2l);
-  FUNCTION_CASE(entry, SharedRuntime::frem);
-  FUNCTION_CASE(entry, SharedRuntime::l2d);
-  FUNCTION_CASE(entry, SharedRuntime::l2f);
-  FUNCTION_CASE(entry, SharedRuntime::ldiv);
-  FUNCTION_CASE(entry, SharedRuntime::lmul);
-  FUNCTION_CASE(entry, SharedRuntime::lrem);
-  FUNCTION_CASE(entry, SharedRuntime::lrem);
-  FUNCTION_CASE(entry, SharedRuntime::dtrace_method_entry);
-  FUNCTION_CASE(entry, SharedRuntime::dtrace_method_exit);
-#ifdef TRACE_HAVE_INTRINSICS
-  FUNCTION_CASE(entry, TRACE_TIME_METHOD);
-#endif
-
-  ShouldNotReachHere();
-  return NULL;
-
-#undef FUNCTION_CASE
-}
-
-
 JRT_ENTRY(void, GraalRuntime::new_instance(JavaThread* thread, Klass* klass))
   assert(klass->is_klass(), "not a class");
   instanceKlassHandle h(thread, klass);
@@ -260,11 +83,16 @@
   // This is pretty rare but this runtime patch is stressful to deoptimization
   // if we deoptimize here so force a deopt to stress the path.
   if (DeoptimizeALot) {
-    deopt_caller();
+    static int deopts = 0;
+    // Alternate between deoptimizing and raising an error (which will also cause a deopt)
+    if (deopts++ % 2 == 0) {
+      ResourceMark rm(THREAD);
+      THROW(vmSymbols::java_lang_OutOfMemoryError());
+    } else {
+      deopt_caller();
+    }
   }
- JRT_END
-
-
+JRT_END
 
 JRT_ENTRY(void, GraalRuntime::new_multi_array(JavaThread* thread, Klass* klass, int rank, jint* dims))
   assert(klass->is_klass(), "not a class");
@@ -273,10 +101,6 @@
   thread->set_vm_result(obj);
 JRT_END
 
-JRT_ENTRY(void, GraalRuntime::unimplemented_entry(JavaThread* thread, StubID id))
-  tty->print_cr("GraalRuntime::entry_for(%d) returned unimplemented entry point", id);
-JRT_END
-
 extern void vm_exit(int code);
 
 // Enter this method from compiled code handler below. This is where we transition
@@ -397,7 +221,6 @@
     }
   }
 
-  thread->set_vm_result(exception());
   // Set flag if return address is a method handle call site.
   thread->set_is_method_handle_return(nm->is_method_handle_return(pc));
 
@@ -481,11 +304,11 @@
   }
 JRT_END
 
-JRT_LEAF(void, GraalRuntime::wb_pre_call(JavaThread* thread, oopDesc* obj))
+JRT_LEAF(void, GraalRuntime::write_barrier_pre(JavaThread* thread, oopDesc* obj))
     thread->satb_mark_queue().enqueue(obj);
 JRT_END
 
-JRT_LEAF(void, GraalRuntime::wb_post_call(JavaThread* thread, oopDesc* obj, void* card_addr))
+JRT_LEAF(void, GraalRuntime::write_barrier_post(JavaThread* thread, oopDesc* obj, void* card_addr))
     thread->dirty_card_queue().enqueue(card_addr);
 JRT_END
 
@@ -565,10 +388,44 @@
   tty->print(buf, v1, v2, v3);
 JRT_END
 
-JRT_LEAF(void, GraalRuntime::stub_printf(JavaThread* thread, jlong format, jlong v1, jlong v2, jlong v3))
+static void decipher(jlong v, bool ignoreZero) {
+  if (v != 0 || !ignoreZero) {
+    void* p = (void *)(address) v;
+    CodeBlob* cb = CodeCache::find_blob(p);
+    if (cb) {
+      if (cb->is_nmethod()) {
+        char buf[O_BUFLEN];
+        tty->print("%s [%p+%d]", cb->as_nmethod_or_null()->method()->name_and_sig_as_C_string(buf, O_BUFLEN), cb->code_begin(), (address)v - cb->code_begin());
+        return;
+      }
+      cb->print_value_on(tty);
+      return;
+    }
+    if (Universe::heap()->is_in(p)) {
+      oop obj = oop(p);
+      obj->print_value_on(tty);
+      return;
+    }
+    tty->print("%p [long: %d, double %f, char %c]", v, v, v, v);
+  }
+}
+
+JRT_LEAF(void, GraalRuntime::vm_message(jboolean vmError, jlong format, jlong v1, jlong v2, jlong v3))
   ResourceMark rm;
   char *buf = (char*) (address) format;
-  tty->print(buf, v1, v2, v3);
+  if (vmError) {
+    if (buf != NULL) {
+      fatal(err_msg(buf, v1, v2, v3));
+    } else {
+      fatal("<anonymous error>");
+    }
+  } else if (buf != NULL) {
+    tty->print(buf, v1, v2, v3);
+  } else {
+    assert(v2 == 0, "v2 != 0");
+    assert(v3 == 0, "v3 != 0");
+    decipher(v1, false);
+  }
 JRT_END
 
 JRT_ENTRY(void, GraalRuntime::log_primitive(JavaThread* thread, jchar typeChar, jlong value, jboolean newline))
--- a/src/share/vm/graal/graalRuntime.hpp	Mon May 13 16:46:39 2013 +0200
+++ b/src/share/vm/graal/graalRuntime.hpp	Mon May 13 17:11:31 2013 +0200
@@ -24,137 +24,26 @@
 #ifndef SHARE_VM_GRAAL_GRAAL_RUNTIME_HPP
 #define SHARE_VM_GRAAL_GRAAL_RUNTIME_HPP
 
-#include "code/stubs.hpp"
 #include "interpreter/interpreter.hpp"
 #include "memory/allocation.hpp"
 #include "runtime/deoptimization.hpp"
 
-// A GraalStubAssembler is a MacroAssembler w/ extra functionality for runtime
-// stubs. Currently it 'knows' some stub info. Eventually, the information
-// may be set automatically or can be asserted when using specialised
-// GraalStubAssembler functions.
-
-class GraalStubAssembler: public MacroAssembler {
- private:
-  const char* _name;
-  bool        _must_gc_arguments;
-  int         _frame_size;
-  int         _num_rt_args;
-  int         _stub_id;
-
+class GraalRuntime: public AllStatic {
  public:
-
-  enum {
-    no_frame_size            = -1
-  };
-
-  // creation
-  GraalStubAssembler(CodeBuffer* code, const char * name, int stub_id);
-  void set_info(const char* name, bool must_gc_arguments);
-
-  void set_frame_size(int size);
-  void set_num_rt_args(int args);
-
-  // accessors
-  const char* name() const                       { return _name; }
-  bool  must_gc_arguments() const                { return _must_gc_arguments; }
-  int frame_size() const                         { return _frame_size; }
-  int num_rt_args() const                        { return _num_rt_args; }
-  int stub_id() const                            { return _stub_id; }
-
-  void verify_stack_oop(int offset) PRODUCT_RETURN;
-  void verify_not_null_oop(Register r)  PRODUCT_RETURN;
-
-  // runtime calls (return offset of call to be used by GC map)
-  int call_RT(Register oop_result1, Register metadata_result, address entry, int args_size = 0);
-  int call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1);
-  int call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1, Register arg2);
-  int call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1, Register arg2, Register arg3);
-  int call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1, Register arg2, Register arg3, Register arg4);
-};
-
-// set frame size and return address offset to these values in blobs
-// (if the compiled frame uses ebp as link pointer on IA; otherwise,
-// the frame size must be fixed)
-
-// Holds all assembly stubs and VM
-// runtime routines needed by code code generated
-// by Graal.
-#define GRAAL_STUBS(stub, last_entry) \
-  stub(register_finalizer)      \
-  stub(new_instance)            \
-  stub(new_array)               \
-  stub(new_multi_array)         \
-  stub(handle_exception_nofpu) /* optimized version that does not preserve fpu registers */ \
-  stub(unwind_exception_call)   \
-  stub(OSR_migration_end)       \
-  stub(arithmetic_frem)         \
-  stub(arithmetic_drem)         \
-  stub(monitorenter)            \
-  stub(monitorexit)             \
-  stub(verify_oop)              \
-  stub(vm_error)                \
-  stub(create_null_pointer_exception) \
-  stub(create_out_of_bounds_exception) \
-  stub(log_object)              \
-  stub(log_printf)              \
-  stub(stub_printf)             \
-  stub(log_primitive)           \
-  stub(identity_hash_code)      \
-  stub(thread_is_interrupted)   \
-  stub(wb_pre_call)             \
-  stub(wb_post_call)             \
- last_entry(number_of_ids)
-
-#define DECLARE_STUB_ID(x)       x ## _id ,
-#define DECLARE_LAST_STUB_ID(x)  x
-#define STUB_NAME(x)             #x " GraalRuntime stub",
-#define LAST_STUB_NAME(x)        #x " GraalRuntime stub"
-
-class GraalRuntime: public AllStatic {
-  friend class VMStructs;
-
- public:
-  enum StubID {
-    GRAAL_STUBS(DECLARE_STUB_ID, DECLARE_LAST_STUB_ID)
-  };
-
- private:
-  static CodeBlob* _blobs[number_of_ids];
-  static const char* _blob_names[];
-
-  // stub generation
-  static void       generate_blob_for(BufferBlob* blob, StubID id);
-  static OopMapSet* generate_code_for(StubID id, GraalStubAssembler* sasm);
-  static OopMapSet* generate_handle_exception(StubID id, GraalStubAssembler* sasm);
-  static void       generate_unwind_exception(GraalStubAssembler *sasm);
-
-  static OopMapSet* generate_stub_call(GraalStubAssembler* sasm, Register result, address entry,
-                                       Register arg1 = noreg, Register arg2 = noreg, Register arg3 = noreg);
-
-  // runtime entry points
   static void new_instance(JavaThread* thread, Klass* klass);
   static void new_array(JavaThread* thread, Klass* klass, jint length);
   static void new_multi_array(JavaThread* thread, Klass* klass, int rank, jint* dims);
-
-  static void unimplemented_entry(JavaThread* thread, StubID id);
-
+  static jboolean thread_is_interrupted(JavaThread* thread, oopDesc* obj, jboolean clear_interrupte);
+  static void vm_message(jboolean vmError, jlong format, jlong v1, jlong v2, jlong v3);
+  static jint identity_hash_code(JavaThread* thread, oopDesc* objd);
   static address exception_handler_for_pc(JavaThread* thread);
-
-  static void create_null_exception(JavaThread* thread);
-  static void create_out_of_bounds_exception(JavaThread* thread, jint index);
   static void monitorenter(JavaThread* thread, oopDesc* obj, BasicLock* lock);
   static void monitorexit (JavaThread* thread, oopDesc* obj, BasicLock* lock);
+  static void create_null_exception(JavaThread* thread);
+  static void create_out_of_bounds_exception(JavaThread* thread, jint index);
   static void vm_error(JavaThread* thread, oop where, oop format, jlong value);
   static void log_printf(JavaThread* thread, oop format, jlong v1, jlong v2, jlong v3);
-  static void stub_printf(JavaThread* thread, jlong format, jlong v1, jlong v2, jlong v3);
   static void log_primitive(JavaThread* thread, jchar typeChar, jlong value, jboolean newline);
-  static void wb_pre_call(JavaThread* thread, oopDesc* obj);
-  static void wb_post_call(JavaThread* thread, oopDesc* obj, void* card);
-
-  static jint identity_hash_code(JavaThread* thread, oopDesc* objd);
-  static jboolean thread_is_interrupted(JavaThread* thread, oopDesc* obj, jboolean clear_interrupte);
-
   // Note: Must be kept in sync with constants in com.oracle.graal.replacements.Log
   enum {
     LOG_OBJECT_NEWLINE = 0x01,
@@ -162,16 +51,8 @@
     LOG_OBJECT_ADDRESS = 0x04
   };
   static void log_object(JavaThread* thread, oop msg, jint flags);
-
- public:
-  // initialization
-  static void initialize(BufferBlob* blob);
-
-  // stubs
-  static CodeBlob* blob_for (StubID id);
-  static address   entry_for(StubID id)          { return blob_for(id)->code_begin(); }
-  static const char* name_for (StubID id);
-  static const char* name_for_address(address entry);
+  static void write_barrier_pre(JavaThread* thread, oopDesc* obj);
+  static void write_barrier_post(JavaThread* thread, oopDesc* obj, void* card);
 };
 
 #endif // SHARE_VM_GRAAL_GRAAL_RUNTIME_HPP
--- a/src/share/vm/runtime/deoptimization.cpp	Mon May 13 16:46:39 2013 +0200
+++ b/src/share/vm/runtime/deoptimization.cpp	Mon May 13 17:11:31 2013 +0200
@@ -1344,8 +1344,19 @@
     // Ensure that we can record deopt. history:
     bool create_if_missing = ProfileTraps;
 
+    methodHandle profiled_method;
+#ifdef GRAAL
+    if (nm->is_compiled_by_graal()) {
+      profiled_method = nm->method();
+    } else {
+      profiled_method = trap_method;
+    }
+#else
+    profiled_method = trap_method;
+#endif
+
     MethodData* trap_mdo =
-      get_method_data(thread, trap_method, create_if_missing);
+      get_method_data(thread, profiled_method, create_if_missing);
 
     // Log a message
     Events::log_deopt_message(thread, "Uncommon trap: reason=%s action=%s pc=" INTPTR_FORMAT " method=%s @ %d",
@@ -1538,7 +1549,6 @@
     bool inc_recompile_count = false;
     ProfileData* pdata = NULL;
     if (ProfileTraps && update_trap_state && trap_mdo != NULL) {
-      assert(trap_mdo == get_method_data(thread, trap_method, false), "sanity");
       uint this_trap_count = 0;
       bool maybe_prior_trap = false;
       bool maybe_prior_recompile = false;
--- a/src/share/vm/runtime/globals.hpp	Mon May 13 16:46:39 2013 +0200
+++ b/src/share/vm/runtime/globals.hpp	Mon May 13 17:11:31 2013 +0200
@@ -3691,6 +3691,9 @@
   product(bool , AllowNonVirtualCalls, false,                               \
           "Obey the ACC_SUPER flag and allow invokenonvirtual calls")       \
                                                                             \
+  product(bool, TraceWarpLoading, false,                                    \
+          "trace external GPU warp loading")                                \
+                                                                            \
   experimental(uintx, ArrayAllocatorMallocLimit,                            \
           SOLARIS_ONLY(64*K) NOT_SOLARIS(max_uintx),                        \
           "Allocation less than this value will be allocated "              \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/runtime/gpu.cpp	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "runtime/gpu.hpp"
+#include "ptx/gpu_ptx.hpp"
+
+bool gpu::_available = false;   // does the hardware exist?
+bool gpu::_gpu_linkage = false; // is the driver library to access the GPU installed
+bool gpu::_initialized = false; // is the GPU defvice initialized
+
+void gpu::init() {
+#ifdef TARGET_OS_FAMILY_bsd
+  gpu::probe_gpu();
+#endif
+  // need multi-gpu TARGET ifdef
+  gpu::probe_linkage();
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/runtime/gpu.hpp	Mon May 13 17:11:31 2013 +0200
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef SHARE_VM_RUNTIME_GPU_HPP
+#define SHARE_VM_RUNTIME_GPU_HPP
+
+#include "runtime/atomic.hpp"
+
+// gpu defines the interface to the graphics processor; this includes traditional
+// GPU services such as graphics kernel load and execute.
+
+
+class gpu: AllStatic {
+public:
+  static void init(void);
+
+  static void probe_gpu();
+
+  static void probe_linkage();
+  
+  static void initialize_gpu();
+  
+  static void generate_kernel(unsigned char *code, int code_len, const char *name);
+
+  static void set_available(bool value) {
+    _available = value;
+  }
+
+  static bool is_available() { return _available; }
+
+  static void set_initialized(bool value) {
+    _initialized = value;
+  }
+
+  static bool is_initialized() { return _initialized; }
+
+  static void set_gpu_linkage(bool value) {
+    _gpu_linkage = value;
+  }
+
+  static bool has_gpu_linkage() { return _gpu_linkage; }
+
+protected:
+  static bool _available;
+  static bool _gpu_linkage;
+  static bool _initialized;
+
+  // Platform dependent stuff
+#ifdef TARGET_OS_FAMILY_linux
+#endif
+#ifdef TARGET_OS_FAMILY_solaris
+#endif
+#ifdef TARGET_OS_FAMILY_windows
+#endif
+#ifdef TARGET_OS_FAMILY_bsd
+# include "gpu_bsd.hpp"
+#endif
+
+# include "ptx/gpu_ptx.hpp"
+
+};
+
+
+#endif // SHARE_VM_RUNTIME_GPU_HPP
--- a/src/share/vm/runtime/sharedRuntime.cpp	Mon May 13 16:46:39 2013 +0200
+++ b/src/share/vm/runtime/sharedRuntime.cpp	Mon May 13 17:11:31 2013 +0200
@@ -484,6 +484,12 @@
   // Reset method handle flag.
   thread->set_is_method_handle_return(false);
 
+#ifdef GRAAL
+  // Graal's ExceptionHandlerStub expects the thread local exception PC to be clear
+  // and other exception handler continuations do not read it
+  thread->set_exception_pc(NULL);
+#endif
+
   // The fastest case first
   CodeBlob* blob = CodeCache::find_blob(return_address);
   nmethod* nm = (blob != NULL) ? blob->as_nmethod_or_null() : NULL;
--- a/src/share/vm/runtime/thread.cpp	Mon May 13 16:46:39 2013 +0200
+++ b/src/share/vm/runtime/thread.cpp	Mon May 13 17:11:31 2013 +0200
@@ -54,6 +54,7 @@
 #include "runtime/deoptimization.hpp"
 #include "runtime/fprofiler.hpp"
 #include "runtime/frame.inline.hpp"
+#include "runtime/gpu.hpp"
 #include "runtime/init.hpp"
 #include "runtime/interfaceSupport.hpp"
 #include "runtime/java.hpp"
@@ -3307,6 +3308,9 @@
   // Initialize the os module before using TLS
   os::init();
 
+  // probe for warp capability
+  gpu::init();
+
   // Initialize system properties.
   Arguments::init_system_properties();