changeset 9462:861a9e0aba38

Merge.
author Doug Simon <doug.simon@oracle.com>
date Tue, 30 Apr 2013 23:09:37 +0200
parents a14fef4fca7d (current diff) ca34e36c53e8 (diff)
children 902a974d55c8
files graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRuntime.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java src/share/vm/graal/graalCompilerToVM.cpp
diffstat 158 files changed, 2771 insertions(+), 1073 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.amd64/src/com/oracle/graal/amd64/AMD64.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.amd64/src/com/oracle/graal/amd64/AMD64.java	Tue Apr 30 23:09:37 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	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Architecture.java	Tue Apr 30 23:09:37 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	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CalleeSaveLayout.java	Tue Apr 30 23:09:37 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/Register.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Register.java	Tue Apr 30 23:09:37 2013 +0200
@@ -34,18 +34,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 +74,32 @@
     }
 
     /**
-     * The size of the stack slot used to spill the value of this register.
+     * A platform specific register category that describes which values can be stored in a
+     * register.
      */
-    public final int spillSlotSize;
-
-    /**
-     * The set of {@link RegisterFlag} values associated with this register.
-     */
-    private final int flags;
+    private final RegisterCategory registerCategory;
 
     /**
      * 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 HashMap<PlatformKind, RegisterValue> values;
 
     /**
-     * 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;
 
-        /**
-         * Denotes a register whose lowest order byte can be addressed separately.
-         */
-        Byte,
+        public RegisterCategory(String name) {
+            this.name = name;
+        }
 
-        /**
-         * Denotes a floating point register.
-         */
-        FPU;
-
-        public final int mask = 1 << (ordinal() + 1);
+        @Override
+        public String toString() {
+            return name;
+        }
     }
 
     /**
@@ -115,33 +107,19 @@
      * 
      * @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);
-        }
+        this.values = new HashMap<>();
     }
 
-    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 +128,14 @@
      * @param kind the specified kind
      * @return the {@link RegisterValue}
      */
-    public RegisterValue asValue(Kind kind) {
-        return values[kind.ordinal()];
+    public RegisterValue asValue(PlatformKind kind) {
+        if (values.containsKey(kind)) {
+            return values.get(kind);
+        } else {
+            RegisterValue ret = new RegisterValue(kind, this);
+            values.put(kind, ret);
+            return ret;
+        }
     }
 
     /**
@@ -173,29 +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}
@@ -206,27 +167,6 @@
     }
 
     /**
-     * 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
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterConfig.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterConfig.java	Tue Apr 30 23:09:37 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();
 
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterValue.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterValue.java	Tue Apr 30 23:09:37 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,14 +39,14 @@
     /**
      * 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();
+        return (getRegister().number << 4) ^ getPlatformKind().hashCode();
     }
 
     @Override
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/StackSlot.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/StackSlot.java	Tue Apr 30 23:09:37 2013 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.api.code;
 
-import static com.oracle.graal.api.meta.Kind.*;
+import java.util.*;
 
 import com.oracle.graal.api.meta.*;
 
@@ -46,25 +46,20 @@
      * @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;
+            StackSlot slot;
             if (!addFrameSize) {
-                cache = OUT_CACHE;
+                slot = OUT_CACHE.lookup(kind, offset);
             } else if (offset >= 0) {
-                cache = IN_CACHE;
+                slot = IN_CACHE.lookup(kind, offset);
             } else {
-                cache = SPILL_CACHE;
-                index = -index;
+                slot = SPILL_CACHE.lookup(kind, offset);
             }
-            StackSlot[] slots = cache[kind.ordinal()];
-            if (index < slots.length) {
-                StackSlot slot = slots[index];
-                assert slot.getKind() == kind && slot.offset == offset && slot.addFrameSize == addFrameSize;
+            if (slot != null) {
+                assert slot.getPlatformKind().equals(kind) && slot.offset == offset && slot.addFrameSize == addFrameSize;
                 return slot;
             }
         }
@@ -72,10 +67,10 @@
     }
 
     /**
-     * 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;
@@ -107,7 +102,7 @@
 
     @Override
     public int hashCode() {
-        return getKind().ordinal() ^ (offset << 4) ^ (addFrameSize ? 15 : 0);
+        return getPlatformKind().hashCode() ^ (offset << 4) ^ (addFrameSize ? 15 : 0);
     }
 
     @Override
@@ -117,7 +112,7 @@
         }
         if (o instanceof StackSlot) {
             StackSlot l = (StackSlot) o;
-            return l.getKind() == getKind() && l.offset == offset && l.addFrameSize == addFrameSize;
+            return l.getPlatformKind().equals(getPlatformKind()) && l.offset == offset && l.addFrameSize == addFrameSize;
         }
         return false;
     }
@@ -139,7 +134,7 @@
     public StackSlot asOutArg() {
         assert offset >= 0;
         if (addFrameSize) {
-            return get(getKind(), offset, false);
+            return get(getPlatformKind(), offset, false);
         }
         return this;
     }
@@ -150,28 +145,48 @@
     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 int CACHE_GRANULARITY = 8;
 
-    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);
+    private static class Cache extends HashMap<PlatformKind, StackSlot[]> {
+
+        private static final long serialVersionUID = 4424132866289682843L;
+
+        private final int cachePerKindSize;
+        private final int sign;
+        private final boolean addFrameSize;
+
+        Cache(int cachePerKindSize, int sign, boolean addFrameSize) {
+            this.cachePerKindSize = cachePerKindSize;
+            this.sign = sign;
+            this.addFrameSize = addFrameSize;
+        }
 
-    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);
+        StackSlot lookup(PlatformKind kind, int offset) {
+            int index = sign * offset / CACHE_GRANULARITY;
+            StackSlot[] slots = this.get(kind);
+            if (slots == null) {
+                slots = new StackSlot[cachePerKindSize];
+                for (int i = 0; i < cachePerKindSize; i++) {
+                    slots[i] = new StackSlot(kind, sign * i * CACHE_GRANULARITY, addFrameSize);
+                }
+                this.put(kind, slots);
             }
-            cache[kind.ordinal()] = slots;
+            if (index < slots.length) {
+                return slots[index];
+            } else {
+                return null;
+            }
         }
-        return cache;
     }
+
+    private static final Cache SPILL_CACHE = new Cache(SPILL_CACHE_PER_KIND_SIZE, -1, true);
+    private static final Cache IN_CACHE = new Cache(PARAM_CACHE_PER_KIND_SIZE, 1, true);
+    private static final Cache OUT_CACHE = new Cache(PARAM_CACHE_PER_KIND_SIZE, 1, false);
 }
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/TargetDescription.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/TargetDescription.java	Tue Apr 30 23:09:37 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/VirtualObject.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/VirtualObject.java	Tue Apr 30 23:09:37 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	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/AllocatableValue.java	Tue Apr 30 23:09:37 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	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/DeoptimizationReason.java	Tue Apr 30 23:09:37 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/Kind.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Kind.java	Tue Apr 30 23:09:37 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),
 
--- /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	Tue Apr 30 23:09:37 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/Value.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Value.java	Tue Apr 30 23:09:37 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,11 @@
     public final Kind getKind() {
         return kind;
     }
+
+    /**
+     * Returns the platform specific kind used to store this value.
+     */
+    public final PlatformKind getPlatformKind() {
+        return platformKind;
+    }
 }
--- a/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java	Tue Apr 30 23:09:37 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);
@@ -540,7 +540,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 +549,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 +559,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 +568,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 +577,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 +586,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 +595,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 +604,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 +622,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 +639,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 +654,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 +663,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 +673,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 +682,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 +862,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 +887,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 +918,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 +981,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 +990,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 +1010,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 +1038,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 +1048,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 +1057,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 +1066,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 +1076,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 +1085,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 +1137,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 +1146,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 +1157,7 @@
     }
 
     public final void mulss(Register dst, AMD64Address src) {
-        assert dst.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM;
 
         emitByte(0xF3);
         prefix(src, dst);
@@ -1167,8 +1167,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 +1512,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 +1545,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 +1555,7 @@
     }
 
     public final void subsd(Register dst, AMD64Address src) {
-        assert dst.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM;
 
         emitByte(0xF2);
         prefix(src, dst);
@@ -1565,8 +1565,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 +1575,7 @@
     }
 
     public final void subss(Register dst, AMD64Address src) {
-        assert dst.isFpu();
+        assert dst.getRegisterCategory() == AMD64.XMM;
 
         emitByte(0xF3);
         prefix(src, dst);
@@ -1611,20 +1611,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 +1633,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 +1668,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 +1676,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 +1694,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 +1702,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 +1720,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 +1728,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 +2014,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 +2023,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 +2032,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 +2041,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 +2058,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 +2075,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);
@@ -2154,13 +2154,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);
--- a/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64MacroAssembler.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64MacroAssembler.java	Tue Apr 30 23:09:37 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,7 +218,7 @@
     }
 
     public final void flog(Register dest, Register value, boolean base10) {
-        assert dest.isFpu() && value.isFpu();
+        assert dest.getRegisterCategory() == AMD64.XMM && value.getRegisterCategory() == AMD64.XMM;
 
         AMD64Address tmp = new AMD64Address(AMD64.rsp);
         if (base10) {
@@ -262,7 +253,7 @@
     }
 
     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);
@@ -271,7 +262,7 @@
     }
 
     private void trigEpilogue(Register dest, AMD64Address tmp) {
-        assert dest.isFpu();
+        assert dest.getRegisterCategory() == AMD64.XMM;
         fstp(tmp);
         movsd(dest, tmp);
         addq(AMD64.rsp, 8);
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Tue Apr 30 23:09:37 2013 +0200
@@ -87,11 +87,11 @@
     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);
         }
     }
 
@@ -143,7 +143,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)) {
@@ -525,7 +525,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 +554,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;
             }
@@ -657,7 +657,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)));
--- a/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/BasicPTXTest.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/BasicPTXTest.java	Tue Apr 30 23:09:37 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	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/PTXTestBase.java	Tue Apr 30 23:09:37 2013 +0200
@@ -24,33 +24,57 @@
 
 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.CompilationResult;
+import com.oracle.graal.api.code.SpeculationLog;
+import com.oracle.graal.api.code.TargetDescription;
+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,
-                        new SpeculationLog());
+        CompilationResult result = GraalCompiler.compileMethod(runtime, graalRuntime().getReplacements(),
+                                                               ptxBackend, target, graph.method(), graph, 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	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXBackend.java	Tue Apr 30 23:09:37 2013 +0200
@@ -50,9 +50,6 @@
 
         @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,9 +71,9 @@
         // - 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;
     }
@@ -81,6 +83,8 @@
         // Emit the prologue
         final String name = method.getName();
         Buffer codeBuffer = tasm.asm.codeBuffer;
+        codeBuffer.emitString(".version 1.4");
+        codeBuffer.emitString(".target sm_10");
         codeBuffer.emitString0(".entry " + name + " (");
         codeBuffer.emitString("");
 
--- /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	Tue Apr 30 23:09:37 2013 +0200
@@ -0,0 +1,65 @@
+/*
+ * 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.CodeCacheProvider;
+import com.oracle.graal.api.code.CompilationResult;
+import com.oracle.graal.api.code.TargetDescription;
+import com.oracle.graal.asm.AbstractAssembler;
+import com.oracle.graal.hotspot.HotSpotGraalRuntime;
+import com.oracle.graal.hotspot.bridge.CompilerToGPU;
+import com.oracle.graal.hotspot.meta.HotSpotMethod;
+import com.oracle.graal.lir.FrameMap;
+import com.oracle.graal.lir.asm.FrameContext;
+import com.oracle.graal.lir.asm.TargetMethodAssembler;
+
+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(Object name, boolean isStub) {
+        CompilationResult graalCompile = super.finishTargetMethod(name, isStub);
+
+        try {
+            if (validDevice) {
+                HotSpotMethod method = (HotSpotMethod) name;
+                toGPU.generateKernel(graalCompile.getTargetCode(), method.getName());
+            }
+        } catch (Throwable th) {
+            th.printStackTrace();
+        }
+
+        return graalCompile;  // for now
+    }
+}
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SimpleCFGTest.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SimpleCFGTest.java	Tue Apr 30 23:09:37 2013 +0200
@@ -35,12 +35,12 @@
     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));
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/WriteBarrierVerificationTest.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/WriteBarrierVerificationTest.java	Tue Apr 30 23:09:37 2013 +0200
@@ -683,7 +683,7 @@
                     }
 
                     @Override
-                    protected State afterSplit(BeginNode node, State oldState) {
+                    protected State afterSplit(AbstractBeginNode node, State oldState) {
                         return new State();
                     }
                 };
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Tue Apr 30 23:09:37 2013 +0200
@@ -146,7 +146,7 @@
 
         plan.runPhases(PhasePosition.LOW_LEVEL, graph);
 
-        LowTierContext lowTierContext = new LowTierContext(runtime, assumptions, replacements, target);
+        LowTierContext lowTierContext = new LowTierContext(runtime, assumptions, replacements, target, optimisticOpts);
         Suites.DEFAULT.getLowTier().apply(graph, lowTierContext);
 
         final SchedulePhase schedule = new SchedulePhase();
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/Interval.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/Interval.java	Tue Apr 30 23:09:37 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;
     }
 
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java	Tue Apr 30 23:09:37 2013 +0200
@@ -305,7 +305,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);
 
@@ -968,7 +968,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 +987,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 +1008,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;
         }
@@ -1197,7 +1197,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 +1208,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 +1220,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 +1232,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 +1247,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;
                     }
                 });
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScanWalker.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScanWalker.java	Tue Apr 30 23:09:37 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,8 +810,7 @@
     }
 
     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) {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/MoveResolver.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/MoveResolver.java	Tue Apr 30 23:09:37 2013 +0200
@@ -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;
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Tue Apr 30 23:09:37 2013 +0200
@@ -142,23 +142,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
@@ -476,7 +471,7 @@
     }
 
     @Override
-    public void visitEndNode(EndNode end) {
+    public void visitEndNode(AbstractEndNode end) {
         moveToPhi(end.merge(), end);
     }
 
@@ -487,7 +482,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);
         }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LowTier.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LowTier.java	Tue Apr 30 23:09:37 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/target/Backend.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java	Tue Apr 30 23:09:37 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.*;
@@ -52,6 +53,8 @@
 
     public abstract LIRGenerator newLIRGenerator(StructuredGraph graph, FrameMap frameMap, ResolvedJavaMethod method, LIR lir);
 
+    protected abstract AbstractAssembler createAssembler(FrameMap frameMap);
+
     public abstract TargetMethodAssembler newAssembler(LIRGenerator lirGen, CompilationResult compilationResult);
 
     /**
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Tue Apr 30 23:09:37 2013 +0200
@@ -477,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/NodeClass.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Tue Apr 30 23:09:37 2013 +0200
@@ -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	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeMap.java	Tue Apr 30 23:09:37 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	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64.test/src/com/oracle/graal/hotspot/amd64/test/AMD64HotSpotFrameOmissionTest.java	Tue Apr 30 23:09:37 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/AMD64HotSpotBackend.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Tue Apr 30 23:09:37 2013 +0200
@@ -140,6 +140,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
@@ -151,7 +156,7 @@
         LIR lir = gen.lir;
         boolean omitFrame = CanOmitFrame && !frameMap.frameNeedsAllocating() && !lir.hasArgInCallerFrame();
 
-        AbstractAssembler masm = new AMD64MacroAssembler(target, frameMap.registerConfig);
+        AbstractAssembler masm = createAssembler(frameMap);
         HotSpotFrameContext frameContext = omitFrame ? null : new HotSpotFrameContext();
         TargetMethodAssembler tasm = new TargetMethodAssembler(target, runtime(), frameMap, masm, frameContext, compilationResult);
         tasm.setFrameSize(frameMap.frameSize());
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotEpilogueOp.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotEpilogueOp.java	Tue Apr 30 23:09:37 2013 +0200
@@ -24,7 +24,6 @@
 
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.amd64.*;
@@ -39,7 +38,7 @@
      * 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;
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotGraalRuntime.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotGraalRuntime.java	Tue Apr 30 23:09:37 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
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Tue Apr 30 23:09:37 2013 +0200
@@ -54,13 +54,13 @@
 /**
  * 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) {
+    protected AMD64HotSpotLIRGenerator(StructuredGraph graph, CodeCacheProvider runtime, TargetDescription target, FrameMap frameMap, ResolvedJavaMethod method, LIR lir) {
         super(graph, runtime, target, frameMap, method, lir);
     }
 
@@ -198,11 +198,19 @@
         if (needsCalleeSave) {
             Register[] savedRegisters = frameMap.registerConfig.getAllocatableRegisters();
             savedRegisterLocations = new StackSlot[savedRegisters.length];
+            AMD64LIRInstruction[] savingMoves = new AMD64LIRInstruction[savedRegisters.length];
+            AMD64LIRInstruction[] restoringMoves = new AMD64LIRInstruction[savedRegisters.length];
             for (int i = 0; i < savedRegisters.length; i++) {
-                StackSlot spillSlot = frameMap.allocateSpillSlot(Kind.Long);
+                PlatformKind kind = target.arch.getLargestStorableKind(savedRegisters[i].getRegisterCategory());
+                assert kind != Kind.Illegal;
+                StackSlot spillSlot = frameMap.allocateSpillSlot(kind);
                 savedRegisterLocations[i] = spillSlot;
+
+                RegisterValue register = savedRegisters[i].asValue(kind);
+                savingMoves[i] = createMove(spillSlot, register);
+                restoringMoves[i] = createMove(register, spillSlot);
             }
-            save = new AMD64SaveRegistersOp(savedRegisters, savedRegisterLocations);
+            save = new AMD64SaveRegistersOp(savingMoves, restoringMoves, savedRegisterLocations);
             append(save);
 
             Value thread = args[0];
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRegisterConfig.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRegisterConfig.java	Tue Apr 30 23:09:37 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,9 +37,11 @@
 // @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;
 
@@ -49,9 +50,21 @@
         return allocatable.clone();
     }
 
-    @Override
-    public EnumMap<RegisterFlag, Register[]> getCategorizedAllocatableRegisters() {
-        return categorized.clone();
+    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
@@ -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/AMD64HotSpotRuntime.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRuntime.java	Tue Apr 30 23:09:37 2013 +0200
@@ -187,6 +187,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.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java	Tue Apr 30 23:09:37 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.*;
@@ -47,6 +48,12 @@
     }
 
     @Override
+    protected AbstractAssembler createAssembler(FrameMap frameMap) {
+        // SPARC: Create assembler.
+        return null;
+    }
+
+    @Override
     public TargetMethodAssembler newAssembler(LIRGenerator lirGen, CompilationResult compilationResult) {
         // SPARC: Create assembler.
         return null;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java	Tue Apr 30 23:09:37 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	Tue Apr 30 23:09:37 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/HotSpotVMConfig.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Tue Apr 30 23:09:37 2013 +0200
@@ -394,6 +394,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	Tue Apr 30 23:09:37 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	Tue Apr 30 23:09:37 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/meta/HotSpotRuntime.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Tue Apr 30 23:09:37 2013 +0200
@@ -25,7 +25,6 @@
 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.*;
@@ -41,7 +40,6 @@
 import static com.oracle.graal.hotspot.stubs.NewInstanceStub.*;
 import static com.oracle.graal.hotspot.stubs.NewMultiArrayStub.*;
 import static com.oracle.graal.hotspot.stubs.RegisterFinalizerStub.*;
-import static com.oracle.graal.hotspot.stubs.Stub.*;
 import static com.oracle.graal.hotspot.stubs.ThreadIsInterruptedStub.*;
 import static com.oracle.graal.java.GraphBuilderPhase.RuntimeCalls.*;
 import static com.oracle.graal.nodes.java.RegisterFinalizerNode.*;
@@ -59,7 +57,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.*;
@@ -195,13 +192,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;
@@ -734,7 +730,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.dependencies().add(AbstractBeginNode.prevBegin(load));
             graph.replaceFixedWithFixed(load, memoryRead);
         } else if (n instanceof UnsafeStoreNode) {
             UnsafeStoreNode store = (UnsafeStoreNode) n;
@@ -867,7 +863,7 @@
     }
 
     private IndexedLocationNode createArrayLocation(Graph graph, Kind elementKind, ValueNode index) {
-        int scale = this.graalRuntime.getTarget().sizeInBytes(elementKind);
+        int scale = this.graalRuntime.getTarget().arch.getSizeInBytes(elementKind);
         return IndexedLocationNode.create(LocationNode.getArrayLocation(elementKind), elementKind, getArrayBaseOffset(elementKind), index, graph, scale);
     }
 
@@ -998,6 +994,8 @@
                 return config.deoptReasonDiv0Check;
             case RuntimeConstraint:
                 return config.deoptReasonConstraint;
+            case LoopLimitCheck:
+                return config.deoptReasonLoopLimitCheck;
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Tue Apr 30 23:09:37 2013 +0200
@@ -261,7 +261,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);
                 /*
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java	Tue Apr 30 23:09:37 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	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Tue Apr 30 23:09:37 2013 +0200
@@ -679,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(1, currentBlock.successors.get(0), frameState));
         assert currentBlock.numNormalSuccessors() == 1;
     }
 
@@ -725,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));
@@ -1493,7 +1489,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();
@@ -1508,7 +1504,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);
@@ -1522,9 +1518,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.";
@@ -1705,7 +1701,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.
@@ -1773,7 +1769,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	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/JTTTest.java	Tue Apr 30 23:09:37 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.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64AddressValue.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64AddressValue.java	Tue Apr 30 23:09:37 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;
@@ -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	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java	Tue Apr 30 23:09:37 2013 +0200
@@ -255,8 +255,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;
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64RestoreRegistersOp.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64RestoreRegistersOp.java	Tue Apr 30 23:09:37 2013 +0200
@@ -52,12 +52,9 @@
 
     @Override
     public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
-        Register[] savedRegisters = save.savedRegisters;
-        for (int i = 0; i < savedRegisters.length; i++) {
-            if (savedRegisters[i] != null) {
-                StackSlot input = slots[i];
-                RegisterValue result = savedRegisters[i].asValue(input.getKind());
-                AMD64Move.move(tasm, masm, result, input);
+        for (AMD64LIRInstruction restoringMove : save.restoringMoves) {
+            if (restoringMove != null) {
+                restoringMove.emitCode(tasm, masm);
             }
         }
     }
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64SaveRegistersOp.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64SaveRegistersOp.java	Tue Apr 30 23:09:37 2013 +0200
@@ -30,6 +30,7 @@
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.LIRInstruction.Opcode;
+import com.oracle.graal.lir.StandardOp.MoveOp;
 import com.oracle.graal.lir.asm.*;
 
 /**
@@ -39,29 +40,31 @@
 public final class AMD64SaveRegistersOp extends AMD64LIRInstruction {
 
     /**
-     * The registers (potentially) saved by this operation.
+     * The move instructions for saving the registers.
      */
-    protected final Register[] savedRegisters;
+    protected final AMD64LIRInstruction[] savingMoves;
+
+    /**
+     * The move instructions for restoring the registers.
+     */
+    protected final AMD64LIRInstruction[] restoringMoves;
 
     /**
      * The slots to which the registers are saved.
      */
     @Def(STACK) protected final StackSlot[] slots;
 
-    public AMD64SaveRegistersOp(Register[] savedRegisters, StackSlot[] slots) {
-        this.savedRegisters = savedRegisters;
+    public AMD64SaveRegistersOp(AMD64LIRInstruction[] savingMoves, AMD64LIRInstruction[] restoringMoves, StackSlot[] slots) {
+        this.savingMoves = savingMoves;
+        this.restoringMoves = restoringMoves;
         this.slots = slots;
     }
 
     @Override
     public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
-        for (int i = 0; i < savedRegisters.length; i++) {
-            if (savedRegisters[i] != null) {
-                StackSlot result = slots[i];
-                RegisterValue input = savedRegisters[i].asValue(result.getKind());
-                AMD64Move.move(tasm, masm, result, input);
-            } else {
-                assert savedRegisters[i] == null;
+        for (AMD64LIRInstruction savingMove : savingMoves) {
+            if (savingMove != null) {
+                savingMove.emitCode(tasm, masm);
             }
         }
     }
@@ -73,10 +76,12 @@
      */
     public void updateAndDescribePreservation(Set<Register> notSaved, DebugInfo debugInfo, FrameMap frameMap) {
         int preserved = 0;
-        for (int i = 0; i < savedRegisters.length; i++) {
-            if (savedRegisters[i] != null) {
-                if (notSaved.contains(savedRegisters[i])) {
-                    savedRegisters[i] = null;
+        for (int i = 0; i < savingMoves.length; i++) {
+            if (savingMoves[i] != null) {
+                Register register = ValueUtil.asRegister(((MoveOp) savingMoves[i]).getInput());
+                if (notSaved.contains(register)) {
+                    savingMoves[i] = null;
+                    restoringMoves[i] = null;
                 } else {
                     preserved++;
                 }
@@ -86,9 +91,9 @@
             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];
+            for (int i = 0; i < savingMoves.length; i++) {
+                if (savingMoves[i] != null) {
+                    keys[mapIndex] = ValueUtil.asRegister(((MoveOp) savingMoves[i]).getInput());
                     values[mapIndex] = frameMap.indexForStackSlot(slots[i]);
                     mapIndex++;
                 }
--- a/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXAddressValue.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXAddressValue.java	Tue Apr 30 23:09:37 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	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValue.java	Tue Apr 30 23:09:37 2013 +0200
@@ -45,7 +45,7 @@
 
     private final CompositeValueClass valueClass;
 
-    public CompositeValue(Kind kind) {
+    public CompositeValue(PlatformKind kind) {
         super(kind);
         valueClass = CompositeValueClass.get(getClass());
     }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java	Tue Apr 30 23:09:37 2013 +0200
@@ -197,7 +197,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) {
@@ -266,7 +266,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);
     }
 
@@ -277,12 +277,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;
@@ -291,7 +291,7 @@
                 }
             }
         }
-        int size = target.sizeInBytes(kind);
+        int size = target.arch.getSizeInBytes(kind);
         spillSize = NumUtil.roundUp(spillSize + size, size);
         return getSlot(kind, 0);
     }
@@ -299,8 +299,8 @@
     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) {
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/Variable.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/Variable.java	Tue Apr 30 23:09:37 2013 +0200
@@ -39,22 +39,15 @@
     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
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/BasicInductionVariable.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/BasicInductionVariable.java	Tue Apr 30 23:09:37 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	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/CountedLoopInfo.java	Tue Apr 30 23:09:37 2013 +0200
@@ -22,9 +22,14 @@
  */
 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.*;
 
 public class CountedLoopInfo {
 
@@ -32,19 +37,39 @@
     private InductionVariable iv;
     private ValueNode end;
     private boolean oneOff;
+    private ValueNode overflowGuard;
+    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 = (StructuredGraph) 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,53 @@
     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 ValueNode getOverFlowGuard() {
+        if (overflowGuard == null) {
+            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), add(iv.strideNode(), one));
+                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));
+        }
+        return overflowGuard;
+    }
+
+    public Kind getKind() {
+        return iv.valueNode().kind();
+    }
 }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedOffsetInductionVariable.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedOffsetInductionVariable.java	Tue Apr 30 23:09:37 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	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedScaledInductionVariable.java	Tue Apr 30 23:09:37 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	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariable.java	Tue Apr 30 23:09:37 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	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariables.java	Tue Apr 30 23:09:37 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	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopEx.java	Tue Apr 30 23:09:37 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;
@@ -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	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java	Tue Apr 30 23:09:37 2013 +0200
@@ -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,7 +183,7 @@
             }
         }
 
-        for (BeginNode b : blocks) {
+        for (AbstractBeginNode b : blocks) {
             for (Node n : b.getBlockNodes()) {
                 for (Node usage : n.usages()) {
                     markFloating(usage, nodes);
@@ -223,8 +223,8 @@
         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 +238,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	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInside.java	Tue Apr 30 23:09:37 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);
@@ -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	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java	Tue Apr 30 23:09:37 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	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java	Tue Apr 30 23:09:37 2013 +0200
@@ -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();
         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	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopsData.java	Tue Apr 30 23:09:37 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	Tue Apr 30 23:09:37 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<LowTierContext> {
+
+    @Override
+    protected void run(StructuredGraph graph, LowTierContext 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.loopBegin().dependencies().add(loop.counted().getOverFlowGuard());
+                    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	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformLowPhase.java	Tue Apr 30 23:09:37 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	Tue Apr 30 23:09:37 2013 +0200
@@ -0,0 +1,187 @@
+/*
+ * 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.spi.*;
+import com.oracle.graal.nodes.type.*;
+
+public abstract class AbstractBeginNode 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;
+    }
+
+    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());
+            ((StructuredGraph) 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 == ((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(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();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractEndNode.java	Tue Apr 30 23:09:37 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());
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java	Tue Apr 30 23:09:37 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	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginStateSplitNode.java	Tue Apr 30 23:09:37 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/ControlSplitNode.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ControlSplitNode.java	Tue Apr 30 23:09:37 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/EndNode.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/EndNode.java	Tue Apr 30 23:09:37 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	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/EntryMarkerNode.java	Tue Apr 30 23:09:37 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	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java	Tue Apr 30 23:09:37 2013 +0200
@@ -101,7 +101,8 @@
     }
 
     @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/GuardNode.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java	Tue Apr 30 23:09:37 2013 +0200
@@ -104,7 +104,8 @@
     }
 
     @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	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Tue Apr 30 23:09:37 2013 +0200
@@ -43,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;
 
@@ -58,10 +58,10 @@
     }
 
     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;
@@ -75,7 +75,7 @@
      * 
      * @return the true successor
      */
-    public BeginNode trueSuccessor() {
+    public AbstractBeginNode trueSuccessor() {
         return trueSuccessor;
     }
 
@@ -84,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;
     }
@@ -104,14 +104,15 @@
      * @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);
@@ -125,7 +126,7 @@
     }
 
     @Override
-    public double probability(BeginNode successor) {
+    public double probability(AbstractBeginNode successor) {
         return successor == trueSuccessor ? trueSuccessorProbability : 1 - trueSuccessorProbability;
     }
 
@@ -169,7 +170,7 @@
         }
 
         if (falseSuccessor().usages().isEmpty() && (!(falseSuccessor() instanceof LoopExitNode)) && falseSuccessor().next() instanceof IfNode) {
-            BeginNode intermediateBegin = falseSuccessor();
+            AbstractBeginNode intermediateBegin = falseSuccessor();
             IfNode nextIf = (IfNode) intermediateBegin.next();
             double probabilityB = (1.0 - this.trueSuccessorProbability) * nextIf.trueSuccessorProbability;
             if (this.trueSuccessorProbability < probabilityB) {
@@ -178,7 +179,7 @@
                 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;
-                    BeginNode bothFalseBegin = nextIf.falseSuccessor();
+                    AbstractBeginNode bothFalseBegin = nextIf.falseSuccessor();
                     nextIf.setFalseSuccessor(null);
                     intermediateBegin.setNext(null);
                     this.setFalseSuccessor(null);
@@ -322,9 +323,9 @@
      * @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();
@@ -447,7 +448,7 @@
             }
         }
 
-        List<EndNode> mergePredecessors = merge.cfgPredecessors().snapshot();
+        List<AbstractEndNode> mergePredecessors = merge.cfgPredecessors().snapshot();
         assert phi.valueCount() == merge.forwardEndCount();
 
         Constant[] xs = constantValues(compare.x(), merge);
@@ -461,19 +462,19 @@
             return false;
         }
 
-        List<EndNode> falseEnds = new ArrayList<>(mergePredecessors.size());
-        List<EndNode> trueEnds = new ArrayList<>(mergePredecessors.size());
-        Map<EndNode, ValueNode> phiValues = new HashMap<>(mergePredecessors.size());
+        List<AbstractEndNode> falseEnds = new ArrayList<>(mergePredecessors.size());
+        List<AbstractEndNode> trueEnds = new ArrayList<>(mergePredecessors.size());
+        Map<AbstractEndNode, ValueNode> phiValues = new HashMap<>(mergePredecessors.size());
 
-        BeginNode oldFalseSuccessor = falseSuccessor();
-        BeginNode oldTrueSuccessor = trueSuccessor();
+        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);
@@ -525,8 +526,8 @@
             } else if (node instanceof FixedWithNextNode) {
                 FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) node;
                 node = fixedWithNextNode.next();
-            } else if (node instanceof EndNode) {
-                EndNode endNode = (EndNode) node;
+            } else if (node instanceof AbstractEndNode) {
+                AbstractEndNode endNode = (AbstractEndNode) node;
                 node = endNode.merge();
             } else if (node instanceof ControlSinkNode) {
                 return true;
@@ -545,12 +546,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);
@@ -561,7 +562,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);
                 }
@@ -613,12 +614,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/InvokeWithExceptionNode.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Tue Apr 30 23:09:37 2013 +0200
@@ -34,7 +34,7 @@
 @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;
@@ -61,11 +61,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 +121,7 @@
     @Override
     public void setNext(FixedNode x) {
         if (x != null) {
-            this.setNext(BeginNode.begin(x));
+            this.setNext(AbstractBeginNode.begin(x));
         } else {
             this.setNext(null);
         }
@@ -170,7 +170,7 @@
     }
 
     public void killExceptionEdge() {
-        BeginNode edge = exceptionEdge();
+        AbstractBeginNode edge = exceptionEdge();
         setExceptionEdge(null);
         GraphUtil.killCFG(edge);
     }
@@ -205,7 +205,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;
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicBinaryNode.java	Tue Apr 30 23:09:37 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	Tue Apr 30 23:09:37 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	Tue Apr 30 23:09:37 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	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicNode.java	Tue Apr 30 23:09:37 2013 +0200
@@ -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	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java	Tue Apr 30 23:09:37 2013 +0200
@@ -87,7 +87,7 @@
         return snapshot;
     }
 
-    public EndNode forwardEnd() {
+    public AbstractEndNode forwardEnd() {
         assert forwardEndCount() == 1;
         return forwardEndAt(0);
     }
@@ -98,7 +98,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 +122,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 +136,7 @@
     }
 
     @Override
-    public EndNode phiPredecessorAt(int index) {
+    public AbstractEndNode phiPredecessorAt(int index) {
         if (index < forwardEndCount()) {
             return forwardEndAt(index);
         }
@@ -173,7 +173,7 @@
         // nothing yet
     }
 
-    public boolean isLoopExit(BeginNode begin) {
+    public boolean isLoopExit(AbstractBeginNode begin) {
         return begin instanceof LoopExitNode && ((LoopExitNode) begin).loopBegin() == this;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopEndNode.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopEndNode.java	Tue Apr 30 23:09:37 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	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java	Tue Apr 30 23:09:37 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;
@@ -169,8 +169,8 @@
             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));
                 } else {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java	Tue Apr 30 23:09:37 2013 +0200
@@ -159,7 +159,7 @@
         values.set(i, x);
     }
 
-    public ValueNode valueAt(EndNode pred) {
+    public ValueNode valueAt(AbstractEndNode pred) {
         return valueAt(merge().phiPredecessorIndex(pred));
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ProxyNode.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ProxyNode.java	Tue Apr 30 23:09:37 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/StructuredGraph.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Tue Apr 30 23:09:37 2013 +0200
@@ -50,14 +50,14 @@
     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);
@@ -214,8 +214,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();
@@ -251,7 +251,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 +260,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 +271,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 +287,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 +295,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 +348,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
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java	Tue Apr 30 23:09:37 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	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java	Tue Apr 30 23:09:37 2013 +0200
@@ -94,7 +94,8 @@
     }
 
     @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);
         return replacement;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java	Tue Apr 30 23:09:37 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, false),
+        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/IntegerDivNode.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java	Tue Apr 30 23:09:37 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/NegateNode.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java	Tue Apr 30 23:09:37 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/cfg/Block.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java	Tue Apr 30 23:09:37 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/ControlFlowGraph.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java	Tue Apr 30 23:09:37 2013 +0200
@@ -58,7 +58,7 @@
 
     protected ControlFlowGraph(StructuredGraph graph) {
         this.graph = graph;
-        this.nodeToBlock = graph.createNodeMap();
+        this.nodeToBlock = graph.createNodeMap(true);
     }
 
     public Block[] getBlocks() {
@@ -135,7 +135,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 +144,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 +247,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);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IntegerSwitchNode.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IntegerSwitchNode.java	Tue Apr 30 23:09:37 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);
     }
 
     /**
@@ -124,7 +124,7 @@
                     tool.addToWorkList(defaultSuccessor());
                     ((StructuredGraph) 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);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SwitchNode.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SwitchNode.java	Tue Apr 30 23:09:37 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,7 +45,7 @@
      * @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);
@@ -55,7 +55,7 @@
     }
 
     @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 +89,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 +107,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 +124,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/UnsafeCastNode.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java	Tue Apr 30 23:09:37 2013 +0200
@@ -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/ValueAnchorNode.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java	Tue Apr 30 23:09:37 2013 +0200
@@ -100,7 +100,7 @@
         if (permanent) {
             return;
         }
-        for (ValueNode node : dependencies().nonNull().and(isNotA(BeginNode.class))) {
+        for (ValueNode node : dependencies().nonNull().and(isNotA(AbstractBeginNode.class))) {
             State state = tool.getObjectState(node);
             if (state == null || state.getState() != EscapeState.Virtual) {
                 return;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeSwitchNode.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeSwitchNode.java	Tue Apr 30 23:09:37 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;
@@ -110,7 +110,7 @@
                     tool.addToWorkList(defaultSuccessor());
                     ((StructuredGraph) 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	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java	Tue Apr 30 23:09:37 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/Negatable.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Negatable.java	Tue Apr 30 23:09:37 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/util/ComputeImmediateDominator.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/ComputeImmediateDominator.java	Tue Apr 30 23:09:37 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	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Tue Apr 30 23:09:37 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,7 +63,7 @@
         propagateKill(node);
     }
 
-    private static void killEnd(EndNode end) {
+    private static void killEnd(AbstractEndNode end) {
         MergeNode merge = end.merge();
         if (merge != null) {
             merge.removeEnd(end);
@@ -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();
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java	Tue Apr 30 23:09:37 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	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertDeoptimizeToGuardPhase.java	Tue Apr 30 23:09:37 2013 +0200
@@ -32,11 +32,11 @@
 
 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();
             }
@@ -57,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);
             }
@@ -75,7 +75,7 @@
             return;
         } else if (deoptBegin.predecessor() instanceof IfNode) {
             IfNode ifNode = (IfNode) deoptBegin.predecessor();
-            BeginNode otherBegin = ifNode.trueSuccessor();
+            AbstractBeginNode otherBegin = ifNode.trueSuccessor();
             LogicNode conditionNode = ifNode.condition();
             FixedGuardNode guard = graph.add(new FixedGuardNode(conditionNode, deopt.reason(), deopt.action(), deoptBegin == ifNode.trueSuccessor()));
             FixedWithNextNode pred = (FixedWithNextNode) ifNode.predecessor();
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CullFrameStatesPhase.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CullFrameStatesPhase.java	Tue Apr 30 23:09:37 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	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeadCodeEliminationPhase.java	Tue Apr 30 23:09:37 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	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/EliminatePartiallyRedundantGuardsPhase.java	Tue Apr 30 23:09:37 2013 +0200
@@ -119,8 +119,8 @@
             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) {
@@ -140,8 +140,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,7 +152,7 @@
     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;
@@ -175,9 +175,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.dependencies().first();
                 begins.add(begin);
                 if (guard.action().ordinal() > action.ordinal()) {
                     action = guard.action();
@@ -191,7 +191,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	Tue Apr 30 23:09:37 2013 +0200
@@ -0,0 +1,95 @@
+/*
+ * 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);
+        }
+    }
+
+    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	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java	Tue Apr 30 23:09:37 2013 +0200
@@ -105,7 +105,7 @@
         }
 
         @Override
-        protected Set<Object> afterSplit(BeginNode node, Set<Object> oldState) {
+        protected Set<Object> afterSplit(AbstractBeginNode node, Set<Object> oldState) {
             return new HashSet<>(oldState);
         }
 
@@ -214,7 +214,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) {
                 /*
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java	Tue Apr 30 23:09:37 2013 +0200
@@ -171,11 +171,11 @@
 
         private void lowerToIf(GuardNode guard) {
             StructuredGraph graph = (StructuredGraph) guard.graph();
-            BeginNode fastPath = graph.add(new BeginNode());
+            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;
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java	Tue Apr 30 23:09:37 2013 +0200
@@ -532,7 +532,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	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Tue Apr 30 23:09:37 2013 +0200
@@ -495,7 +495,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);
             }
@@ -507,7 +507,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) {
@@ -533,7 +533,7 @@
 
             // 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;
@@ -616,10 +616,10 @@
         private void inlineSingleMethod(StructuredGraph graph, InliningCallback callback, Replacements replacements, Assumptions assumptions, MetaAccessProvider runtime) {
             assert concretes.size() == 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};
+            AbstractBeginNode unknownTypeSux = createUnknownTypeSuccessor(graph);
+            AbstractBeginNode[] successors = new AbstractBeginNode[]{calleeEntryNode, unknownTypeSux};
             createDispatchOnTypeBeforeInvoke(graph, successors, false, runtime);
 
             calleeEntryNode.setNext(invoke.asNode());
@@ -628,7 +628,7 @@
             inline(invoke, concrete, callback, replacements, assumptions, false);
         }
 
-        private boolean createDispatchOnTypeBeforeInvoke(StructuredGraph graph, BeginNode[] successors, boolean invokeIsOnlySuccessor, MetaAccessProvider runtime) {
+        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();
@@ -728,13 +728,13 @@
             return costEstimateMethodDispatch < costEstimateTypeDispatch;
         }
 
-        private static BeginNode createInvocationBlock(StructuredGraph graph, Invoke invoke, MergeNode returnMerge, PhiNode returnValuePhi, MergeNode exceptionMerge, PhiNode exceptionObjectPhi,
-                        boolean useForInlining) {
+        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);
 
@@ -769,7 +769,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,9 +812,9 @@
         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};
+            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());
@@ -824,8 +824,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
@@ -1175,7 +1175,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;
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java	Tue Apr 30 23:09:37 2013 +0200
@@ -169,7 +169,7 @@
             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();
@@ -246,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);
@@ -269,14 +269,14 @@
                 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
@@ -293,7 +293,7 @@
                 endIndex++;
             }
             GraphUtil.killCFG(merge);
-            for (EndNode forwardEnd : endSnapshot) {
+            for (AbstractEndNode forwardEnd : endSnapshot) {
                 forwardEnd.safeDelete();
             }
             for (PhiNode phi : phiSnapshot) {
@@ -428,9 +428,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	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Tue Apr 30 23:09:37 2013 +0200
@@ -37,6 +37,7 @@
     public static int     Threads                            = 4;
 
     public static String  CompilerConfiguration              = "basic";
+    public static String  GraalRuntime                       = "basic";
 
     // inlining settings
     public static boolean Inline                             = true;
@@ -106,6 +107,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              = ____;
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/OptimisticOptimizations.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/OptimisticOptimizations.java	Tue Apr 30 23:09:37 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)) {
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ComputeInliningRelevanceClosure.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ComputeInliningRelevanceClosure.java	Tue Apr 30 23:09:37 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	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ComputeProbabilityClosure.java	Tue Apr 30 23:09:37 2013 +0200
@@ -208,7 +208,7 @@
         }
 
         @Override
-        public void afterSplit(BeginNode node) {
+        public void afterSplit(AbstractBeginNode node) {
             assert node.predecessor() != null;
             Node pred = node.predecessor();
             if (pred instanceof Invoke) {
@@ -275,7 +275,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	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/MergeableState.java	Tue Apr 30 23:09:37 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	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/PostOrderNodeIterator.java	Tue Apr 30 23:09:37 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	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantBlockIterator.java	Tue Apr 30 23:09:37 2013 +0200
@@ -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;
@@ -162,7 +162,7 @@
                     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);
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantNodeIterator.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantNodeIterator.java	Tue Apr 30 23:09:37 2013 +0200
@@ -41,7 +41,7 @@
 
         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;
@@ -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	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ScopedPostOrderNodeIterator.java	Tue Apr 30 23:09:37 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	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Tue Apr 30 23:09:37 2013 +0200
@@ -652,7 +652,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/LowTierContext.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/LowTierContext.java	Tue Apr 30 23:09:37 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 LowTierContext extends PhaseContext {
 
     private final TargetDescription target;
+    private final OptimisticOptimizations optimisticOpts;
 
-    public LowTierContext(MetaAccessProvider runtime, Assumptions assumptions, Replacements replacements, TargetDescription target) {
+    public LowTierContext(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.printer/src/com/oracle/graal/printer/CFGPrinter.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java	Tue Apr 30 23:09:37 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 {
@@ -471,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/IdealGraphPrinter.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinter.java	Tue Apr 30 23:09:37 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	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.ptx/src/com/oracle/graal/ptx/PTX.java	Tue Apr 30 23:09:37 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/src/com/oracle/graal/replacements/SnippetFrameStateCleanupPhase.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetFrameStateCleanupPhase.java	Tue Apr 30 23:09:37 2013 +0200
@@ -93,7 +93,7 @@
         }
 
         @Override
-        protected CleanupState afterSplit(BeginNode node, CleanupState oldState) {
+        protected CleanupState afterSplit(AbstractBeginNode node, CleanupState oldState) {
             return new CleanupState(oldState.containsFrameState);
         }
 
--- a/graal/com.oracle.graal.sparc/src/com/oracle/graal/sparc/SPARC.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.sparc/src/com/oracle/graal/sparc/SPARC.java	Tue Apr 30 23:09:37 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/phases/ea/PartialEscapeAnalysisPhase.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java	Tue Apr 30 23:09:37 2013 +0200
@@ -139,8 +139,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);
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java	Tue Apr 30 00:53:33 2013 +0200
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java	Tue Apr 30 23:09:37 2013 +0200
@@ -272,7 +272,7 @@
         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.dependencies().add(AbstractBeginNode.prevBegin(invoke.asNode()));
         return read;
     }
 
--- a/make/bsd/makefiles/buildtree.make	Tue Apr 30 00:53:33 2013 +0200
+++ b/make/bsd/makefiles/buildtree.make	Tue Apr 30 23:09:37 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	Tue Apr 30 00:53:33 2013 +0200
+++ b/make/bsd/makefiles/launcher.make	Tue Apr 30 23:09:37 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	Tue Apr 30 00:53:33 2013 +0200
+++ b/make/bsd/makefiles/vm.make	Tue Apr 30 23:09:37 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	Tue Apr 30 00:53:33 2013 +0200
+++ b/make/linux/makefiles/buildtree.make	Tue Apr 30 23:09:37 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	Tue Apr 30 00:53:33 2013 +0200
+++ b/make/linux/makefiles/vm.make	Tue Apr 30 23:09:37 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/mx/projects	Tue Apr 30 00:53:33 2013 +0200
+++ b/mx/projects	Tue Apr 30 23:09:37 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
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gpu/ptx/gpu_ptx.cpp	Tue Apr 30 23:09:37 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 "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	Tue Apr 30 23:09:37 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	Tue Apr 30 23:09:37 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 <CoreGraphics/CoreGraphics.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
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/os/bsd/vm/gpu_bsd.hpp	Tue Apr 30 23:09:37 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/vm/graal/graalCompiler.cpp	Tue Apr 30 00:53:33 2013 +0200
+++ b/src/share/vm/graal/graalCompiler.cpp	Tue Apr 30 23:09:37 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"
@@ -65,6 +66,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	Tue Apr 30 23:09:37 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	Tue Apr 30 23:09:37 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	Tue Apr 30 00:53:33 2013 +0200
+++ b/src/share/vm/graal/graalCompilerToVM.cpp	Tue Apr 30 23:09:37 2013 +0200
@@ -802,6 +802,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);
--- a/src/share/vm/runtime/globals.hpp	Tue Apr 30 00:53:33 2013 +0200
+++ b/src/share/vm/runtime/globals.hpp	Tue Apr 30 23:09:37 2013 +0200
@@ -3691,6 +3691,9 @@
   product(bool , AllowNonVirtualCalls, false,                               \
           "Obey the ACC_SUPER flag and allow invokenonvirtual calls")       \
                                                                             \
+  develop(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	Tue Apr 30 23:09:37 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	Tue Apr 30 23:09:37 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/thread.cpp	Tue Apr 30 00:53:33 2013 +0200
+++ b/src/share/vm/runtime/thread.cpp	Tue Apr 30 23:09:37 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();