changeset 19874:825f5c7468bd

Merge
author Stefan Anzinger <stefan.anzinger@oracle.com>
date Tue, 17 Mar 2015 12:05:51 +0100
parents 8e316bc46018 (current diff) ab898f9f9c3c (diff)
children 823074fd8410 6d142d351bf7 749b96e8ff90
files graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCompare.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArrayStubCall.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceStubCall.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewMultiArrayStubCall.java graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BitManipulationOp.java graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Compare.java graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64TestMemoryOp.java graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64TestOp.java
diffstat 167 files changed, 4490 insertions(+), 5501 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ForeignCallsProvider.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ForeignCallsProvider.java	Tue Mar 17 12:05:51 2015 +0100
@@ -37,8 +37,8 @@
 
     /**
      * Gets the set of memory locations killed by a given foreign call. Returning the special value
-     * {@link LocationIdentity#ANY_LOCATION} denotes that the call kills all memory locations.
-     * Returning any empty array denotes that the call does not kill any memory locations.
+     * {@link LocationIdentity#any()} denotes that the call kills all memory locations. Returning
+     * any empty array denotes that the call does not kill any memory locations.
      */
     LocationIdentity[] getKilledLocations(ForeignCallDescriptor descriptor);
 
--- a/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaField.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaField.java	Tue Mar 17 12:05:51 2015 +0100
@@ -71,6 +71,14 @@
     }
 
     @Test
+    public void getLocationIdentityTest() {
+        for (Map.Entry<Field, ResolvedJavaField> e : fields.entrySet()) {
+            LocationIdentity identity = e.getValue().getLocationIdentity();
+            assertTrue(identity != null);
+        }
+    }
+
+    @Test
     public void readConstantValueTest() throws NoSuchFieldException {
         ResolvedJavaField field = metaAccess.lookupJavaField(getClass().getDeclaredField("stringField"));
         for (Object receiver : new Object[]{this, null, new String()}) {
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LocationIdentity.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LocationIdentity.java	Tue Mar 17 12:05:51 2015 +0100
@@ -33,30 +33,56 @@
  * comparing two {@link LocationIdentity} values for equality. Likewise, they must not use
  * {@link IdentityHashMap}s with {@link LocationIdentity} values as keys.
  */
-public interface LocationIdentity extends TrustedInterface {
+public abstract class LocationIdentity {
 
     /**
      * Denotes any location. A write to such a location kills all values in a memory map during an
      * analysis of memory accesses. A read from this location cannot be moved or coalesced with
      * other reads because its interaction with other reads is not known.
      */
-    LocationIdentity ANY_LOCATION = NamedLocationIdentity.mutable("ANY_LOCATION");
+    private static final LocationIdentity ANY_LOCATION = NamedLocationIdentity.mutable("ANY_LOCATION");
 
     /**
      * Denotes the location of a value that is guaranteed to be unchanging.
      */
-    LocationIdentity FINAL_LOCATION = NamedLocationIdentity.immutable("FINAL_LOCATION");
+    public static final LocationIdentity FINAL_LOCATION = NamedLocationIdentity.immutable("FINAL_LOCATION");
 
     /**
      * Denotes the location of the length field of a Java array.
      */
-    LocationIdentity ARRAY_LENGTH_LOCATION = NamedLocationIdentity.immutable("[].length");
+    public static final LocationIdentity ARRAY_LENGTH_LOCATION = NamedLocationIdentity.immutable("[].length");
+
+    protected final boolean immutable;
+
+    public static LocationIdentity any() {
+        return ANY_LOCATION;
+    }
+
+    protected LocationIdentity(boolean immutable) {
+        this.immutable = immutable;
+    }
 
     /**
      * Denotes a location is unchanging in all cases. Not that this is different than the Java
      * notion of final which only requires definite assignment.
      */
-    default boolean isImmutable() {
-        return false;
+    public final boolean isImmutable() {
+        return immutable;
+    }
+
+    public final boolean isMutable() {
+        return !immutable;
+    }
+
+    public final boolean isAny() {
+        return this == ANY_LOCATION;
+    }
+
+    public final boolean isSingle() {
+        return this != ANY_LOCATION;
+    }
+
+    public final boolean overlaps(LocationIdentity other) {
+        return isAny() || other.isAny() || this.equals(other);
     }
 }
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/NamedLocationIdentity.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/NamedLocationIdentity.java	Tue Mar 17 12:05:51 2015 +0100
@@ -29,7 +29,7 @@
 /**
  * A {@link LocationIdentity} with a name.
  */
-public final class NamedLocationIdentity implements LocationIdentity, FormatWithToString {
+public final class NamedLocationIdentity extends LocationIdentity implements FormatWithToString {
 
     /**
      * Map for asserting all {@link NamedLocationIdentity} instances have a unique name.
@@ -48,11 +48,9 @@
 
     protected final String name;
 
-    protected final boolean immutable;
-
     private NamedLocationIdentity(String name, boolean immutable) {
+        super(immutable);
         this.name = name;
-        this.immutable = immutable;
     }
 
     /**
@@ -89,31 +87,8 @@
     }
 
     @Override
-    public int hashCode() {
-        return name.hashCode();
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (obj == this) {
-            return true;
-        }
-        if (obj instanceof NamedLocationIdentity) {
-            NamedLocationIdentity that = (NamedLocationIdentity) obj;
-            boolean res = this.name.equals(that.name);
-            assert !res || this.immutable == that.immutable;
-            return res;
-        }
-        return false;
-    }
-
-    @Override
     public String toString() {
-        return name + (immutable ? ":immutable" : ":mutable");
-    }
-
-    public boolean isImmutable() {
-        return immutable;
+        return name + (isImmutable() ? ":immutable" : ":mutable");
     }
 
     /**
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaField.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaField.java	Tue Mar 17 12:05:51 2015 +0100
@@ -29,7 +29,7 @@
  * Represents a reference to a resolved Java field. Fields, like methods and types, are resolved
  * through {@link ConstantPool constant pools}.
  */
-public interface ResolvedJavaField extends JavaField, LocationIdentity, ModifiersProvider {
+public interface ResolvedJavaField extends JavaField, ModifiersProvider {
 
     /**
      * {@inheritDoc}
@@ -65,4 +65,11 @@
      *         else {@code null}
      */
     <T extends Annotation> T getAnnotation(Class<T> annotationClass);
+
+    /**
+     * Returns an object representing the unique location identity of this resolved Java field.
+     * 
+     * @return the location identity of the field
+     */
+    LocationIdentity getLocationIdentity();
 }
--- a/graal/com.oracle.graal.asm.amd64.test/src/com/oracle/graal/asm/amd64/test/BitOpsTest.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.asm.amd64.test/src/com/oracle/graal/asm/amd64/test/BitOpsTest.java	Tue Mar 17 12:05:51 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,16 +24,18 @@
 package com.oracle.graal.asm.amd64.test;
 
 import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp.*;
+import static com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize.*;
 import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 import static org.junit.Assume.*;
 
-import org.junit.*;
-
 import java.lang.reflect.*;
 import java.util.*;
 
+import org.junit.*;
+
 import com.oracle.graal.amd64.*;
-import com.oracle.graal.amd64.AMD64.*;
+import com.oracle.graal.amd64.AMD64.CPUFeature;
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.amd64.*;
@@ -61,7 +63,7 @@
                     AMD64Assembler asm = new AMD64Assembler(target, registerConfig);
                     Register ret = registerConfig.getReturnRegister(Kind.Int);
                     Register arg = asRegister(cc.getArgument(0));
-                    asm.lzcntl(ret, arg);
+                    LZCNT.emit(asm, DWORD, ret, arg);
                     asm.ret(0);
                     return asm.close(true);
                 }
@@ -82,7 +84,7 @@
                     try {
                         Field f = IntField.class.getDeclaredField("x");
                         AMD64Address arg = new AMD64Address(asRegister(cc.getArgument(0)), (int) unsafe.objectFieldOffset(f));
-                        asm.lzcntl(ret, arg);
+                        LZCNT.emit(asm, DWORD, ret, arg);
                         asm.ret(0);
                         return asm.close(true);
                     } catch (Exception e) {
@@ -104,7 +106,7 @@
                     AMD64Assembler asm = new AMD64Assembler(target, registerConfig);
                     Register ret = registerConfig.getReturnRegister(Kind.Int);
                     Register arg = asRegister(cc.getArgument(0));
-                    asm.lzcntq(ret, arg);
+                    LZCNT.emit(asm, QWORD, ret, arg);
                     asm.ret(0);
                     return asm.close(true);
                 }
@@ -125,7 +127,7 @@
                     try {
                         Field f = LongField.class.getDeclaredField("x");
                         AMD64Address arg = new AMD64Address(asRegister(cc.getArgument(0)), (int) unsafe.objectFieldOffset(f));
-                        asm.lzcntq(ret, arg);
+                        LZCNT.emit(asm, QWORD, ret, arg);
                         asm.ret(0);
                         return asm.close(true);
                     } catch (Exception e) {
@@ -147,7 +149,7 @@
                     AMD64Assembler asm = new AMD64Assembler(target, registerConfig);
                     Register ret = registerConfig.getReturnRegister(Kind.Int);
                     Register arg = asRegister(cc.getArgument(0));
-                    asm.tzcntl(ret, arg);
+                    TZCNT.emit(asm, DWORD, ret, arg);
                     asm.ret(0);
                     return asm.close(true);
                 }
@@ -168,7 +170,7 @@
                     try {
                         Field f = IntField.class.getDeclaredField("x");
                         AMD64Address arg = new AMD64Address(asRegister(cc.getArgument(0)), (int) unsafe.objectFieldOffset(f));
-                        asm.tzcntl(ret, arg);
+                        TZCNT.emit(asm, DWORD, ret, arg);
                         asm.ret(0);
                         return asm.close(true);
                     } catch (Exception e) {
@@ -190,7 +192,7 @@
                     AMD64Assembler asm = new AMD64Assembler(target, registerConfig);
                     Register ret = registerConfig.getReturnRegister(Kind.Int);
                     Register arg = asRegister(cc.getArgument(0));
-                    asm.tzcntq(ret, arg);
+                    TZCNT.emit(asm, QWORD, ret, arg);
                     asm.ret(0);
                     return asm.close(true);
                 }
@@ -211,7 +213,7 @@
                     try {
                         Field f = LongField.class.getDeclaredField("x");
                         AMD64Address arg = new AMD64Address(asRegister(cc.getArgument(0)), (int) unsafe.objectFieldOffset(f));
-                        asm.tzcntq(ret, arg);
+                        TZCNT.emit(asm, QWORD, ret, arg);
                         asm.ret(0);
                         return asm.close(true);
                     } catch (Exception e) {
--- a/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java	Tue Mar 17 12:05:51 2015 +0100
@@ -26,10 +26,13 @@
 import static com.oracle.graal.api.code.MemoryBarriers.*;
 import static com.oracle.graal.asm.NumUtil.*;
 import static com.oracle.graal.asm.amd64.AMD64AsmOptions.*;
+import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.*;
+import static com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize.*;
 
 import com.oracle.graal.amd64.*;
 import com.oracle.graal.amd64.AMD64.CPUFeature;
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.code.Register.RegisterCategory;
 import com.oracle.graal.asm.*;
 
 /**
@@ -158,6 +161,131 @@
     }
 
     /**
+     * The x86 operand sizes.
+     */
+    public static enum OperandSize {
+        BYTE(1) {
+            @Override
+            protected void emitImmediate(AMD64Assembler asm, int imm) {
+                assert imm == (byte) imm;
+                asm.emitByte(imm);
+            }
+        },
+
+        WORD(2, 0x66) {
+            @Override
+            protected void emitImmediate(AMD64Assembler asm, int imm) {
+                assert imm == (short) imm;
+                asm.emitShort(imm);
+            }
+        },
+
+        DWORD(4) {
+            @Override
+            protected void emitImmediate(AMD64Assembler asm, int imm) {
+                asm.emitInt(imm);
+            }
+        },
+
+        QWORD(8) {
+            @Override
+            protected void emitImmediate(AMD64Assembler asm, int imm) {
+                asm.emitInt(imm);
+            }
+        },
+
+        SS(4, 0xF3, true),
+
+        SD(8, 0xF2, true),
+
+        PS(16, true),
+
+        PD(16, 0x66, true);
+
+        private final int sizePrefix;
+
+        private final int bytes;
+        private final boolean xmm;
+
+        private OperandSize(int bytes) {
+            this(bytes, 0);
+        }
+
+        private OperandSize(int bytes, int sizePrefix) {
+            this(bytes, sizePrefix, false);
+        }
+
+        private OperandSize(int bytes, boolean xmm) {
+            this(bytes, 0, xmm);
+        }
+
+        private OperandSize(int bytes, int sizePrefix, boolean xmm) {
+            this.sizePrefix = sizePrefix;
+            this.bytes = bytes;
+            this.xmm = xmm;
+        }
+
+        public int getBytes() {
+            return bytes;
+        }
+
+        public boolean isXmmType() {
+            return xmm;
+        }
+
+        /**
+         * Emit an immediate of this size. Note that immediate {@link #QWORD} operands are encoded
+         * as sign-extended 32-bit values.
+         *
+         * @param asm
+         * @param imm
+         */
+        protected void emitImmediate(AMD64Assembler asm, int imm) {
+            assert false;
+        }
+    }
+
+    /**
+     * Operand size and register type constraints.
+     */
+    private static enum OpAssertion {
+        ByteAssertion(CPU, CPU, BYTE),
+        IntegerAssertion(CPU, CPU, WORD, DWORD, QWORD),
+        No16BitAssertion(CPU, CPU, DWORD, QWORD),
+        QwordOnlyAssertion(CPU, CPU, QWORD),
+        FloatingAssertion(XMM, XMM, SS, SD, PS, PD),
+        PackedFloatingAssertion(XMM, XMM, PS, PD),
+        SingleAssertion(XMM, XMM, SS),
+        DoubleAssertion(XMM, XMM, SD),
+        IntToFloatingAssertion(XMM, CPU, DWORD, QWORD),
+        FloatingToIntAssertion(CPU, XMM, DWORD, QWORD);
+
+        private final RegisterCategory resultCategory;
+        private final RegisterCategory inputCategory;
+        private final OperandSize[] allowedSizes;
+
+        private OpAssertion(RegisterCategory resultCategory, RegisterCategory inputCategory, OperandSize... allowedSizes) {
+            this.resultCategory = resultCategory;
+            this.inputCategory = inputCategory;
+            this.allowedSizes = allowedSizes;
+        }
+
+        protected boolean checkOperands(AMD64Op op, OperandSize size, Register resultReg, Register inputReg) {
+            assert resultReg == null || resultCategory.equals(resultReg.getRegisterCategory()) : "invalid result register " + resultReg + " used in " + op;
+            assert inputReg == null || inputCategory.equals(inputReg.getRegisterCategory()) : "invalid input register " + inputReg + " used in " + op;
+
+            for (OperandSize s : allowedSizes) {
+                if (size == s) {
+                    return true;
+                }
+            }
+
+            assert false : "invalid operand size " + size + " used in " + op;
+            return false;
+        }
+    }
+
+    /**
      * The register to which {@link Register#Frame} and {@link Register#CallerFrame} are bound.
      */
     public final Register frameRegister;
@@ -184,97 +312,65 @@
         return r.encoding & 0x7;
     }
 
-    private void emitArithImm8(int op, Register dst, int imm8) {
-        int encode = prefixAndEncode(op, false, dst.encoding, true);
-        emitByte(0x80);
-        emitByte(0xC0 | encode);
-        emitByte(imm8);
-    }
-
-    private void emitArithImm16(int op, Register dst, int imm16) {
-        emitByte(0x66);
-        int encode = prefixAndEncode(op, dst.encoding);
-        if (isByte(imm16)) {
-            emitByte(0x83); // imm8 sign extend
-            emitByte(0xC0 | encode);
-            emitByte(imm16 & 0xFF);
-        } else {
-            emitByte(0x81);
-            emitByte(0xC0 | encode);
-            emitShort(imm16);
-        }
-    }
-
-    private void emitArithImm32(int op, Register dst, int imm32) {
-        int encode = prefixAndEncode(op, dst.encoding);
-        if (isByte(imm32)) {
-            emitByte(0x83); // imm8 sign extend
-            emitByte(0xC0 | encode);
-            emitByte(imm32 & 0xFF);
-        } else {
-            emitByte(0x81);
-            emitByte(0xC0 | encode);
-            emitInt(imm32);
-        }
-    }
-
-    private void emitArithImm32q(int op, Register dst, int imm32) {
-        emitArithImm32q(op, dst, imm32, false);
+    /**
+     * Get RXB bits for register-register instruction. In that encoding, ModRM.rm contains a
+     * register index. The R bit extends the ModRM.reg field and the B bit extends the ModRM.rm
+     * field. The X bit must be 0.
+     */
+    protected static int getRXB(Register reg, Register rm) {
+        int rxb = (reg == null ? 0 : reg.encoding & 0x08) >> 1;
+        rxb |= (rm == null ? 0 : rm.encoding & 0x08) >> 3;
+        return rxb;
     }
 
-    private void emitArithImm32q(int op, Register dst, int imm32, boolean force32Imm) {
-        int encode = prefixqAndEncode(op, dst.encoding);
-        if (isByte(imm32) && !force32Imm) {
-            emitByte(0x83); // imm8 sign extend
-            emitByte(0xC0 | encode);
-            emitByte(imm32 & 0xFF);
-        } else {
-            emitByte(0x81);
-            emitByte(0xC0 | encode);
-            emitInt(imm32);
+    /**
+     * Get RXB bits for register-memory instruction. The R bit extends the ModRM.reg field. There
+     * are two cases for the memory operand:<br>
+     * ModRM.rm contains the base register: In that case, B extends the ModRM.rm field and X = 0.<br>
+     * There is an SIB byte: In that case, X extends SIB.index and B extends SIB.base.
+     */
+    protected static int getRXB(Register reg, AMD64Address rm) {
+        int rxb = (reg == null ? 0 : reg.encoding & 0x08) >> 1;
+        if (!rm.getIndex().equals(Register.None)) {
+            rxb |= (rm.getIndex().encoding & 0x08) >> 2;
         }
-    }
-
-    // immediate-to-memory forms
-    private void emitArithImm8(int op, AMD64Address adr, int imm8) {
-        prefix(adr);
-        emitByte(0x80);
-        emitOperandHelper(op, adr);
-        emitByte(imm8);
+        if (!rm.getBase().equals(Register.None)) {
+            rxb |= (rm.getBase().encoding & 0x08) >> 3;
+        }
+        return rxb;
     }
 
-    private void emitArithImm16(int op, AMD64Address adr, int imm16) {
-        emitByte(0x66);
-        prefix(adr);
-        if (isByte(imm16)) {
-            emitByte(0x83); // imm8 sign extend
-            emitOperandHelper(op, adr);
-            emitByte(imm16 & 0xFF);
-        } else {
-            emitByte(0x81);
-            emitOperandHelper(op, adr);
-            emitShort(imm16);
-        }
+    /**
+     * Emit the ModR/M byte for one register operand and an opcode extension in the R field.
+     * <p>
+     * Format: [ 11 reg r/m ]
+     */
+    protected void emitModRM(int reg, Register rm) {
+        assert (reg & 0x07) == reg;
+        emitByte(0xC0 | (reg << 3) | (rm.encoding & 0x07));
     }
 
-    private void emitArithImm32(int op, AMD64Address adr, int imm32) {
-        prefix(adr);
-        if (isByte(imm32)) {
-            emitByte(0x83); // imm8 sign extend
-            emitOperandHelper(op, adr);
-            emitByte(imm32 & 0xFF);
-        } else {
-            emitByte(0x81);
-            emitOperandHelper(op, adr);
-            emitInt(imm32);
-        }
+    /**
+     * Emit the ModR/M byte for two register operands.
+     * <p>
+     * Format: [ 11 reg r/m ]
+     */
+    protected void emitModRM(Register reg, Register rm) {
+        emitModRM(reg.encoding & 0x07, rm);
     }
 
+    /**
+     * Emits the ModR/M byte and optionally the SIB byte for one register and one memory operand.
+     */
     protected void emitOperandHelper(Register reg, AMD64Address addr) {
         assert !reg.equals(Register.None);
         emitOperandHelper(encode(reg), addr);
     }
 
+    /**
+     * Emits the ModR/M byte and optionally the SIB byte for one memory operand and an opcode
+     * extension in the R field.
+     */
     protected void emitOperandHelper(int reg, AMD64Address addr) {
         assert (reg & 0x07) == reg;
         int regenc = reg << 3;
@@ -379,24 +475,470 @@
         }
     }
 
+    /**
+     * Base class for AMD64 opcodes.
+     */
+    public static class AMD64Op {
+
+        protected static final int P_0F = 0x0F;
+        protected static final int P_0F38 = 0x380F;
+        protected static final int P_0F3A = 0x3A0F;
+
+        private final String opcode;
+
+        private final int prefix1;
+        private final int prefix2;
+        private final int op;
+
+        private final boolean dstIsByte;
+        private final boolean srcIsByte;
+
+        private final OpAssertion assertion;
+        private final CPUFeature feature;
+
+        protected AMD64Op(String opcode, int prefix1, int prefix2, int op, OpAssertion assertion, CPUFeature feature) {
+            this(opcode, prefix1, prefix2, op, assertion == OpAssertion.ByteAssertion, assertion == OpAssertion.ByteAssertion, assertion, feature);
+        }
+
+        protected AMD64Op(String opcode, int prefix1, int prefix2, int op, boolean dstIsByte, boolean srcIsByte, OpAssertion assertion, CPUFeature feature) {
+            this.opcode = opcode;
+            this.prefix1 = prefix1;
+            this.prefix2 = prefix2;
+            this.op = op;
+
+            this.dstIsByte = dstIsByte;
+            this.srcIsByte = srcIsByte;
+
+            this.assertion = assertion;
+            this.feature = feature;
+        }
+
+        protected final void emitOpcode(AMD64Assembler asm, OperandSize size, int rxb, int dstEnc, int srcEnc) {
+            if (prefix1 != 0) {
+                asm.emitByte(prefix1);
+            }
+            if (size.sizePrefix != 0) {
+                asm.emitByte(size.sizePrefix);
+            }
+            int rexPrefix = 0x40 | rxb;
+            if (size == QWORD) {
+                rexPrefix |= 0x08;
+            }
+            if (rexPrefix != 0x40 || (dstIsByte && dstEnc >= 4) || (srcIsByte && srcEnc >= 4)) {
+                asm.emitByte(rexPrefix);
+            }
+            if (prefix2 > 0xFF) {
+                asm.emitShort(prefix2);
+            } else if (prefix2 > 0) {
+                asm.emitByte(prefix2);
+            }
+            asm.emitByte(op);
+        }
+
+        protected final boolean verify(AMD64Assembler asm, OperandSize size, Register resultReg, Register inputReg) {
+            assert feature == null || asm.supports(feature) : String.format("unsupported feature %s required for %s", feature, opcode);
+            assert assertion.checkOperands(this, size, resultReg, inputReg);
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            return opcode;
+        }
+    }
+
+    /**
+     * Base class for AMD64 opcodes with immediate operands.
+     */
+    public static class AMD64ImmOp extends AMD64Op {
+
+        private final boolean immIsByte;
+
+        protected AMD64ImmOp(String opcode, boolean immIsByte, int prefix, int op, OpAssertion assertion) {
+            super(opcode, 0, prefix, op, assertion, null);
+            this.immIsByte = immIsByte;
+        }
+
+        protected final void emitImmediate(AMD64Assembler asm, OperandSize size, int imm) {
+            if (immIsByte) {
+                assert imm == (byte) imm;
+                asm.emitByte(imm);
+            } else {
+                size.emitImmediate(asm, imm);
+            }
+        }
+    }
+
+    /**
+     * Opcode with operand order of either RM or MR.
+     */
+    public abstract static class AMD64RROp extends AMD64Op {
+
+        protected AMD64RROp(String opcode, int prefix1, int prefix2, int op, OpAssertion assertion, CPUFeature feature) {
+            super(opcode, prefix1, prefix2, op, assertion, feature);
+        }
+
+        protected AMD64RROp(String opcode, int prefix1, int prefix2, int op, boolean dstIsByte, boolean srcIsByte, OpAssertion assertion, CPUFeature feature) {
+            super(opcode, prefix1, prefix2, op, dstIsByte, srcIsByte, assertion, feature);
+        }
+
+        public abstract void emit(AMD64Assembler asm, OperandSize size, Register dst, Register src);
+    }
+
+    /**
+     * Opcode with operand order of RM.
+     */
+    public static class AMD64RMOp extends AMD64RROp {
+        // @formatter:off
+        public static final AMD64RMOp IMUL   = new AMD64RMOp("IMUL",         P_0F, 0xAF);
+        public static final AMD64RMOp BSF    = new AMD64RMOp("BSF",          P_0F, 0xBC);
+        public static final AMD64RMOp BSR    = new AMD64RMOp("BSR",          P_0F, 0xBD);
+        public static final AMD64RMOp POPCNT = new AMD64RMOp("POPCNT", 0xF3, P_0F, 0xB8, CPUFeature.POPCNT);
+        public static final AMD64RMOp TZCNT  = new AMD64RMOp("TZCNT",  0xF3, P_0F, 0xBC, CPUFeature.BMI1);
+        public static final AMD64RMOp LZCNT  = new AMD64RMOp("LZCNT",  0xF3, P_0F, 0xBD, CPUFeature.LZCNT);
+        public static final AMD64RMOp MOVZXB = new AMD64RMOp("MOVZXB",       P_0F, 0xB6, false, true, OpAssertion.IntegerAssertion);
+        public static final AMD64RMOp MOVZX  = new AMD64RMOp("MOVZX",        P_0F, 0xB7, OpAssertion.No16BitAssertion);
+        public static final AMD64RMOp MOVSXB = new AMD64RMOp("MOVSXB",       P_0F, 0xBE, false, true, OpAssertion.IntegerAssertion);
+        public static final AMD64RMOp MOVSX  = new AMD64RMOp("MOVSX",        P_0F, 0xBF, OpAssertion.No16BitAssertion);
+        public static final AMD64RMOp MOVSXD = new AMD64RMOp("MOVSXD",             0x63, OpAssertion.QwordOnlyAssertion);
+        public static final AMD64RMOp MOV    = new AMD64RMOp("MOV",                0x8B);
+
+        // MOVD and MOVQ are the same opcode, just with different operand size prefix
+        public static final AMD64RMOp MOVD   = new AMD64RMOp("MOVD",   0x66, P_0F, 0x6E, OpAssertion.IntToFloatingAssertion, CPUFeature.SSE2);
+        public static final AMD64RMOp MOVQ   = new AMD64RMOp("MOVQ",   0x66, P_0F, 0x6E, OpAssertion.IntToFloatingAssertion, CPUFeature.SSE2);
+
+        // TEST is documented as MR operation, but it's symmetric, and using it as RM operation is more convenient.
+        public static final AMD64RMOp TESTB  = new AMD64RMOp("TEST",               0x84, OpAssertion.ByteAssertion);
+        public static final AMD64RMOp TEST   = new AMD64RMOp("TEST",               0x85);
+        // @formatter:on
+
+        protected AMD64RMOp(String opcode, int op) {
+            this(opcode, 0, op);
+        }
+
+        protected AMD64RMOp(String opcode, int op, OpAssertion assertion) {
+            this(opcode, 0, op, assertion);
+        }
+
+        protected AMD64RMOp(String opcode, int prefix, int op) {
+            this(opcode, 0, prefix, op, null);
+        }
+
+        protected AMD64RMOp(String opcode, int prefix, int op, OpAssertion assertion) {
+            this(opcode, 0, prefix, op, assertion, null);
+        }
+
+        protected AMD64RMOp(String opcode, int prefix, int op, boolean dstIsByte, boolean srcIsByte, OpAssertion assertion) {
+            super(opcode, 0, prefix, op, dstIsByte, srcIsByte, assertion, null);
+        }
+
+        protected AMD64RMOp(String opcode, int prefix1, int prefix2, int op, CPUFeature feature) {
+            this(opcode, prefix1, prefix2, op, OpAssertion.IntegerAssertion, feature);
+        }
+
+        protected AMD64RMOp(String opcode, int prefix1, int prefix2, int op, OpAssertion assertion, CPUFeature feature) {
+            super(opcode, prefix1, prefix2, op, assertion, feature);
+        }
+
+        @Override
+        public final void emit(AMD64Assembler asm, OperandSize size, Register dst, Register src) {
+            assert verify(asm, size, dst, src);
+            emitOpcode(asm, size, getRXB(dst, src), dst.encoding, src.encoding);
+            asm.emitModRM(dst, src);
+        }
+
+        public final void emit(AMD64Assembler asm, OperandSize size, Register dst, AMD64Address src) {
+            assert verify(asm, size, dst, null);
+            emitOpcode(asm, size, getRXB(dst, src), dst.encoding, 0);
+            asm.emitOperandHelper(dst, src);
+        }
+    }
+
+    /**
+     * Opcode with operand order of MR.
+     */
+    public static class AMD64MROp extends AMD64RROp {
+        // @formatter:off
+        public static final AMD64MROp MOV    = new AMD64MROp("MOV",                0x89);
+
+        // MOVD and MOVQ are the same opcode, just with different operand size prefix
+        // Note that as MR opcodes, they have reverse operand order, so the IntToFloatingAssertion must be used.
+        public static final AMD64MROp MOVD   = new AMD64MROp("MOVD",   0x66, P_0F, 0x7E, OpAssertion.IntToFloatingAssertion, CPUFeature.SSE2);
+        public static final AMD64MROp MOVQ   = new AMD64MROp("MOVQ",   0x66, P_0F, 0x7E, OpAssertion.IntToFloatingAssertion, CPUFeature.SSE2);
+        // @formatter:on
+
+        protected AMD64MROp(String opcode, int op) {
+            this(opcode, 0, op);
+        }
+
+        protected AMD64MROp(String opcode, int op, OpAssertion assertion) {
+            this(opcode, 0, op, assertion);
+        }
+
+        protected AMD64MROp(String opcode, int prefix, int op) {
+            this(opcode, prefix, op, OpAssertion.IntegerAssertion);
+        }
+
+        protected AMD64MROp(String opcode, int prefix, int op, OpAssertion assertion) {
+            this(opcode, 0, prefix, op, assertion, null);
+        }
+
+        protected AMD64MROp(String opcode, int prefix1, int prefix2, int op, OpAssertion assertion, CPUFeature feature) {
+            super(opcode, prefix1, prefix2, op, assertion, feature);
+        }
+
+        @Override
+        public final void emit(AMD64Assembler asm, OperandSize size, Register dst, Register src) {
+            assert verify(asm, size, src, dst);
+            emitOpcode(asm, size, getRXB(src, dst), src.encoding, dst.encoding);
+            asm.emitModRM(src, dst);
+        }
+
+        public final void emit(AMD64Assembler asm, OperandSize size, AMD64Address dst, Register src) {
+            assert verify(asm, size, null, src);
+            emitOpcode(asm, size, getRXB(src, dst), src.encoding, 0);
+            asm.emitOperandHelper(src, dst);
+        }
+    }
+
+    /**
+     * Opcodes with operand order of M.
+     */
+    public static class AMD64MOp extends AMD64Op {
+        // @formatter:off
+        public static final AMD64MOp NOT  = new AMD64MOp("NOT",  0xF7, 2);
+        public static final AMD64MOp NEG  = new AMD64MOp("NEG",  0xF7, 3);
+        public static final AMD64MOp MUL  = new AMD64MOp("MUL",  0xF7, 4);
+        public static final AMD64MOp IMUL = new AMD64MOp("IMUL", 0xF7, 5);
+        public static final AMD64MOp DIV  = new AMD64MOp("DIV",  0xF7, 6);
+        public static final AMD64MOp IDIV = new AMD64MOp("IDIV", 0xF7, 7);
+        // @formatter:on
+
+        private final int ext;
+
+        protected AMD64MOp(String opcode, int op, int ext) {
+            this(opcode, 0, op, ext);
+        }
+
+        protected AMD64MOp(String opcode, int prefix, int op, int ext) {
+            this(opcode, prefix, op, ext, OpAssertion.IntegerAssertion);
+        }
+
+        protected AMD64MOp(String opcode, int prefix, int op, int ext, OpAssertion assertion) {
+            super(opcode, 0, prefix, op, assertion, null);
+            this.ext = ext;
+        }
+
+        public final void emit(AMD64Assembler asm, OperandSize size, Register dst) {
+            assert verify(asm, size, dst, null);
+            emitOpcode(asm, size, getRXB(null, dst), 0, dst.encoding);
+            asm.emitModRM(ext, dst);
+        }
+
+        public final void emit(AMD64Assembler asm, OperandSize size, AMD64Address dst) {
+            assert verify(asm, size, null, null);
+            emitOpcode(asm, size, getRXB(null, dst), 0, 0);
+            asm.emitOperandHelper(ext, dst);
+        }
+    }
+
+    /**
+     * Opcodes with operand order of MI.
+     */
+    public static class AMD64MIOp extends AMD64ImmOp {
+        // @formatter:off
+        public static final AMD64MIOp MOV  = new AMD64MIOp("MOV",  false, 0xC7, 0);
+        public static final AMD64MIOp TEST = new AMD64MIOp("TEST", false, 0xF7, 0);
+        // @formatter:on
+
+        private final int ext;
+
+        protected AMD64MIOp(String opcode, boolean immIsByte, int op, int ext) {
+            this(opcode, immIsByte, 0, op, ext, OpAssertion.IntegerAssertion);
+        }
+
+        protected AMD64MIOp(String opcode, boolean immIsByte, int prefix, int op, int ext, OpAssertion assertion) {
+            super(opcode, immIsByte, prefix, op, assertion);
+            this.ext = ext;
+        }
+
+        public final void emit(AMD64Assembler asm, OperandSize size, Register dst, int imm) {
+            assert verify(asm, size, dst, null);
+            emitOpcode(asm, size, getRXB(null, dst), 0, dst.encoding);
+            asm.emitModRM(ext, dst);
+            emitImmediate(asm, size, imm);
+        }
+
+        public final void emit(AMD64Assembler asm, OperandSize size, AMD64Address dst, int imm) {
+            assert verify(asm, size, null, null);
+            emitOpcode(asm, size, getRXB(null, dst), 0, 0);
+            asm.emitOperandHelper(ext, dst);
+            emitImmediate(asm, size, imm);
+        }
+    }
+
+    /**
+     * Opcodes with operand order of RMI.
+     */
+    public static class AMD64RMIOp extends AMD64ImmOp {
+        // @formatter:off
+        public static final AMD64RMIOp IMUL    = new AMD64RMIOp("IMUL", false, 0x69);
+        public static final AMD64RMIOp IMUL_SX = new AMD64RMIOp("IMUL", true,  0x6B);
+        // @formatter:on
+
+        protected AMD64RMIOp(String opcode, boolean immIsByte, int op) {
+            this(opcode, immIsByte, 0, op, OpAssertion.IntegerAssertion);
+        }
+
+        protected AMD64RMIOp(String opcode, boolean immIsByte, int prefix, int op, OpAssertion assertion) {
+            super(opcode, immIsByte, prefix, op, assertion);
+        }
+
+        public final void emit(AMD64Assembler asm, OperandSize size, Register dst, Register src, int imm) {
+            assert verify(asm, size, dst, src);
+            emitOpcode(asm, size, getRXB(dst, src), dst.encoding, src.encoding);
+            asm.emitModRM(dst, src);
+            emitImmediate(asm, size, imm);
+        }
+
+        public final void emit(AMD64Assembler asm, OperandSize size, Register dst, AMD64Address src, int imm) {
+            assert verify(asm, size, dst, null);
+            emitOpcode(asm, size, getRXB(dst, src), dst.encoding, 0);
+            asm.emitOperandHelper(dst, src);
+            emitImmediate(asm, size, imm);
+        }
+    }
+
+    public static class SSEOp extends AMD64RMOp {
+        // @formatter:off
+        public static final SSEOp CVTSI2SS  = new SSEOp("CVTSI2SS",  0xF3, P_0F, 0x2A, OpAssertion.IntToFloatingAssertion);
+        public static final SSEOp CVTSI2SD  = new SSEOp("CVTSI2SS",  0xF2, P_0F, 0x2A, OpAssertion.IntToFloatingAssertion);
+        public static final SSEOp CVTTSS2SI = new SSEOp("CVTTSS2SI", 0xF3, P_0F, 0x2C, OpAssertion.FloatingToIntAssertion);
+        public static final SSEOp CVTTSD2SI = new SSEOp("CVTTSD2SI", 0xF2, P_0F, 0x2C, OpAssertion.FloatingToIntAssertion);
+        public static final SSEOp UCOMIS    = new SSEOp("UCOMIS",          P_0F, 0x2E, OpAssertion.PackedFloatingAssertion);
+        public static final SSEOp SQRT      = new SSEOp("SQRT",            P_0F, 0x51);
+        public static final SSEOp AND       = new SSEOp("AND",             P_0F, 0x54, OpAssertion.PackedFloatingAssertion);
+        public static final SSEOp ANDN      = new SSEOp("ANDN",            P_0F, 0x55, OpAssertion.PackedFloatingAssertion);
+        public static final SSEOp OR        = new SSEOp("OR",              P_0F, 0x56, OpAssertion.PackedFloatingAssertion);
+        public static final SSEOp XOR       = new SSEOp("XOR",             P_0F, 0x57, OpAssertion.PackedFloatingAssertion);
+        public static final SSEOp ADD       = new SSEOp("ADD",             P_0F, 0x58);
+        public static final SSEOp MUL       = new SSEOp("MUL",             P_0F, 0x59);
+        public static final SSEOp CVTSS2SD  = new SSEOp("CVTSS2SD",        P_0F, 0x5A, OpAssertion.SingleAssertion);
+        public static final SSEOp CVTSD2SS  = new SSEOp("CVTSD2SS",        P_0F, 0x5A, OpAssertion.DoubleAssertion);
+        public static final SSEOp SUB       = new SSEOp("SUB",             P_0F, 0x5C);
+        public static final SSEOp MIN       = new SSEOp("MIN",             P_0F, 0x5D);
+        public static final SSEOp DIV       = new SSEOp("DIV",             P_0F, 0x5E);
+        public static final SSEOp MAX       = new SSEOp("MAX",             P_0F, 0x5F);
+        // @formatter:on
+
+        protected SSEOp(String opcode, int prefix, int op) {
+            this(opcode, prefix, op, OpAssertion.FloatingAssertion);
+        }
+
+        protected SSEOp(String opcode, int prefix, int op, OpAssertion assertion) {
+            this(opcode, 0, prefix, op, assertion);
+        }
+
+        protected SSEOp(String opcode, int mandatoryPrefix, int prefix, int op, OpAssertion assertion) {
+            super(opcode, mandatoryPrefix, prefix, op, assertion, CPUFeature.SSE2);
+        }
+    }
+
+    /**
+     * Arithmetic operation with operand order of RM, MR or MI.
+     */
+    public static final class AMD64BinaryArithmetic {
+        // @formatter:off
+        public static final AMD64BinaryArithmetic ADD = new AMD64BinaryArithmetic("ADD", 0);
+        public static final AMD64BinaryArithmetic OR  = new AMD64BinaryArithmetic("OR",  1);
+        public static final AMD64BinaryArithmetic ADC = new AMD64BinaryArithmetic("ADC", 2);
+        public static final AMD64BinaryArithmetic SBB = new AMD64BinaryArithmetic("SBB", 3);
+        public static final AMD64BinaryArithmetic AND = new AMD64BinaryArithmetic("AND", 4);
+        public static final AMD64BinaryArithmetic SUB = new AMD64BinaryArithmetic("SUB", 5);
+        public static final AMD64BinaryArithmetic XOR = new AMD64BinaryArithmetic("XOR", 6);
+        public static final AMD64BinaryArithmetic CMP = new AMD64BinaryArithmetic("CMP", 7);
+        // @formatter:on
+
+        private final AMD64MIOp byteImmOp;
+        private final AMD64MROp byteMrOp;
+        private final AMD64RMOp byteRmOp;
+
+        private final AMD64MIOp immOp;
+        private final AMD64MIOp immSxOp;
+        private final AMD64MROp mrOp;
+        private final AMD64RMOp rmOp;
+
+        private AMD64BinaryArithmetic(String opcode, int code) {
+            int baseOp = code << 3;
+
+            byteImmOp = new AMD64MIOp(opcode, true, 0, 0x80, code, OpAssertion.ByteAssertion);
+            byteMrOp = new AMD64MROp(opcode, 0, baseOp, OpAssertion.ByteAssertion);
+            byteRmOp = new AMD64RMOp(opcode, 0, baseOp | 0x02, OpAssertion.ByteAssertion);
+
+            immOp = new AMD64MIOp(opcode, false, 0, 0x81, code, OpAssertion.IntegerAssertion);
+            immSxOp = new AMD64MIOp(opcode, true, 0, 0x83, code, OpAssertion.IntegerAssertion);
+            mrOp = new AMD64MROp(opcode, 0, baseOp | 0x01, OpAssertion.IntegerAssertion);
+            rmOp = new AMD64RMOp(opcode, 0, baseOp | 0x03, OpAssertion.IntegerAssertion);
+        }
+
+        public AMD64MIOp getMIOpcode(OperandSize size, boolean sx) {
+            if (size == BYTE) {
+                return byteImmOp;
+            } else if (sx) {
+                return immSxOp;
+            } else {
+                return immOp;
+            }
+        }
+
+        public AMD64MROp getMROpcode(OperandSize size) {
+            if (size == BYTE) {
+                return byteMrOp;
+            } else {
+                return mrOp;
+            }
+        }
+
+        public AMD64RMOp getRMOpcode(OperandSize size) {
+            if (size == BYTE) {
+                return byteRmOp;
+            } else {
+                return rmOp;
+            }
+        }
+    }
+
+    /**
+     * Shift operation with operand order of M1, MC or MI.
+     */
+    public static final class AMD64Shift {
+        // @formatter:off
+        public static final AMD64Shift ROL = new AMD64Shift("ROL", 0);
+        public static final AMD64Shift ROR = new AMD64Shift("ROR", 1);
+        public static final AMD64Shift RCL = new AMD64Shift("RCL", 2);
+        public static final AMD64Shift RCR = new AMD64Shift("RCR", 3);
+        public static final AMD64Shift SHL = new AMD64Shift("SHL", 4);
+        public static final AMD64Shift SHR = new AMD64Shift("SHR", 5);
+        public static final AMD64Shift SAR = new AMD64Shift("SAR", 7);
+        // @formatter:on
+
+        public final AMD64MOp m1Op;
+        public final AMD64MOp mcOp;
+        public final AMD64MIOp miOp;
+
+        private AMD64Shift(String opcode, int code) {
+            m1Op = new AMD64MOp(opcode, 0, 0xD1, code, OpAssertion.IntegerAssertion);
+            mcOp = new AMD64MOp(opcode, 0, 0xD3, code, OpAssertion.IntegerAssertion);
+            miOp = new AMD64MIOp(opcode, true, 0, 0xC1, code, OpAssertion.IntegerAssertion);
+        }
+    }
+
     public final void addl(AMD64Address dst, int imm32) {
-        emitArithImm32(0, dst, imm32);
+        ADD.getMIOpcode(DWORD, isByte(imm32)).emit(this, DWORD, dst, imm32);
     }
 
     public final void addl(Register dst, int imm32) {
-        emitArithImm32(0, dst, imm32);
-    }
-
-    public final void addl(Register dst, AMD64Address src) {
-        prefix(src, dst);
-        emitByte(0x03);
-        emitOperandHelper(dst, src);
-    }
-
-    public final void addl(Register dst, Register src) {
-        int encode = prefixAndEncode(dst.encoding, src.encoding);
-        emitByte(0x03);
-        emitByte(0xC0 | encode);
+        ADD.getMIOpcode(DWORD, isByte(imm32)).emit(this, DWORD, dst, imm32);
     }
 
     private void addrNop4() {
@@ -433,98 +975,8 @@
         emitInt(0); // 32-bits offset (4 bytes)
     }
 
-    public final void addsd(Register dst, Register src) {
-        assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM);
-        emitByte(0xF2);
-        int encode = prefixAndEncode(dst.encoding, src.encoding);
-        emitByte(0x0F);
-        emitByte(0x58);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void addsd(Register dst, AMD64Address src) {
-        assert dst.getRegisterCategory().equals(AMD64.XMM);
-        emitByte(0xF2);
-        prefix(src, dst);
-        emitByte(0x0F);
-        emitByte(0x58);
-        emitOperandHelper(dst, src);
-    }
-
-    public final void addss(Register dst, Register src) {
-        assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM);
-        emitByte(0xF3);
-        int encode = prefixAndEncode(dst.encoding, src.encoding);
-        emitByte(0x0F);
-        emitByte(0x58);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void addss(Register dst, AMD64Address src) {
-        assert dst.getRegisterCategory().equals(AMD64.XMM);
-        emitByte(0xF3);
-        prefix(src, dst);
-        emitByte(0x0F);
-        emitByte(0x58);
-        emitOperandHelper(dst, src);
-    }
-
     public final void andl(Register dst, int imm32) {
-        emitArithImm32(4, dst, imm32);
-    }
-
-    public final void andl(Register dst, AMD64Address src) {
-        prefix(src, dst);
-        emitByte(0x23);
-        emitOperandHelper(dst, src);
-    }
-
-    public final void andl(Register dst, Register src) {
-        int encode = prefixAndEncode(dst.encoding, src.encoding);
-        emitByte(0x23);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void bsfq(Register dst, Register src) {
-        int encode = prefixqAndEncode(dst.encoding, src.encoding);
-        emitByte(0x0F);
-        emitByte(0xBC);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void bsfq(Register dst, AMD64Address src) {
-        prefixq(src, dst);
-        emitByte(0x0F);
-        emitByte(0xBC);
-        emitOperandHelper(dst, src);
-    }
-
-    public final void bsrq(Register dst, Register src) {
-        int encode = prefixqAndEncode(dst.encoding, src.encoding);
-        emitByte(0x0F);
-        emitByte(0xBD);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void bsrq(Register dst, AMD64Address src) {
-        prefixq(src, dst);
-        emitByte(0x0F);
-        emitByte(0xBD);
-        emitOperandHelper(dst, src);
-    }
-
-    public final void bsrl(Register dst, Register src) {
-        int encode = prefixAndEncode(dst.encoding, src.encoding);
-        emitByte(0x0F);
-        emitByte(0xBD);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void bsrl(Register dst, AMD64Address src) {
-        prefix(src, dst);
-        emitByte(0x0F);
-        emitByte(0xBD);
-        emitOperandHelper(dst, src);
+        AND.getMIOpcode(DWORD, isByte(imm32)).emit(this, DWORD, dst, imm32);
     }
 
     public final void bswapl(Register reg) {
@@ -551,66 +1003,20 @@
         emitOperandHelper(dst, src);
     }
 
-    public final void cmpb(Register dst, int imm8) {
-        emitArithImm8(7, dst, imm8);
-    }
-
-    public final void cmpb(Register dst, Register src) {
-        int encode = prefixAndEncode(dst.encoding, true, src.encoding, true);
-        emitByte(0x3A);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void cmpb(Register dst, AMD64Address src) {
-        prefix(src, dst, true);
-        emitByte(0x3A);
-        emitOperandHelper(dst, src);
-    }
-
-    public final void cmpb(AMD64Address dst, int imm8) {
-        emitArithImm8(7, dst, imm8);
-    }
-
-    public final void cmpw(Register dst, int imm16) {
-        emitArithImm16(7, dst, imm16);
-    }
-
-    public final void cmpw(Register dst, Register src) {
-        emitByte(0x66);
-        int encode = prefixAndEncode(dst.encoding, src.encoding);
-        emitByte(0x3B);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void cmpw(Register dst, AMD64Address src) {
-        emitByte(0x66);
-        prefix(src, dst);
-        emitByte(0x3B);
-        emitOperandHelper(dst, src);
-    }
-
-    public final void cmpw(AMD64Address dst, int imm16) {
-        emitArithImm16(7, dst, imm16);
-    }
-
     public final void cmpl(Register dst, int imm32) {
-        emitArithImm32(7, dst, imm32);
+        CMP.getMIOpcode(DWORD, isByte(imm32)).emit(this, DWORD, dst, imm32);
     }
 
     public final void cmpl(Register dst, Register src) {
-        int encode = prefixAndEncode(dst.encoding, src.encoding);
-        emitByte(0x3B);
-        emitByte(0xC0 | encode);
+        CMP.rmOp.emit(this, DWORD, dst, src);
     }
 
     public final void cmpl(Register dst, AMD64Address src) {
-        prefix(src, dst);
-        emitByte(0x3B);
-        emitOperandHelper(dst, src);
+        CMP.rmOp.emit(this, DWORD, dst, src);
     }
 
     public final void cmpl(AMD64Address dst, int imm32) {
-        emitArithImm32(7, dst, imm32);
+        CMP.getMIOpcode(DWORD, isByte(imm32)).emit(this, DWORD, dst, imm32);
     }
 
     // The 32-bit cmpxchg compares the value at adr with the contents of X86.rax,
@@ -623,235 +1029,21 @@
         emitOperandHelper(reg, adr);
     }
 
-    public final void cvtsd2ss(Register dst, AMD64Address src) {
-        assert dst.getRegisterCategory().equals(AMD64.XMM);
-        emitByte(0xF2);
-        prefix(src, dst);
-        emitByte(0x0F);
-        emitByte(0x5A);
-        emitOperandHelper(dst, src);
-    }
-
-    public final void cvtsd2ss(Register dst, Register src) {
-        assert dst.getRegisterCategory().equals(AMD64.XMM);
-        assert src.getRegisterCategory().equals(AMD64.XMM);
-        emitByte(0xF2);
-        int encode = prefixAndEncode(dst.encoding, src.encoding);
-        emitByte(0x0F);
-        emitByte(0x5A);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void cvtsi2sdl(Register dst, AMD64Address src) {
-        assert dst.getRegisterCategory().equals(AMD64.XMM);
-        emitByte(0xF2);
-        prefix(src, dst);
-        emitByte(0x0F);
-        emitByte(0x2A);
-        emitOperandHelper(dst, src);
-    }
-
-    public final void cvtsi2sdl(Register dst, Register src) {
-        assert dst.getRegisterCategory().equals(AMD64.XMM);
-        emitByte(0xF2);
-        int encode = prefixAndEncode(dst.encoding, src.encoding);
-        emitByte(0x0F);
-        emitByte(0x2A);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void cvtsi2ssl(Register dst, AMD64Address src) {
-        assert dst.getRegisterCategory().equals(AMD64.XMM);
-        emitByte(0xF3);
-        prefix(src, dst);
-        emitByte(0x0F);
-        emitByte(0x2A);
-        emitOperandHelper(dst, src);
-    }
-
-    public final void cvtsi2ssl(Register dst, Register src) {
-        assert dst.getRegisterCategory().equals(AMD64.XMM);
-        emitByte(0xF3);
-        int encode = prefixAndEncode(dst.encoding, src.encoding);
-        emitByte(0x0F);
-        emitByte(0x2A);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void cvtss2sd(Register dst, AMD64Address src) {
-        assert dst.getRegisterCategory().equals(AMD64.XMM);
-        emitByte(0xF3);
-        prefix(src, dst);
-        emitByte(0x0F);
-        emitByte(0x5A);
-        emitOperandHelper(dst, src);
-    }
-
-    public final void cvtss2sd(Register dst, Register src) {
-        assert dst.getRegisterCategory().equals(AMD64.XMM);
-        assert src.getRegisterCategory().equals(AMD64.XMM);
-        emitByte(0xF3);
-        int encode = prefixAndEncode(dst.encoding, src.encoding);
-        emitByte(0x0F);
-        emitByte(0x5A);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void cvttsd2sil(Register dst, AMD64Address src) {
-        emitByte(0xF2);
-        prefix(src, dst);
-        emitByte(0x0F);
-        emitByte(0x2C);
-        emitOperandHelper(dst, src);
-    }
-
-    public final void cvttsd2sil(Register dst, Register src) {
-        assert src.getRegisterCategory().equals(AMD64.XMM);
-        emitByte(0xF2);
-        int encode = prefixAndEncode(dst.encoding, src.encoding);
-        emitByte(0x0F);
-        emitByte(0x2C);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void cvttss2sil(Register dst, AMD64Address src) {
-        emitByte(0xF3);
-        prefix(src, dst);
-        emitByte(0x0F);
-        emitByte(0x2C);
-        emitOperandHelper(dst, src);
-    }
-
-    public final void cvttss2sil(Register dst, Register src) {
-        assert src.getRegisterCategory().equals(AMD64.XMM);
-        emitByte(0xF3);
-        int encode = prefixAndEncode(dst.encoding, src.encoding);
-        emitByte(0x0F);
-        emitByte(0x2C);
-        emitByte(0xC0 | encode);
-    }
-
     protected final void decl(AMD64Address dst) {
         prefix(dst);
         emitByte(0xFF);
         emitOperandHelper(1, dst);
     }
 
-    public final void divsd(Register dst, AMD64Address src) {
-        assert dst.getRegisterCategory().equals(AMD64.XMM);
-        emitByte(0xF2);
-        prefix(src, dst);
-        emitByte(0x0F);
-        emitByte(0x5E);
-        emitOperandHelper(dst, src);
-    }
-
-    public final void divsd(Register dst, Register src) {
-        assert dst.getRegisterCategory().equals(AMD64.XMM);
-        assert src.getRegisterCategory().equals(AMD64.XMM);
-        emitByte(0xF2);
-        int encode = prefixAndEncode(dst.encoding, src.encoding);
-        emitByte(0x0F);
-        emitByte(0x5E);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void divss(Register dst, AMD64Address src) {
-        assert dst.getRegisterCategory().equals(AMD64.XMM);
-        emitByte(0xF3);
-        prefix(src, dst);
-        emitByte(0x0F);
-        emitByte(0x5E);
-        emitOperandHelper(dst, src);
-    }
-
-    public final void divss(Register dst, Register src) {
-        assert dst.getRegisterCategory().equals(AMD64.XMM);
-        assert src.getRegisterCategory().equals(AMD64.XMM);
-        emitByte(0xF3);
-        int encode = prefixAndEncode(dst.encoding, src.encoding);
-        emitByte(0x0F);
-        emitByte(0x5E);
-        emitByte(0xC0 | encode);
-    }
-
     public final void hlt() {
         emitByte(0xF4);
     }
 
-    public final void idivl(Register src) {
-        int encode = prefixAndEncode(7, src.encoding);
-        emitByte(0xF7);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void divl(Register src) {
-        int encode = prefixAndEncode(6, src.encoding);
-        emitByte(0xF7);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void mull(Register src) {
-        int encode = prefixAndEncode(4, src.encoding);
-        emitByte(0xF7);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void mull(AMD64Address src) {
-        prefix(src);
-        emitByte(0xF7);
-        emitOperandHelper(4, src);
-    }
-
-    public final void imull(Register src) {
-        int encode = prefixAndEncode(5, src.encoding);
-        emitByte(0xF7);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void imull(AMD64Address src) {
-        prefix(src);
-        emitByte(0xF7);
-        emitOperandHelper(5, src);
-    }
-
-    public final void imull(Register dst, Register src) {
-        int encode = prefixAndEncode(dst.encoding, src.encoding);
-        emitByte(0x0F);
-        emitByte(0xAF);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void imull(Register dst, AMD64Address src) {
-        prefix(src, dst);
-        emitByte(0x0F);
-        emitByte(0xAF);
-        emitOperandHelper(dst, src);
-    }
-
     public final void imull(Register dst, Register src, int value) {
-        int encode = prefixAndEncode(dst.encoding, src.encoding);
         if (isByte(value)) {
-            emitByte(0x6B);
-            emitByte(0xC0 | encode);
-            emitByte(value & 0xFF);
+            AMD64RMIOp.IMUL_SX.emit(this, DWORD, dst, src, value);
         } else {
-            emitByte(0x69);
-            emitByte(0xC0 | encode);
-            emitInt(value);
-        }
-    }
-
-    public final void imull(Register dst, AMD64Address src, int value) {
-        prefix(src, dst);
-        if (isByte(value)) {
-            emitByte(0x6B);
-            emitOperandHelper(dst, src);
-            emitByte(value & 0xFF);
-        } else {
-            emitByte(0x69);
-            emitOperandHelper(dst, src);
-            emitInt(value);
+            AMD64RMIOp.IMUL.emit(this, DWORD, dst, src, value);
         }
     }
 
@@ -1039,25 +1231,6 @@
         emitOperandHelper(src, dst);
     }
 
-    public final void movdl(Register dst, Register src) {
-        if (dst.getRegisterCategory().equals(AMD64.XMM)) {
-            assert !src.getRegisterCategory().equals(AMD64.XMM) : "does this hold?";
-            emitByte(0x66);
-            int encode = prefixAndEncode(dst.encoding, src.encoding);
-            emitByte(0x0F);
-            emitByte(0x6E);
-            emitByte(0xC0 | encode);
-        } else if (src.getRegisterCategory().equals(AMD64.XMM)) {
-            assert !dst.getRegisterCategory().equals(AMD64.XMM);
-            emitByte(0x66);
-            // swap src/dst to get correct prefix
-            int encode = prefixAndEncode(src.encoding, dst.encoding);
-            emitByte(0x0F);
-            emitByte(0x7E);
-            emitByte(0xC0 | encode);
-        }
-    }
-
     public final void movl(Register dst, int imm32) {
         int encode = prefixAndEncode(dst.encoding);
         emitByte(0xB8 | encode);
@@ -1229,27 +1402,6 @@
         emitOperandHelper(dst, src);
     }
 
-    public final void movswl(Register dst, Register src) {
-        int encode = prefixAndEncode(dst.encoding, src.encoding);
-        emitByte(0x0F);
-        emitByte(0xBF);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void movswq(Register dst, AMD64Address src) {
-        prefixq(src, dst);
-        emitByte(0x0F);
-        emitByte(0xBF);
-        emitOperandHelper(dst, src);
-    }
-
-    public final void movswq(Register dst, Register src) {
-        int encode = prefixqAndEncode(dst.encoding, src.encoding);
-        emitByte(0x0F);
-        emitByte(0xBF);
-        emitByte(0xC0 | encode);
-    }
-
     public final void movw(AMD64Address dst, int imm16) {
         emitByte(0x66); // switch to 16-bit mode
         prefix(dst);
@@ -1279,99 +1431,11 @@
         emitOperandHelper(dst, src);
     }
 
-    public final void mulsd(Register dst, AMD64Address src) {
-        assert dst.getRegisterCategory().equals(AMD64.XMM);
-        emitByte(0xF2);
-        prefix(src, dst);
-        emitByte(0x0F);
-        emitByte(0x59);
-        emitOperandHelper(dst, src);
-    }
-
-    public final void mulsd(Register dst, Register src) {
-        assert dst.getRegisterCategory().equals(AMD64.XMM);
-        assert src.getRegisterCategory().equals(AMD64.XMM);
-
-        emitByte(0xF2);
-        int encode = prefixAndEncode(dst.encoding, src.encoding);
-        emitByte(0x0F);
-        emitByte(0x59);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void mulss(Register dst, AMD64Address src) {
-        assert dst.getRegisterCategory().equals(AMD64.XMM);
-
-        emitByte(0xF3);
-        prefix(src, dst);
-        emitByte(0x0F);
-        emitByte(0x59);
-        emitOperandHelper(dst, src);
-    }
-
-    public final void mulss(Register dst, Register src) {
-        assert dst.getRegisterCategory().equals(AMD64.XMM);
-        assert src.getRegisterCategory().equals(AMD64.XMM);
-        emitByte(0xF3);
-        int encode = prefixAndEncode(dst.encoding, src.encoding);
-        emitByte(0x0F);
-        emitByte(0x59);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void negl(Register dst) {
-        int encode = prefixAndEncode(dst.encoding);
-        emitByte(0xF7);
-        emitByte(0xD8 | encode);
-    }
-
-    public final void notl(Register dst) {
-        int encode = prefixAndEncode(dst.encoding);
-        emitByte(0xF7);
-        emitByte(0xD0 | encode);
-    }
-
     @Override
     public final void ensureUniquePC() {
         nop();
     }
 
-    public final void lzcntl(Register dst, Register src) {
-        assert supports(CPUFeature.LZCNT);
-        emitByte(0xF3);
-        int encode = prefixAndEncode(dst.encoding, src.encoding);
-        emitByte(0x0F);
-        emitByte(0xBD);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void lzcntq(Register dst, Register src) {
-        assert supports(CPUFeature.LZCNT);
-        emitByte(0xF3);
-        int encode = prefixqAndEncode(dst.encoding, src.encoding);
-        emitByte(0x0F);
-        emitByte(0xBD);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void lzcntl(Register dst, AMD64Address src) {
-        assert supports(CPUFeature.LZCNT);
-        emitByte(0xF3);
-        prefix(src, dst);
-        emitByte(0x0F);
-        emitByte(0xBD);
-        emitOperandHelper(dst, src);
-    }
-
-    public final void lzcntq(Register dst, AMD64Address src) {
-        assert supports(CPUFeature.LZCNT);
-        emitByte(0xF3);
-        prefixq(src, dst);
-        emitByte(0x0F);
-        emitByte(0xBD);
-        emitOperandHelper(dst, src);
-    }
-
     public final void nop() {
         nop(1);
     }
@@ -1578,58 +1642,6 @@
         }
     }
 
-    public final void orl(Register dst, int imm32) {
-        emitArithImm32(1, dst, imm32);
-    }
-
-    public final void orl(Register dst, AMD64Address src) {
-        prefix(src, dst);
-        emitByte(0x0B);
-        emitOperandHelper(dst, src);
-    }
-
-    public final void orl(Register dst, Register src) {
-        int encode = prefixAndEncode(dst.encoding, src.encoding);
-        emitByte(0x0B);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void popcntl(Register dst, AMD64Address src) {
-        assert supports(CPUFeature.POPCNT);
-        emitByte(0xF3);
-        prefix(src, dst);
-        emitByte(0x0F);
-        emitByte(0xB8);
-        emitOperandHelper(dst, src);
-    }
-
-    public final void popcntl(Register dst, Register src) {
-        assert supports(CPUFeature.POPCNT);
-        emitByte(0xF3);
-        int encode = prefixAndEncode(dst.encoding, src.encoding);
-        emitByte(0x0F);
-        emitByte(0xB8);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void popcntq(Register dst, AMD64Address src) {
-        assert supports(CPUFeature.POPCNT);
-        emitByte(0xF3);
-        prefixq(src, dst);
-        emitByte(0x0F);
-        emitByte(0xB8);
-        emitOperandHelper(dst, src);
-    }
-
-    public final void popcntq(Register dst, Register src) {
-        assert supports(CPUFeature.POPCNT);
-        emitByte(0xF3);
-        int encode = prefixqAndEncode(dst.encoding, src.encoding);
-        emitByte(0x0F);
-        emitByte(0xB8);
-        emitByte(0xC0 | encode);
-    }
-
     public final void pop(Register dst) {
         int encode = prefixAndEncode(dst.encoding);
         emitByte(0x58 | encode);
@@ -1675,218 +1687,12 @@
         }
     }
 
-    public final void sarl(Register dst, int imm8) {
-        int encode = prefixAndEncode(dst.encoding);
-        assert isShiftCount(imm8) : "illegal shift count";
-        if (imm8 == 1) {
-            emitByte(0xD1);
-            emitByte(0xF8 | encode);
-        } else {
-            emitByte(0xC1);
-            emitByte(0xF8 | encode);
-            emitByte(imm8);
-        }
-    }
-
-    public final void sarl(Register dst) {
-        int encode = prefixAndEncode(dst.encoding);
-        emitByte(0xD3);
-        emitByte(0xF8 | encode);
-    }
-
-    public final void shll(Register dst, int imm8) {
-        assert isShiftCount(imm8) : "illegal shift count";
-        int encode = prefixAndEncode(dst.encoding);
-        if (imm8 == 1) {
-            emitByte(0xD1);
-            emitByte(0xE0 | encode);
-        } else {
-            emitByte(0xC1);
-            emitByte(0xE0 | encode);
-            emitByte(imm8);
-        }
-    }
-
-    public final void shll(Register dst) {
-        int encode = prefixAndEncode(dst.encoding);
-        emitByte(0xD3);
-        emitByte(0xE0 | encode);
-    }
-
-    public final void shrl(Register dst, int imm8) {
-        assert isShiftCount(imm8) : "illegal shift count";
-        int encode = prefixAndEncode(dst.encoding);
-        if (imm8 == 1) {
-            emitByte(0xD1);
-            emitByte(0xE8 | encode);
-        } else {
-            emitByte(0xC1);
-            emitByte(0xE8 | encode);
-            emitByte(imm8);
-        }
-    }
-
-    public final void shrl(Register dst) {
-        int encode = prefixAndEncode(dst.encoding);
-        emitByte(0xD3);
-        emitByte(0xE8 | encode);
-    }
-
-    public final void roll(Register dst, int imm8) {
-        assert isShiftCount(imm8) : "illegal shift count";
-        int encode = prefixAndEncode(dst.encoding);
-        if (imm8 == 1) {
-            emitByte(0xD1);
-            emitByte(0xC0 | encode);
-        } else {
-            emitByte(0xC1);
-            emitByte(0xC0 | encode);
-            emitByte(imm8);
-        }
-    }
-
-    public final void roll(Register dst) {
-        int encode = prefixAndEncode(dst.encoding);
-        emitByte(0xD3);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void rorl(Register dst, int imm8) {
-        assert isShiftCount(imm8) : "illegal shift count";
-        int encode = prefixAndEncode(dst.encoding);
-        if (imm8 == 1) {
-            emitByte(0xD1);
-            emitByte(0xC8 | encode);
-        } else {
-            emitByte(0xC1);
-            emitByte(0xC8 | encode);
-            emitByte(imm8);
-        }
-    }
-
-    public final void rorl(Register dst) {
-        int encode = prefixAndEncode(dst.encoding);
-        emitByte(0xD3);
-        emitByte(0xC8 | encode);
-    }
-
-    public final void rolq(Register dst, int imm8) {
-        assert isShiftCount(imm8) : "illegal shift count";
-        int encode = prefixqAndEncode(dst.encoding);
-        if (imm8 == 1) {
-            emitByte(0xD1);
-            emitByte(0xC0 | encode);
-        } else {
-            emitByte(0xC1);
-            emitByte(0xC0 | encode);
-            emitByte(imm8);
-        }
-    }
-
-    public final void rolq(Register dst) {
-        int encode = prefixqAndEncode(dst.encoding);
-        emitByte(0xD3);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void rorq(Register dst, int imm8) {
-        assert isShiftCount(imm8) : "illegal shift count";
-        int encode = prefixqAndEncode(dst.encoding);
-        if (imm8 == 1) {
-            emitByte(0xD1);
-            emitByte(0xC8 | encode);
-        } else {
-            emitByte(0xC1);
-            emitByte(0xC8 | encode);
-            emitByte(imm8);
-        }
-    }
-
-    public final void rorq(Register dst) {
-        int encode = prefixqAndEncode(dst.encoding);
-        emitByte(0xD3);
-        emitByte(0xC8 | encode);
-    }
-
-    public final void sqrtsd(Register dst, AMD64Address src) {
-        assert dst.getRegisterCategory().equals(AMD64.XMM);
-        emitByte(0xF2);
-        prefix(src, dst);
-        emitByte(0x0F);
-        emitByte(0x51);
-        emitOperandHelper(dst, src);
-    }
-
-    public final void sqrtsd(Register dst, Register src) {
-        assert dst.getRegisterCategory().equals(AMD64.XMM);
-        assert src.getRegisterCategory().equals(AMD64.XMM);
-        // HMM Table D-1 says sse2
-        // assert is64 || target.supportsSSE();
-        emitByte(0xF2);
-        int encode = prefixAndEncode(dst.encoding, src.encoding);
-        emitByte(0x0F);
-        emitByte(0x51);
-        emitByte(0xC0 | encode);
-    }
-
     public final void subl(AMD64Address dst, int imm32) {
-        emitArithImm32(5, dst, imm32);
+        SUB.getMIOpcode(DWORD, isByte(imm32)).emit(this, DWORD, dst, imm32);
     }
 
     public final void subl(Register dst, int imm32) {
-        emitArithImm32(5, dst, imm32);
-    }
-
-    public final void subl(Register dst, AMD64Address src) {
-        prefix(src, dst);
-        emitByte(0x2B);
-        emitOperandHelper(dst, src);
-    }
-
-    public final void subl(Register dst, Register src) {
-        int encode = prefixAndEncode(dst.encoding, src.encoding);
-        emitByte(0x2B);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void subsd(Register dst, Register src) {
-        assert dst.getRegisterCategory().equals(AMD64.XMM);
-        assert src.getRegisterCategory().equals(AMD64.XMM);
-        emitByte(0xF2);
-        int encode = prefixAndEncode(dst.encoding, src.encoding);
-        emitByte(0x0F);
-        emitByte(0x5C);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void subsd(Register dst, AMD64Address src) {
-        assert dst.getRegisterCategory().equals(AMD64.XMM);
-
-        emitByte(0xF2);
-        prefix(src, dst);
-        emitByte(0x0F);
-        emitByte(0x5C);
-        emitOperandHelper(dst, src);
-    }
-
-    public final void subss(Register dst, Register src) {
-        assert dst.getRegisterCategory().equals(AMD64.XMM);
-        assert src.getRegisterCategory().equals(AMD64.XMM);
-        emitByte(0xF3);
-        int encode = prefixAndEncode(dst.encoding, src.encoding);
-        emitByte(0x0F);
-        emitByte(0x5C);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void subss(Register dst, AMD64Address src) {
-        assert dst.getRegisterCategory().equals(AMD64.XMM);
-
-        emitByte(0xF3);
-        prefix(src, dst);
-        emitByte(0x0F);
-        emitByte(0x5C);
-        emitOperandHelper(dst, src);
+        SUB.getMIOpcode(DWORD, isByte(imm32)).emit(this, DWORD, dst, imm32);
     }
 
     public final void testl(Register dst, int imm32) {
@@ -1904,13 +1710,6 @@
         emitInt(imm32);
     }
 
-    public final void testl(AMD64Address dst, int imm32) {
-        prefix(dst);
-        emitByte(0xF7);
-        emitOperandHelper(0, dst);
-        emitInt(imm32);
-    }
-
     public final void testl(Register dst, Register src) {
         int encode = prefixAndEncode(dst.encoding, src.encoding);
         emitByte(0x85);
@@ -1923,139 +1722,8 @@
         emitOperandHelper(dst, src);
     }
 
-    public final void tzcntl(Register dst, Register src) {
-        assert supports(CPUFeature.BMI1);
-        emitByte(0xF3);
-        int encode = prefixAndEncode(dst.encoding, src.encoding);
-        emitByte(0x0F);
-        emitByte(0xBC);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void tzcntq(Register dst, Register src) {
-        assert supports(CPUFeature.BMI1);
-        emitByte(0xF3);
-        int encode = prefixqAndEncode(dst.encoding, src.encoding);
-        emitByte(0x0F);
-        emitByte(0xBC);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void tzcntl(Register dst, AMD64Address src) {
-        assert supports(CPUFeature.BMI1);
-        emitByte(0xF3);
-        prefix(src, dst);
-        emitByte(0x0F);
-        emitByte(0xBC);
-        emitOperandHelper(dst, src);
-    }
-
-    public final void tzcntq(Register dst, AMD64Address src) {
-        assert supports(CPUFeature.BMI1);
-        emitByte(0xF3);
-        prefixq(src, dst);
-        emitByte(0x0F);
-        emitByte(0xBC);
-        emitOperandHelper(dst, src);
-    }
-
-    public final void ucomisd(Register dst, AMD64Address src) {
-        assert dst.getRegisterCategory().equals(AMD64.XMM);
-        emitByte(0x66);
-        ucomiss(dst, src);
-    }
-
-    public final void ucomisd(Register dst, Register src) {
-        assert dst.getRegisterCategory().equals(AMD64.XMM);
-        assert src.getRegisterCategory().equals(AMD64.XMM);
-        emitByte(0x66);
-        ucomiss(dst, src);
-    }
-
-    public final void ucomiss(Register dst, AMD64Address src) {
-        assert dst.getRegisterCategory().equals(AMD64.XMM);
-
-        prefix(src, dst);
-        emitByte(0x0F);
-        emitByte(0x2E);
-        emitOperandHelper(dst, src);
-    }
-
-    public final void ucomiss(Register dst, Register src) {
-        assert dst.getRegisterCategory().equals(AMD64.XMM);
-        assert src.getRegisterCategory().equals(AMD64.XMM);
-        int encode = prefixAndEncode(dst.encoding, src.encoding);
-        emitByte(0x0F);
-        emitByte(0x2E);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void xorl(Register dst, int imm32) {
-        emitArithImm32(6, dst, imm32);
-    }
-
-    public final void xorl(Register dst, AMD64Address src) {
-        prefix(src, dst);
-        emitByte(0x33);
-        emitOperandHelper(dst, src);
-    }
-
     public final void xorl(Register dst, Register src) {
-        int encode = prefixAndEncode(dst.encoding, src.encoding);
-        emitByte(0x33);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void andpd(Register dst, Register src) {
-        emitByte(0x66);
-        andps(dst, src);
-    }
-
-    public final void andpd(Register dst, AMD64Address src) {
-        emitByte(0x66);
-        andps(dst, src);
-    }
-
-    public final void andps(Register dst, Register src) {
-        assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM);
-        int encode = prefixAndEncode(dst.encoding, src.encoding);
-        emitByte(0x0F);
-        emitByte(0x54);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void andps(Register dst, AMD64Address src) {
-        assert dst.getRegisterCategory().equals(AMD64.XMM);
-        prefix(src, dst);
-        emitByte(0x0F);
-        emitByte(0x54);
-        emitOperandHelper(dst, src);
-    }
-
-    public final void orpd(Register dst, Register src) {
-        emitByte(0x66);
-        orps(dst, src);
-    }
-
-    public final void orpd(Register dst, AMD64Address src) {
-        emitByte(0x66);
-        orps(dst, src);
-    }
-
-    public final void orps(Register dst, Register src) {
-        assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM);
-        int encode = prefixAndEncode(dst.encoding, src.encoding);
-        emitByte(0x0F);
-        emitByte(0x56);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void orps(Register dst, AMD64Address src) {
-        assert dst.getRegisterCategory().equals(AMD64.XMM);
-        prefix(src, dst);
-        emitByte(0x0F);
-        emitByte(0x56);
-        emitOperandHelper(dst, src);
+        XOR.rmOp.emit(this, DWORD, dst, src);
     }
 
     public final void xorpd(Register dst, Register src) {
@@ -2063,11 +1731,6 @@
         xorps(dst, src);
     }
 
-    public final void xorpd(Register dst, AMD64Address src) {
-        emitByte(0x66);
-        xorps(dst, src);
-    }
-
     public final void xorps(Register dst, Register src) {
         assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM);
         int encode = prefixAndEncode(dst.encoding, src.encoding);
@@ -2076,14 +1739,6 @@
         emitByte(0xC0 | encode);
     }
 
-    public final void xorps(Register dst, AMD64Address src) {
-        assert dst.getRegisterCategory().equals(AMD64.XMM);
-        prefix(src, dst);
-        emitByte(0x0F);
-        emitByte(0x57);
-        emitOperandHelper(dst, src);
-    }
-
     protected final void decl(Register dst) {
         // Use two-byte form (one-byte form is a REX prefix in 64-bit mode)
         int encode = prefixAndEncode(dst.encoding);
@@ -2281,35 +1936,15 @@
     }
 
     public final void addq(Register dst, int imm32) {
-        emitArithImm32q(0, dst, imm32);
-    }
-
-    public final void addq(Register dst, AMD64Address src) {
-        prefixq(src, dst);
-        emitByte(0x03);
-        emitOperandHelper(dst, src);
+        ADD.getMIOpcode(QWORD, isByte(imm32)).emit(this, QWORD, dst, imm32);
     }
 
     public final void addq(Register dst, Register src) {
-        int encode = prefixqAndEncode(dst.encoding, src.encoding);
-        emitByte(0x03);
-        emitByte(0xC0 | encode);
+        ADD.rmOp.emit(this, QWORD, dst, src);
     }
 
     public final void andq(Register dst, int imm32) {
-        emitArithImm32q(4, dst, imm32);
-    }
-
-    public final void andq(Register dst, AMD64Address src) {
-        prefixq(src, dst);
-        emitByte(0x23);
-        emitOperandHelper(dst, src);
-    }
-
-    public final void andq(Register dst, Register src) {
-        int encode = prefixqAndEncode(dst.encoding, src.encoding);
-        emitByte(0x23);
-        emitByte(0xC0 | encode);
+        AND.getMIOpcode(QWORD, isByte(imm32)).emit(this, QWORD, dst, imm32);
     }
 
     public final void bswapq(Register reg) {
@@ -2337,27 +1972,16 @@
         emitOperandHelper(dst, src);
     }
 
-    public final void cmpq(AMD64Address dst, int imm32) {
-        prefixq(dst);
-        emitByte(0x81);
-        emitOperandHelper(7, dst);
-        emitInt(imm32);
-    }
-
     public final void cmpq(Register dst, int imm32) {
-        emitArithImm32q(7, dst, imm32);
+        CMP.getMIOpcode(QWORD, isByte(imm32)).emit(this, QWORD, dst, imm32);
     }
 
     public final void cmpq(Register dst, Register src) {
-        int encode = prefixqAndEncode(dst.encoding, src.encoding);
-        emitByte(0x3B);
-        emitByte(0xC0 | encode);
+        CMP.rmOp.emit(this, QWORD, dst, src);
     }
 
     public final void cmpq(Register dst, AMD64Address src) {
-        prefixq(src, dst);
-        emitByte(0x3B);
-        emitOperandHelper(dst, src);
+        CMP.rmOp.emit(this, QWORD, dst, src);
     }
 
     public final void cmpxchgq(Register reg, AMD64Address adr) {
@@ -2367,76 +1991,6 @@
         emitOperandHelper(reg, adr);
     }
 
-    public final void cvtsi2sdq(Register dst, AMD64Address src) {
-        assert dst.getRegisterCategory().equals(AMD64.XMM);
-        emitByte(0xF2);
-        prefixq(src, dst);
-        emitByte(0x0F);
-        emitByte(0x2A);
-        emitOperandHelper(dst, src);
-    }
-
-    public final void cvtsi2sdq(Register dst, Register src) {
-        assert dst.getRegisterCategory().equals(AMD64.XMM);
-        emitByte(0xF2);
-        int encode = prefixqAndEncode(dst.encoding, src.encoding);
-        emitByte(0x0F);
-        emitByte(0x2A);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void cvtsi2ssq(Register dst, AMD64Address src) {
-        assert dst.getRegisterCategory().equals(AMD64.XMM);
-        emitByte(0xF3);
-        prefixq(src, dst);
-        emitByte(0x0F);
-        emitByte(0x2A);
-        emitOperandHelper(dst, src);
-    }
-
-    public final void cvtsi2ssq(Register dst, Register src) {
-        assert dst.getRegisterCategory().equals(AMD64.XMM);
-        emitByte(0xF3);
-        int encode = prefixqAndEncode(dst.encoding, src.encoding);
-        emitByte(0x0F);
-        emitByte(0x2A);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void cvttsd2siq(Register dst, AMD64Address src) {
-        emitByte(0xF2);
-        prefixq(src, dst);
-        emitByte(0x0F);
-        emitByte(0x2C);
-        emitOperandHelper(dst, src);
-    }
-
-    public final void cvttsd2siq(Register dst, Register src) {
-        assert src.getRegisterCategory().equals(AMD64.XMM);
-        emitByte(0xF2);
-        int encode = prefixqAndEncode(dst.encoding, src.encoding);
-        emitByte(0x0F);
-        emitByte(0x2C);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void cvttss2siq(Register dst, AMD64Address src) {
-        emitByte(0xF3);
-        prefixq(src, dst);
-        emitByte(0x0F);
-        emitByte(0x2C);
-        emitOperandHelper(dst, src);
-    }
-
-    public final void cvttss2siq(Register dst, Register src) {
-        assert src.getRegisterCategory().equals(AMD64.XMM);
-        emitByte(0xF3);
-        int encode = prefixqAndEncode(dst.encoding, src.encoding);
-        emitByte(0x0F);
-        emitByte(0x2C);
-        emitByte(0xC0 | encode);
-    }
-
     protected final void decq(Register dst) {
         // Use two-byte form (one-byte from is a REX prefix in 64-bit mode)
         int encode = prefixqAndEncode(dst.encoding);
@@ -2444,88 +1998,6 @@
         emitByte(0xC8 | encode);
     }
 
-    protected final void decq(AMD64Address dst) {
-        prefixq(dst);
-        emitByte(0xFF);
-        emitOperandHelper(1, dst);
-    }
-
-    public final void divq(Register src) {
-        int encode = prefixqAndEncode(6, src.encoding);
-        emitByte(0xF7);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void idivq(Register src) {
-        int encode = prefixqAndEncode(7, src.encoding);
-        emitByte(0xF7);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void mulq(Register src) {
-        int encode = prefixqAndEncode(4, src.encoding);
-        emitByte(0xF7);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void mulq(AMD64Address src) {
-        prefixq(src);
-        emitByte(0xF7);
-        emitOperandHelper(4, src);
-    }
-
-    public final void imulq(Register src) {
-        int encode = prefixqAndEncode(5, src.encoding);
-        emitByte(0xF7);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void imulq(AMD64Address src) {
-        prefixq(src);
-        emitByte(0xF7);
-        emitOperandHelper(5, src);
-    }
-
-    public final void imulq(Register dst, Register src) {
-        int encode = prefixqAndEncode(dst.encoding, src.encoding);
-        emitByte(0x0F);
-        emitByte(0xAF);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void imulq(Register dst, AMD64Address src) {
-        prefixq(src, dst);
-        emitByte(0x0F);
-        emitByte(0xAF);
-        emitOperandHelper(dst, src);
-    }
-
-    public final void imulq(Register dst, Register src, int value) {
-        int encode = prefixqAndEncode(dst.encoding, src.encoding);
-        if (isByte(value)) {
-            emitByte(0x6B);
-            emitByte(0xC0 | encode);
-            emitByte(value & 0xFF);
-        } else {
-            emitByte(0x69);
-            emitByte(0xC0 | encode);
-            emitInt(value);
-        }
-    }
-
-    public final void imulq(Register dst, AMD64Address src, int value) {
-        prefixq(src, dst);
-        if (isByte(value)) {
-            emitByte(0x6B);
-            emitOperandHelper(dst, src);
-            emitByte(value & 0xFF);
-        } else {
-            emitByte(0x69);
-            emitOperandHelper(dst, src);
-            emitInt(value);
-        }
-    }
-
     public final void incq(Register dst) {
         // Don't use it directly. Use Macroincrementq() instead.
         // Use two-byte form (one-byte from is a REX prefix in 64-bit mode)
@@ -2602,47 +2074,6 @@
         emitByte(0xD8 | encode);
     }
 
-    public final void notq(Register dst) {
-        int encode = prefixqAndEncode(dst.encoding);
-        emitByte(0xF7);
-        emitByte(0xD0 | encode);
-    }
-
-    public final void orq(Register dst, int imm32) {
-        emitArithImm32q(1, dst, imm32);
-    }
-
-    public final void orq(Register dst, AMD64Address src) {
-        prefixq(src, dst);
-        emitByte(0x0B);
-        emitOperandHelper(dst, src);
-    }
-
-    public final void orq(Register dst, Register src) {
-        int encode = prefixqAndEncode(dst.encoding, src.encoding);
-        emitByte(0x0B);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void sarq(Register dst, int imm8) {
-        assert isShiftCount(imm8 >> 1) : "illegal shift count";
-        int encode = prefixqAndEncode(dst.encoding);
-        if (imm8 == 1) {
-            emitByte(0xD1);
-            emitByte(0xF8 | encode);
-        } else {
-            emitByte(0xC1);
-            emitByte(0xF8 | encode);
-            emitByte(imm8);
-        }
-    }
-
-    public final void sarq(Register dst) {
-        int encode = prefixqAndEncode(dst.encoding);
-        emitByte(0xD3);
-        emitByte(0xF8 | encode);
-    }
-
     public final void shlq(Register dst, int imm8) {
         assert isShiftCount(imm8 >> 1) : "illegal shift count";
         int encode = prefixqAndEncode(dst.encoding);
@@ -2656,12 +2087,6 @@
         }
     }
 
-    public final void shlq(Register dst) {
-        int encode = prefixqAndEncode(dst.encoding);
-        emitByte(0xD3);
-        emitByte(0xE0 | encode);
-    }
-
     public final void shrq(Register dst, int imm8) {
         assert isShiftCount(imm8 >> 1) : "illegal shift count";
         int encode = prefixqAndEncode(dst.encoding);
@@ -2675,50 +2100,17 @@
         }
     }
 
-    public final void shrq(Register dst) {
-        int encode = prefixqAndEncode(dst.encoding);
-        emitByte(0xD3);
-        emitByte(0xE8 | encode);
-    }
-
     public final void subq(Register dst, int imm32) {
-        subq(dst, imm32, false);
+        SUB.getMIOpcode(QWORD, isByte(imm32)).emit(this, QWORD, dst, imm32);
     }
 
     public final void subqWide(Register dst, int imm32) {
-        subq(dst, imm32, true);
-    }
-
-    private void subq(Register dst, int imm32, boolean force32Imm) {
-        emitArithImm32q(5, dst, imm32, force32Imm);
-    }
-
-    public final void subq(Register dst, AMD64Address src) {
-        prefixq(src, dst);
-        emitByte(0x2B);
-        emitOperandHelper(dst, src);
+        // don't use the sign-extending version, forcing a 32-bit immediate
+        SUB.getMIOpcode(QWORD, false).emit(this, QWORD, dst, imm32);
     }
 
     public final void subq(Register dst, Register src) {
-        int encode = prefixqAndEncode(dst.encoding, src.encoding);
-        emitByte(0x2B);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void testq(Register dst, int imm32) {
-        // not using emitArith because test
-        // doesn't support sign-extension of
-        // 8bit operands
-        int encode = dst.encoding;
-        if (encode == 0) {
-            emitByte(Prefix.REXW);
-            emitByte(0xA9);
-        } else {
-            encode = prefixqAndEncode(encode);
-            emitByte(0xF7);
-            emitByte(0xC0 | encode);
-        }
-        emitInt(imm32);
+        SUB.rmOp.emit(this, QWORD, dst, src);
     }
 
     public final void testq(Register dst, Register src) {
@@ -2727,19 +2119,6 @@
         emitByte(0xC0 | encode);
     }
 
-    public final void testq(Register dst, AMD64Address src) {
-        prefixq(src, dst);
-        emitByte(0x85);
-        emitOperandHelper(dst, src);
-    }
-
-    public final void testq(AMD64Address dst, int imm32) {
-        prefixq(dst);
-        emitByte(0xF7);
-        emitOperandHelper(0, dst);
-        emitInt(imm32);
-    }
-
     public final void xaddl(AMD64Address dst, Register src) {
         prefix(dst, src);
         emitByte(0x0F);
@@ -2766,22 +2145,6 @@
         emitOperandHelper(dst, src);
     }
 
-    public final void xorq(Register dst, int imm32) {
-        emitArithImm32q(6, dst, imm32);
-    }
-
-    public final void xorq(Register dst, Register src) {
-        int encode = prefixqAndEncode(dst.encoding, src.encoding);
-        emitByte(0x33);
-        emitByte(0xC0 | encode);
-    }
-
-    public final void xorq(Register dst, AMD64Address src) {
-        prefixq(src, dst);
-        emitByte(0x33);
-        emitOperandHelper(dst, src);
-    }
-
     public final void membar(int barriers) {
         if (target.isMP) {
             // We only have to handle StoreLoad
--- a/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64MacroAssembler.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64MacroAssembler.java	Tue Mar 17 12:05:51 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2015, 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
@@ -37,10 +37,6 @@
         super(target, registerConfig);
     }
 
-    public final void xorptr(Register dst, Register src) {
-        xorq(dst, src);
-    }
-
     public final void decrementq(Register reg, int value) {
         if (value == Integer.MIN_VALUE) {
             subq(reg, value);
@@ -175,10 +171,6 @@
         }
     }
 
-    public final void signExtendShort(Register reg) {
-        movswl(reg, reg);
-    }
-
     public void movflt(Register dst, Register src) {
         assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM);
         if (UseXmmRegToRegMoveAll) {
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Tue Mar 17 12:05:51 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,9 +24,12 @@
 package com.oracle.graal.compiler.amd64;
 
 import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.*;
+import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MOp.*;
+import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp.*;
+import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64Shift.*;
+import static com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize.*;
 import static com.oracle.graal.lir.amd64.AMD64Arithmetic.*;
-import static com.oracle.graal.lir.amd64.AMD64BitManipulationOp.IntrinsicOpcode.*;
-import static com.oracle.graal.lir.amd64.AMD64Compare.*;
 import static com.oracle.graal.lir.amd64.AMD64MathIntrinsicOp.IntrinsicOpcode.*;
 
 import com.oracle.graal.amd64.*;
@@ -34,7 +37,16 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.*;
 import com.oracle.graal.asm.amd64.AMD64Address.Scale;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MIOp;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MOp;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MROp;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMIOp;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64Shift;
 import com.oracle.graal.asm.amd64.AMD64Assembler.ConditionFlag;
+import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
+import com.oracle.graal.asm.amd64.AMD64Assembler.SSEOp;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.spi.*;
@@ -42,21 +54,7 @@
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.JumpOp;
 import com.oracle.graal.lir.amd64.*;
-import com.oracle.graal.lir.amd64.AMD64Arithmetic.BinaryCommutative;
-import com.oracle.graal.lir.amd64.AMD64Arithmetic.BinaryMemory;
-import com.oracle.graal.lir.amd64.AMD64Arithmetic.BinaryRegConst;
-import com.oracle.graal.lir.amd64.AMD64Arithmetic.BinaryRegReg;
-import com.oracle.graal.lir.amd64.AMD64Arithmetic.BinaryRegStack;
-import com.oracle.graal.lir.amd64.AMD64Arithmetic.BinaryRegStackConst;
-import com.oracle.graal.lir.amd64.AMD64Arithmetic.DivRemOp;
 import com.oracle.graal.lir.amd64.AMD64Arithmetic.FPDivRemOp;
-import com.oracle.graal.lir.amd64.AMD64Arithmetic.MulHighOp;
-import com.oracle.graal.lir.amd64.AMD64Arithmetic.Unary1Op;
-import com.oracle.graal.lir.amd64.AMD64Arithmetic.Unary2MemoryOp;
-import com.oracle.graal.lir.amd64.AMD64Arithmetic.Unary2Op;
-import com.oracle.graal.lir.amd64.AMD64Arithmetic.Unary2RegOp;
-import com.oracle.graal.lir.amd64.AMD64Compare.CompareMemoryOp;
-import com.oracle.graal.lir.amd64.AMD64Compare.CompareOp;
 import com.oracle.graal.lir.amd64.AMD64ControlFlow.BranchOp;
 import com.oracle.graal.lir.amd64.AMD64ControlFlow.CondMoveOp;
 import com.oracle.graal.lir.amd64.AMD64ControlFlow.FloatBranchOp;
@@ -291,41 +289,61 @@
 
     private void emitIntegerTest(Value a, Value b) {
         assert a.getKind().isNumericInteger();
-        if (LIRValueUtil.isVariable(b)) {
-            append(new AMD64TestOp(load(b), loadNonConst(a)));
+        OperandSize size = a.getKind() == Kind.Long ? QWORD : DWORD;
+        if (isConstant(b)) {
+            append(new AMD64CompareConstOp(AMD64MIOp.TEST, size, asAllocatable(a), asConstant(b)));
+        } else if (isConstant(a)) {
+            append(new AMD64CompareConstOp(AMD64MIOp.TEST, size, asAllocatable(b), asConstant(a)));
+        } else if (isAllocatableValue(b)) {
+            append(new AMD64CompareOp(AMD64RMOp.TEST, size, asAllocatable(b), asAllocatable(a)));
         } else {
-            append(new AMD64TestOp(load(a), loadNonConst(b)));
+            append(new AMD64CompareOp(AMD64RMOp.TEST, size, asAllocatable(a), asAllocatable(b)));
         }
     }
 
     protected void emitCompareOp(PlatformKind cmpKind, Variable left, Value right) {
+        OperandSize size;
         switch ((Kind) cmpKind) {
             case Byte:
             case Boolean:
-                append(new CompareOp(BCMP, left, right));
+                size = BYTE;
                 break;
             case Short:
             case Char:
-                append(new CompareOp(SCMP, left, right));
+                size = WORD;
                 break;
             case Int:
-                append(new CompareOp(ICMP, left, right));
+                size = DWORD;
                 break;
             case Long:
-                append(new CompareOp(LCMP, left, right));
-                break;
             case Object:
-                append(new CompareOp(ACMP, left, right));
+                size = QWORD;
                 break;
             case Float:
-                append(new CompareOp(FCMP, left, right));
-                break;
+                append(new AMD64CompareOp(SSEOp.UCOMIS, PS, left, asAllocatable(right)));
+                return;
             case Double:
-                append(new CompareOp(DCMP, left, right));
-                break;
+                append(new AMD64CompareOp(SSEOp.UCOMIS, PD, left, asAllocatable(right)));
+                return;
             default:
-                throw GraalInternalError.shouldNotReachHere();
+                throw GraalInternalError.shouldNotReachHere("unexpected kind: " + cmpKind);
         }
+
+        if (isConstant(right)) {
+            JavaConstant c = asConstant(right);
+            if (c.isDefaultForKind()) {
+                AMD64RMOp op = size == BYTE ? TESTB : TEST;
+                append(new AMD64CompareOp(op, size, left, left));
+                return;
+            } else if (NumUtil.is32bit(c.asLong())) {
+                AMD64MIOp op = CMP.getMIOpcode(size, NumUtil.isByte(c.asLong()));
+                append(new AMD64CompareConstOp(op, size, left, c));
+                return;
+            }
+        }
+
+        AMD64RMOp op = CMP.getRMOpcode(size);
+        append(new AMD64CompareOp(op, size, left, asAllocatable(right)));
     }
 
     /**
@@ -336,74 +354,54 @@
      * @return true if the left and right operands were switched, false otherwise
      */
     private boolean emitCompareMemory(Kind cmpKind, Value a, AMD64AddressValue b, LIRFrameState state) {
-        boolean mirrored;
-        if (LIRValueUtil.isVariable(a)) {
-            Variable left = load(a);
-            emitCompareRegMemoryOp(cmpKind, left, b, state);
-            mirrored = false;
-        } else {
-            emitCompareMemoryConOp(cmpKind, b, (JavaConstant) a, state);
-            mirrored = true;
-        }
-        return mirrored;
-    }
-
-    protected void emitCompareMemoryConOp(Kind kind, AMD64AddressValue address, JavaConstant value, LIRFrameState state) {
-        assert kind.getStackKind() == value.getKind().getStackKind();
-        switch (kind) {
+        OperandSize size;
+        switch (cmpKind) {
             case Byte:
             case Boolean:
-                append(new CompareMemoryOp(BCMP, kind, address, value, state));
+                size = BYTE;
                 break;
             case Short:
             case Char:
-                append(new CompareMemoryOp(SCMP, kind, address, value, state));
+                size = WORD;
                 break;
             case Int:
-                append(new CompareMemoryOp(ICMP, kind, address, value, state));
+                size = DWORD;
                 break;
             case Long:
-                append(new CompareMemoryOp(LCMP, kind, address, value, state));
+            case Object:
+                size = QWORD;
                 break;
-            case Object:
-                assert value.isNull();
-                append(new CompareMemoryOp(ACMP, kind, address, value, state));
-                break;
+            case Float:
+                append(new AMD64CompareMemoryOp(SSEOp.UCOMIS, PS, asAllocatable(a), b, state));
+                return false;
+            case Double:
+                append(new AMD64CompareMemoryOp(SSEOp.UCOMIS, PD, asAllocatable(a), b, state));
+                return false;
             default:
-                throw GraalInternalError.shouldNotReachHere();
+                throw GraalInternalError.shouldNotReachHere("unexpected kind: " + cmpKind);
+        }
+
+        if (isConstant(a)) {
+            return emitCompareMemoryConOp(size, asConstant(a), b, state);
+        } else {
+            return emitCompareRegMemoryOp(size, a, b, state);
         }
     }
 
-    protected void emitCompareRegMemoryOp(Kind kind, Value value, AMD64AddressValue address, LIRFrameState state) {
-        AMD64Compare opcode = null;
-        switch (kind) {
-            case Byte:
-            case Boolean:
-                opcode = BCMP;
-                break;
-            case Short:
-            case Char:
-                opcode = SCMP;
-                break;
-            case Int:
-                opcode = ICMP;
-                break;
-            case Long:
-                opcode = LCMP;
-                break;
-            case Object:
-                opcode = ACMP;
-                break;
-            case Float:
-                opcode = FCMP;
-                break;
-            case Double:
-                opcode = DCMP;
-                break;
-            default:
-                throw GraalInternalError.shouldNotReachHere();
+    protected boolean emitCompareMemoryConOp(OperandSize size, JavaConstant a, AMD64AddressValue b, LIRFrameState state) {
+        if (NumUtil.is32bit(a.asLong())) {
+            AMD64MIOp op = CMP.getMIOpcode(size, NumUtil.isByte(a.asLong()));
+            append(new AMD64CompareMemoryConstOp(op, size, b, a, state));
+            return true;
+        } else {
+            return emitCompareRegMemoryOp(size, a, b, state);
         }
-        append(new CompareMemoryOp(opcode, kind, address, value, state));
+    }
+
+    private boolean emitCompareRegMemoryOp(OperandSize size, Value a, AMD64AddressValue b, LIRFrameState state) {
+        AMD64RMOp op = CMP.getRMOpcode(size);
+        append(new AMD64CompareMemoryOp(op, size, asAllocatable(a), b, state));
+        return false;
     }
 
     /**
@@ -437,16 +435,16 @@
         Variable result = newVariable(LIRKind.derive(input));
         switch (input.getKind()) {
             case Int:
-                append(new Unary1Op(INEG, result, input));
+                append(new AMD64UnaryMOp(NEG, DWORD, result, input));
                 break;
             case Long:
-                append(new Unary1Op(LNEG, result, input));
+                append(new AMD64UnaryMOp(NEG, QWORD, result, input));
                 break;
             case Float:
-                append(new BinaryRegConst(FXOR, result, input, JavaConstant.forFloat(Float.intBitsToFloat(0x80000000))));
+                append(new AMD64BinaryPatchOp(SSEOp.XOR, PS, result, input, JavaConstant.forFloat(Float.intBitsToFloat(0x80000000)), 16));
                 break;
             case Double:
-                append(new BinaryRegConst(DXOR, result, input, JavaConstant.forDouble(Double.longBitsToDouble(0x8000000000000000L))));
+                append(new AMD64BinaryPatchOp(SSEOp.XOR, PD, result, input, JavaConstant.forDouble(Double.longBitsToDouble(0x8000000000000000L)), 16));
                 break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
@@ -460,10 +458,10 @@
         Variable result = newVariable(LIRKind.derive(input));
         switch (input.getKind()) {
             case Int:
-                append(new Unary1Op(INOT, result, input));
+                append(new AMD64UnaryMOp(NOT, DWORD, result, input));
                 break;
             case Long:
-                append(new Unary1Op(LNOT, result, input));
+                append(new AMD64UnaryMOp(NOT, QWORD, result, input));
                 break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
@@ -471,54 +469,48 @@
         return result;
     }
 
-    private Variable emitBinary(AMD64Arithmetic op, boolean commutative, Value a, Value b) {
+    private Variable emitBinary(AMD64BinaryArithmetic op, OperandSize size, boolean commutative, Value a, Value b) {
         if (isConstant(b)) {
-            return emitBinaryConst(op, commutative, asAllocatable(a), asConstant(b));
+            return emitBinaryConst(op, size, commutative, asAllocatable(a), asConstant(b));
         } else if (commutative && isConstant(a)) {
-            return emitBinaryConst(op, commutative, asAllocatable(b), asConstant(a));
+            return emitBinaryConst(op, size, commutative, asAllocatable(b), asConstant(a));
         } else {
-            return emitBinaryVar(op, commutative, asAllocatable(a), asAllocatable(b));
+            return emitBinaryVar(op.getRMOpcode(size), size, commutative, asAllocatable(a), asAllocatable(b));
+        }
+    }
+
+    private Variable emitBinary(AMD64RMOp op, OperandSize size, boolean commutative, Value a, Value b) {
+        if (isConstant(b)) {
+            return emitBinaryConst(op, size, asAllocatable(a), asConstant(b));
+        } else if (commutative && isConstant(a)) {
+            return emitBinaryConst(op, size, asAllocatable(b), asConstant(a));
+        } else {
+            return emitBinaryVar(op, size, commutative, asAllocatable(a), asAllocatable(b));
         }
     }
 
-    private Variable emitBinaryConst(AMD64Arithmetic op, boolean commutative, AllocatableValue a, JavaConstant b) {
-        switch (op) {
-            case IADD:
-            case LADD:
-            case ISUB:
-            case LSUB:
-            case IAND:
-            case LAND:
-            case IOR:
-            case LOR:
-            case IXOR:
-            case LXOR:
-                if (NumUtil.isInt(b.asLong())) {
-                    Variable result = newVariable(LIRKind.derive(a, b));
-                    append(new BinaryRegConst(op, result, a, b));
-                    return result;
-                }
-                break;
-
-            case IMUL:
-            case LMUL:
-                if (NumUtil.isInt(b.asLong())) {
-                    Variable result = newVariable(LIRKind.derive(a, b));
-                    append(new BinaryRegStackConst(op, result, a, b));
-                    return result;
-                }
-                break;
+    private Variable emitBinaryConst(AMD64BinaryArithmetic op, OperandSize size, boolean commutative, AllocatableValue a, JavaConstant b) {
+        if (NumUtil.isInt(b.asLong())) {
+            Variable result = newVariable(LIRKind.derive(a, b));
+            append(new AMD64BinaryConstOp(op, size, result, a, b));
+            return result;
+        } else {
+            return emitBinaryVar(op.getRMOpcode(size), size, commutative, a, asAllocatable(b));
         }
-
-        return emitBinaryVar(op, commutative, a, asAllocatable(b));
     }
 
-    private Variable emitBinaryVar(AMD64Arithmetic op, boolean commutative, AllocatableValue a, AllocatableValue b) {
+    private Variable emitBinaryConst(AMD64RMOp op, OperandSize size, AllocatableValue a, JavaConstant b) {
+        Variable result = newVariable(LIRKind.derive(a, b));
+        append(new AMD64BinaryPatchOp(op, size, result, a, b));
+        return result;
+    }
+
+    private Variable emitBinaryVar(AMD64RMOp op, OperandSize size, boolean commutative, AllocatableValue a, AllocatableValue b) {
         Variable result = newVariable(LIRKind.derive(a, b));
         if (commutative) {
-            append(new BinaryCommutative(op, result, a, b));
+            append(new AMD64BinaryCommutativeOp(op, size, result, a, b));
         } else {
-            append(new BinaryRegStack(op, result, a, b));
+            append(new AMD64BinaryOp(op, size, result, a, b));
         }
         return result;
     }
@@ -527,13 +519,13 @@
     public Variable emitAdd(Value a, Value b, boolean setFlags) {
         switch (a.getKind().getStackKind()) {
             case Int:
-                return emitBinary(IADD, true, a, b);
+                return emitBinary(ADD, DWORD, true, a, b);
             case Long:
-                return emitBinary(LADD, true, a, b);
+                return emitBinary(ADD, QWORD, true, a, b);
             case Float:
-                return emitBinary(FADD, true, a, b);
+                return emitBinary(SSEOp.ADD, SS, true, a, b);
             case Double:
-                return emitBinary(DADD, true, a, b);
+                return emitBinary(SSEOp.ADD, SD, true, a, b);
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
@@ -543,48 +535,80 @@
     public Variable emitSub(Value a, Value b, boolean setFlags) {
         switch (a.getKind().getStackKind()) {
             case Int:
-                return emitBinary(ISUB, false, a, b);
+                return emitBinary(SUB, DWORD, false, a, b);
             case Long:
-                return emitBinary(LSUB, false, a, b);
+                return emitBinary(SUB, QWORD, false, a, b);
             case Float:
-                return emitBinary(FSUB, false, a, b);
+                return emitBinary(SSEOp.SUB, SS, false, a, b);
             case Double:
-                return emitBinary(DSUB, false, a, b);
+                return emitBinary(SSEOp.SUB, SD, false, a, b);
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
     }
 
+    private Variable emitIMULConst(OperandSize size, AllocatableValue a, JavaConstant b) {
+        if (NumUtil.isInt(b.asLong())) {
+            int imm = (int) b.asLong();
+            AMD64RMIOp op;
+            if (NumUtil.isByte(imm)) {
+                op = AMD64RMIOp.IMUL_SX;
+            } else {
+                op = AMD64RMIOp.IMUL;
+            }
+
+            Variable ret = newVariable(LIRKind.derive(a, b));
+            append(new AMD64MulConstOp(op, size, ret, a, b));
+            return ret;
+        } else {
+            return emitBinaryVar(AMD64RMOp.IMUL, size, true, a, asAllocatable(b));
+        }
+    }
+
+    private Variable emitIMUL(OperandSize size, Value a, Value b) {
+        if (isConstant(b)) {
+            return emitIMULConst(size, asAllocatable(a), asConstant(b));
+        } else if (isConstant(a)) {
+            return emitIMULConst(size, asAllocatable(b), asConstant(a));
+        } else {
+            return emitBinaryVar(AMD64RMOp.IMUL, size, true, asAllocatable(a), asAllocatable(b));
+        }
+    }
+
     @Override
     public Variable emitMul(Value a, Value b, boolean setFlags) {
         switch (a.getKind().getStackKind()) {
             case Int:
-                return emitBinary(IMUL, true, a, b);
+                return emitIMUL(DWORD, a, b);
             case Long:
-                return emitBinary(LMUL, true, a, b);
+                return emitIMUL(QWORD, a, b);
             case Float:
-                return emitBinary(FMUL, true, a, b);
+                return emitBinary(SSEOp.MUL, SS, true, a, b);
             case Double:
-                return emitBinary(DMUL, true, a, b);
+                return emitBinary(SSEOp.MUL, SD, true, a, b);
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
     }
 
-    private Value emitMulHigh(AMD64Arithmetic opcode, Value a, Value b) {
-        MulHighOp mulHigh = new MulHighOp(opcode, LIRKind.derive(a, b), asAllocatable(b));
-        emitMove(mulHigh.x, a);
-        append(mulHigh);
-        return emitMove(mulHigh.highResult);
+    private RegisterValue moveToReg(Register reg, Value v) {
+        RegisterValue ret = reg.asValue(v.getLIRKind());
+        emitMove(ret, v);
+        return ret;
+    }
+
+    private Value emitMulHigh(AMD64MOp opcode, OperandSize size, Value a, Value b) {
+        AMD64MulDivOp mulHigh = append(new AMD64MulDivOp(opcode, size, LIRKind.derive(a, b), moveToReg(AMD64.rax, a), asAllocatable(b)));
+        return emitMove(mulHigh.getHighResult());
     }
 
     @Override
     public Value emitMulHigh(Value a, Value b) {
         switch (a.getKind().getStackKind()) {
             case Int:
-                return emitMulHigh(IMUL, a, b);
+                return emitMulHigh(AMD64MOp.IMUL, DWORD, a, b);
             case Long:
-                return emitMulHigh(LMUL, a, b);
+                return emitMulHigh(AMD64MOp.IMUL, QWORD, a, b);
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
@@ -594,23 +618,23 @@
     public Value emitUMulHigh(Value a, Value b) {
         switch (a.getKind().getStackKind()) {
             case Int:
-                return emitMulHigh(IUMUL, a, b);
+                return emitMulHigh(AMD64MOp.MUL, DWORD, a, b);
             case Long:
-                return emitMulHigh(LUMUL, a, b);
+                return emitMulHigh(AMD64MOp.MUL, QWORD, a, b);
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
     }
 
-    public Value emitBinaryMemory(AMD64Arithmetic op, Kind kind, AllocatableValue a, AMD64AddressValue location, LIRFrameState state) {
+    public Value emitBinaryMemory(AMD64RMOp op, OperandSize size, AllocatableValue a, AMD64AddressValue location, LIRFrameState state) {
         Variable result = newVariable(LIRKind.derive(a));
-        append(new BinaryMemory(op, kind, result, a, location, state));
+        append(new AMD64BinaryMemoryOp(op, size, result, a, location, state));
         return result;
     }
 
-    protected Value emitConvert2MemoryOp(PlatformKind kind, AMD64Arithmetic op, AMD64AddressValue address, LIRFrameState state) {
+    protected Value emitConvertMemoryOp(PlatformKind kind, AMD64RMOp op, OperandSize size, AMD64AddressValue address, LIRFrameState state) {
         Variable result = newVariable(LIRKind.value(kind));
-        append(new Unary2MemoryOp(op, result, (Kind) null, address, state));
+        append(new AMD64UnaryMemoryOp(op, size, result, address, state));
         return result;
     }
 
@@ -622,48 +646,50 @@
         return result;
     }
 
-    private DivRemOp emitDivRem(AMD64Arithmetic op, Value a, Value b, LIRFrameState state) {
-        AllocatableValue rax = AMD64.rax.asValue(a.getLIRKind());
-        emitMove(rax, a);
-        DivRemOp ret = new DivRemOp(op, rax, asAllocatable(b), state);
-        append(ret);
-        return ret;
+    private AMD64MulDivOp emitIDIV(OperandSize size, Value a, Value b, LIRFrameState state) {
+        LIRKind kind = LIRKind.derive(a, b);
+
+        AMD64SignExtendOp sx = append(new AMD64SignExtendOp(size, kind, moveToReg(AMD64.rax, a)));
+        return append(new AMD64MulDivOp(AMD64MOp.IDIV, size, kind, sx.getHighResult(), sx.getLowResult(), asAllocatable(b), state));
+    }
+
+    private AMD64MulDivOp emitDIV(OperandSize size, Value a, Value b, LIRFrameState state) {
+        LIRKind kind = LIRKind.derive(a, b);
+
+        RegisterValue rax = moveToReg(AMD64.rax, a);
+        RegisterValue rdx = AMD64.rdx.asValue(kind);
+        append(new AMD64ClearRegisterOp(size, rdx));
+        return append(new AMD64MulDivOp(AMD64MOp.DIV, size, kind, rdx, rax, asAllocatable(b), state));
     }
 
     public Value[] emitIntegerDivRem(Value a, Value b, LIRFrameState state) {
-        DivRemOp op;
+        AMD64MulDivOp op;
         switch (a.getKind().getStackKind()) {
             case Int:
-                op = emitDivRem(IDIVREM, a, b, state);
+                op = emitIDIV(DWORD, a, b, state);
                 break;
             case Long:
-                op = emitDivRem(LDIVREM, a, b, state);
+                op = emitIDIV(QWORD, a, b, state);
                 break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
-        return new Value[]{emitMove(op.divResult), emitMove(op.remResult)};
+        return new Value[]{emitMove(op.getQuotient()), emitMove(op.getRemainder())};
     }
 
     @Override
     public Value emitDiv(Value a, Value b, LIRFrameState state) {
         switch (a.getKind().getStackKind()) {
             case Int:
-                DivRemOp op = emitDivRem(IDIV, a, b, state);
-                return emitMove(op.divResult);
+                AMD64MulDivOp op = emitIDIV(DWORD, a, b, state);
+                return emitMove(op.getQuotient());
             case Long:
-                DivRemOp lop = emitDivRem(LDIV, a, b, state);
-                return emitMove(lop.divResult);
-            case Float: {
-                Variable result = newVariable(LIRKind.derive(a, b));
-                append(new BinaryRegStack(FDIV, result, asAllocatable(a), asAllocatable(b)));
-                return result;
-            }
-            case Double: {
-                Variable result = newVariable(LIRKind.derive(a, b));
-                append(new BinaryRegStack(DDIV, result, asAllocatable(a), asAllocatable(b)));
-                return result;
-            }
+                AMD64MulDivOp lop = emitIDIV(QWORD, a, b, state);
+                return emitMove(lop.getQuotient());
+            case Float:
+                return emitBinary(SSEOp.DIV, SS, false, a, b);
+            case Double:
+                return emitBinary(SSEOp.DIV, SD, false, a, b);
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
@@ -673,11 +699,11 @@
     public Value emitRem(Value a, Value b, LIRFrameState state) {
         switch (a.getKind().getStackKind()) {
             case Int:
-                DivRemOp op = emitDivRem(IREM, a, b, state);
-                return emitMove(op.remResult);
+                AMD64MulDivOp op = emitIDIV(DWORD, a, b, state);
+                return emitMove(op.getRemainder());
             case Long:
-                DivRemOp lop = emitDivRem(LREM, a, b, state);
-                return emitMove(lop.remResult);
+                AMD64MulDivOp lop = emitIDIV(QWORD, a, b, state);
+                return emitMove(lop.getRemainder());
             case Float: {
                 Variable result = newVariable(LIRKind.derive(a, b));
                 append(new FPDivRemOp(FREM, result, load(a), load(b)));
@@ -695,43 +721,47 @@
 
     @Override
     public Variable emitUDiv(Value a, Value b, LIRFrameState state) {
-        DivRemOp op;
+        AMD64MulDivOp op;
         switch (a.getKind().getStackKind()) {
             case Int:
-                op = emitDivRem(IUDIV, a, b, state);
+                op = emitDIV(DWORD, a, b, state);
                 break;
             case Long:
-                op = emitDivRem(LUDIV, a, b, state);
+                op = emitDIV(QWORD, a, b, state);
                 break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
-        return emitMove(op.divResult);
+        return emitMove(op.getQuotient());
     }
 
     @Override
     public Variable emitURem(Value a, Value b, LIRFrameState state) {
-        DivRemOp op;
+        AMD64MulDivOp op;
         switch (a.getKind().getStackKind()) {
             case Int:
-                op = emitDivRem(IUREM, a, b, state);
+                op = emitDIV(DWORD, a, b, state);
                 break;
             case Long:
-                op = emitDivRem(LUREM, a, b, state);
+                op = emitDIV(QWORD, a, b, state);
                 break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
-        return emitMove(op.remResult);
+        return emitMove(op.getRemainder());
     }
 
     @Override
     public Variable emitAnd(Value a, Value b) {
         switch (a.getKind().getStackKind()) {
             case Int:
-                return emitBinary(IAND, true, a, b);
+                return emitBinary(AND, DWORD, true, a, b);
             case Long:
-                return emitBinary(LAND, true, a, b);
+                return emitBinary(AND, QWORD, true, a, b);
+            case Float:
+                return emitBinary(SSEOp.AND, PS, true, a, b);
+            case Double:
+                return emitBinary(SSEOp.AND, PD, true, a, b);
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
@@ -741,9 +771,13 @@
     public Variable emitOr(Value a, Value b) {
         switch (a.getKind().getStackKind()) {
             case Int:
-                return emitBinary(IOR, true, a, b);
+                return emitBinary(OR, DWORD, true, a, b);
             case Long:
-                return emitBinary(LOR, true, a, b);
+                return emitBinary(OR, QWORD, true, a, b);
+            case Float:
+                return emitBinary(SSEOp.OR, PS, true, a, b);
+            case Double:
+                return emitBinary(SSEOp.OR, PD, true, a, b);
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
@@ -753,22 +787,31 @@
     public Variable emitXor(Value a, Value b) {
         switch (a.getKind().getStackKind()) {
             case Int:
-                return emitBinary(IXOR, true, a, b);
+                return emitBinary(XOR, DWORD, true, a, b);
             case Long:
-                return emitBinary(LXOR, true, a, b);
+                return emitBinary(XOR, QWORD, true, a, b);
+            case Float:
+                return emitBinary(SSEOp.XOR, PS, true, a, b);
+            case Double:
+                return emitBinary(SSEOp.XOR, PD, true, a, b);
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
     }
 
-    private Variable emitShift(AMD64Arithmetic op, Value a, Value b) {
+    private Variable emitShift(AMD64Shift op, OperandSize size, Value a, Value b) {
         Variable result = newVariable(LIRKind.derive(a, b).changeType(a.getPlatformKind()));
         AllocatableValue input = asAllocatable(a);
         if (isConstant(b)) {
-            append(new BinaryRegConst(op, result, input, asConstant(b)));
+            JavaConstant c = asConstant(b);
+            if (c.asLong() == 1) {
+                append(new AMD64UnaryMOp(op.m1Op, size, result, input));
+            } else {
+                append(new AMD64BinaryConstOp(op.miOp, size, result, input, c));
+            }
         } else {
             emitMove(RCX_I, b);
-            append(new BinaryRegReg(op, result, input, RCX_I));
+            append(new AMD64ShiftOp(op.mcOp, size, result, input, RCX_I));
         }
         return result;
     }
@@ -777,9 +820,9 @@
     public Variable emitShl(Value a, Value b) {
         switch (a.getKind().getStackKind()) {
             case Int:
-                return emitShift(ISHL, a, b);
+                return emitShift(SHL, DWORD, a, b);
             case Long:
-                return emitShift(LSHL, a, b);
+                return emitShift(SHL, QWORD, a, b);
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
@@ -789,9 +832,9 @@
     public Variable emitShr(Value a, Value b) {
         switch (a.getKind().getStackKind()) {
             case Int:
-                return emitShift(ISHR, a, b);
+                return emitShift(SAR, DWORD, a, b);
             case Long:
-                return emitShift(LSHR, a, b);
+                return emitShift(SAR, QWORD, a, b);
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
@@ -801,9 +844,9 @@
     public Variable emitUShr(Value a, Value b) {
         switch (a.getKind().getStackKind()) {
             case Int:
-                return emitShift(IUSHR, a, b);
+                return emitShift(SHR, DWORD, a, b);
             case Long:
-                return emitShift(LUSHR, a, b);
+                return emitShift(SHR, QWORD, a, b);
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
@@ -812,9 +855,9 @@
     public Variable emitRol(Value a, Value b) {
         switch (a.getKind().getStackKind()) {
             case Int:
-                return emitShift(IROL, a, b);
+                return emitShift(ROL, DWORD, a, b);
             case Long:
-                return emitShift(LROL, a, b);
+                return emitShift(ROL, QWORD, a, b);
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
@@ -823,23 +866,23 @@
     public Variable emitRor(Value a, Value b) {
         switch (a.getKind().getStackKind()) {
             case Int:
-                return emitShift(IROR, a, b);
+                return emitShift(ROR, DWORD, a, b);
             case Long:
-                return emitShift(LROR, a, b);
+                return emitShift(ROR, QWORD, a, b);
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
     }
 
-    private AllocatableValue emitConvert2RegOp(LIRKind kind, AMD64Arithmetic op, AllocatableValue input) {
+    private AllocatableValue emitConvertOp(LIRKind kind, AMD64RMOp op, OperandSize size, Value input) {
         Variable result = newVariable(kind);
-        append(new Unary2RegOp(op, result, input));
+        append(new AMD64UnaryRMOp(op, size, result, asAllocatable(input)));
         return result;
     }
 
-    private AllocatableValue emitConvert2Op(LIRKind kind, AMD64Arithmetic op, AllocatableValue input) {
+    private AllocatableValue emitConvertOp(LIRKind kind, AMD64MROp op, OperandSize size, Value input) {
         Variable result = newVariable(kind);
-        append(new Unary2Op(op, result, input));
+        append(new AMD64UnaryMROp(op, size, result, asAllocatable(input)));
         return result;
     }
 
@@ -860,54 +903,53 @@
             case Int:
                 switch (fromKind) {
                     case Float:
-                        return emitConvert2Op(to, MOV_F2I, input);
+                        return emitConvertOp(to, AMD64MROp.MOVD, DWORD, input);
                 }
                 break;
             case Long:
                 switch (fromKind) {
                     case Double:
-                        return emitConvert2Op(to, MOV_D2L, input);
+                        return emitConvertOp(to, AMD64MROp.MOVQ, QWORD, input);
                 }
                 break;
             case Float:
                 switch (fromKind) {
                     case Int:
-                        return emitConvert2Op(to, MOV_I2F, input);
+                        return emitConvertOp(to, AMD64RMOp.MOVD, DWORD, input);
                 }
                 break;
             case Double:
                 switch (fromKind) {
                     case Long:
-                        return emitConvert2Op(to, MOV_L2D, input);
+                        return emitConvertOp(to, AMD64RMOp.MOVQ, QWORD, input);
                 }
                 break;
         }
         throw GraalInternalError.shouldNotReachHere();
     }
 
-    public Value emitFloatConvert(FloatConvert op, Value inputVal) {
-        AllocatableValue input = asAllocatable(inputVal);
+    public Value emitFloatConvert(FloatConvert op, Value input) {
         switch (op) {
             case D2F:
-                return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Float), D2F, input);
+                return emitConvertOp(LIRKind.derive(input).changeType(Kind.Float), SSEOp.CVTSD2SS, SD, input);
             case D2I:
-                return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Int), D2I, input);
+                return emitConvertOp(LIRKind.derive(input).changeType(Kind.Int), SSEOp.CVTTSD2SI, DWORD, input);
             case D2L:
-                return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Long), D2L, input);
+                return emitConvertOp(LIRKind.derive(input).changeType(Kind.Long), SSEOp.CVTTSD2SI, QWORD, input);
             case F2D:
-                return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Double), F2D, input);
+                return emitConvertOp(LIRKind.derive(input).changeType(Kind.Double), SSEOp.CVTSS2SD, SS, input);
             case F2I:
-                return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Int), F2I, input);
+                return emitConvertOp(LIRKind.derive(input).changeType(Kind.Int), SSEOp.CVTTSS2SI, DWORD, input);
             case F2L:
-                return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Long), F2L, input);
+                return emitConvertOp(LIRKind.derive(input).changeType(Kind.Long), SSEOp.CVTTSS2SI, QWORD, input);
             case I2D:
-                return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Double), I2D, input);
+                return emitConvertOp(LIRKind.derive(input).changeType(Kind.Double), SSEOp.CVTSI2SD, DWORD, input);
             case I2F:
-                return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Float), I2F, input);
+                return emitConvertOp(LIRKind.derive(input).changeType(Kind.Float), SSEOp.CVTSI2SS, DWORD, input);
             case L2D:
-                return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Double), L2D, input);
+                return emitConvertOp(LIRKind.derive(input).changeType(Kind.Double), SSEOp.CVTSI2SD, QWORD, input);
             case L2F:
-                return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Float), L2F, input);
+                return emitConvertOp(LIRKind.derive(input).changeType(Kind.Float), SSEOp.CVTSI2SS, QWORD, input);
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
@@ -917,7 +959,7 @@
     public Value emitNarrow(Value inputVal, int bits) {
         if (inputVal.getKind() == Kind.Long && bits <= 32) {
             // TODO make it possible to reinterpret Long as Int in LIR without move
-            return emitConvert2RegOp(LIRKind.derive(inputVal).changeType(Kind.Int), L2I, asAllocatable(inputVal));
+            return emitConvertOp(LIRKind.derive(inputVal).changeType(Kind.Int), AMD64RMOp.MOV, DWORD, inputVal);
         } else {
             return inputVal;
         }
@@ -932,11 +974,11 @@
             // sign extend to 64 bits
             switch (fromBits) {
                 case 8:
-                    return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Long), B2L, asAllocatable(inputVal));
+                    return emitConvertOp(LIRKind.derive(inputVal).changeType(Kind.Long), MOVSXB, QWORD, inputVal);
                 case 16:
-                    return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Long), S2L, asAllocatable(inputVal));
+                    return emitConvertOp(LIRKind.derive(inputVal).changeType(Kind.Long), MOVSX, QWORD, inputVal);
                 case 32:
-                    return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Long), I2L, asAllocatable(inputVal));
+                    return emitConvertOp(LIRKind.derive(inputVal).changeType(Kind.Long), MOVSXD, QWORD, inputVal);
                 default:
                     throw GraalInternalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
             }
@@ -944,9 +986,9 @@
             // sign extend to 32 bits (smaller values are internally represented as 32 bit values)
             switch (fromBits) {
                 case 8:
-                    return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Int), B2I, asAllocatable(inputVal));
+                    return emitConvertOp(LIRKind.derive(inputVal).changeType(Kind.Int), MOVSXB, DWORD, inputVal);
                 case 16:
-                    return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Int), S2I, asAllocatable(inputVal));
+                    return emitConvertOp(LIRKind.derive(inputVal).changeType(Kind.Int), MOVSX, DWORD, inputVal);
                 case 32:
                     return inputVal;
                 default:
@@ -964,13 +1006,13 @@
             assert inputVal.getKind() == Kind.Long;
             Variable result = newVariable(LIRKind.derive(inputVal).changeType(Kind.Long));
             long mask = CodeUtil.mask(fromBits);
-            append(new BinaryRegConst(AMD64Arithmetic.LAND, result, asAllocatable(inputVal), JavaConstant.forLong(mask)));
+            append(new AMD64BinaryPatchOp(AND.getRMOpcode(QWORD), QWORD, result, asAllocatable(inputVal), JavaConstant.forLong(mask)));
             return result;
         } else {
             assert inputVal.getKind().getStackKind() == Kind.Int;
             Variable result = newVariable(LIRKind.derive(inputVal).changeType(Kind.Int));
             int mask = (int) CodeUtil.mask(fromBits);
-            append(new BinaryRegConst(AMD64Arithmetic.IAND, result, asAllocatable(inputVal), JavaConstant.forInt(mask)));
+            append(new AMD64BinaryPatchOp(AND.getRMOpcode(DWORD), DWORD, result, asAllocatable(inputVal), JavaConstant.forInt(mask)));
             if (toBits > 32) {
                 Variable longResult = newVariable(LIRKind.derive(inputVal).changeType(Kind.Long));
                 emitMove(longResult, result);
@@ -1005,9 +1047,9 @@
     public Variable emitBitCount(Value value) {
         Variable result = newVariable(LIRKind.derive(value).changeType(Kind.Int));
         if (value.getKind().getStackKind() == Kind.Int) {
-            append(new AMD64BitManipulationOp(IPOPCNT, result, asAllocatable(value)));
+            append(new AMD64UnaryRMOp(POPCNT, DWORD, result, asAllocatable(value)));
         } else {
-            append(new AMD64BitManipulationOp(LPOPCNT, result, asAllocatable(value)));
+            append(new AMD64UnaryRMOp(POPCNT, QWORD, result, asAllocatable(value)));
         }
         return result;
     }
@@ -1015,7 +1057,7 @@
     @Override
     public Variable emitBitScanForward(Value value) {
         Variable result = newVariable(LIRKind.derive(value).changeType(Kind.Int));
-        append(new AMD64BitManipulationOp(BSF, result, asAllocatable(value)));
+        append(new AMD64UnaryRMOp(BSF, QWORD, result, asAllocatable(value)));
         return result;
     }
 
@@ -1023,9 +1065,9 @@
     public Variable emitBitScanReverse(Value value) {
         Variable result = newVariable(LIRKind.derive(value).changeType(Kind.Int));
         if (value.getKind().getStackKind() == Kind.Int) {
-            append(new AMD64BitManipulationOp(IBSR, result, asAllocatable(value)));
+            append(new AMD64UnaryRMOp(BSR, DWORD, result, asAllocatable(value)));
         } else {
-            append(new AMD64BitManipulationOp(LBSR, result, asAllocatable(value)));
+            append(new AMD64UnaryRMOp(BSR, QWORD, result, asAllocatable(value)));
         }
         return result;
     }
@@ -1033,9 +1075,9 @@
     public Value emitCountLeadingZeros(Value value) {
         Variable result = newVariable(LIRKind.derive(value).changeType(Kind.Int));
         if (value.getKind().getStackKind() == Kind.Int) {
-            append(new AMD64BitManipulationOp(ILZCNT, result, asAllocatable(value)));
+            append(new AMD64UnaryRMOp(LZCNT, DWORD, result, asAllocatable(value)));
         } else {
-            append(new AMD64BitManipulationOp(LLZCNT, result, asAllocatable(value)));
+            append(new AMD64UnaryRMOp(LZCNT, QWORD, result, asAllocatable(value)));
         }
         return result;
     }
@@ -1043,9 +1085,9 @@
     public Value emitCountTrailingZeros(Value value) {
         Variable result = newVariable(LIRKind.derive(value).changeType(Kind.Int));
         if (value.getKind().getStackKind() == Kind.Int) {
-            append(new AMD64BitManipulationOp(ITZCNT, result, asAllocatable(value)));
+            append(new AMD64UnaryRMOp(TZCNT, DWORD, result, asAllocatable(value)));
         } else {
-            append(new AMD64BitManipulationOp(LTZCNT, result, asAllocatable(value)));
+            append(new AMD64UnaryRMOp(TZCNT, QWORD, result, asAllocatable(value)));
         }
         return result;
     }
@@ -1055,10 +1097,10 @@
         Variable result = newVariable(LIRKind.derive(input));
         switch (input.getKind()) {
             case Float:
-                append(new BinaryRegConst(FAND, result, asAllocatable(input), JavaConstant.forFloat(Float.intBitsToFloat(0x7FFFFFFF))));
+                append(new AMD64BinaryPatchOp(SSEOp.AND, PS, result, asAllocatable(input), JavaConstant.forFloat(Float.intBitsToFloat(0x7FFFFFFF)), 16));
                 break;
             case Double:
-                append(new BinaryRegConst(DAND, result, asAllocatable(input), JavaConstant.forDouble(Double.longBitsToDouble(0x7FFFFFFFFFFFFFFFL))));
+                append(new AMD64BinaryPatchOp(SSEOp.AND, PD, result, asAllocatable(input), JavaConstant.forDouble(Double.longBitsToDouble(0x7FFFFFFFFFFFFFFFL)), 16));
                 break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
@@ -1069,7 +1111,16 @@
     @Override
     public Value emitMathSqrt(Value input) {
         Variable result = newVariable(LIRKind.derive(input));
-        append(new Unary2Op(SQRT, result, asAllocatable(input)));
+        switch (input.getKind()) {
+            case Float:
+                append(new AMD64UnaryRMOp(SSEOp.SQRT, SS, result, asAllocatable(input)));
+                break;
+            case Double:
+                append(new AMD64UnaryRMOp(SSEOp.SQRT, SD, result, asAllocatable(input)));
+                break;
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
         return result;
     }
 
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java	Tue Mar 17 12:05:51 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2015, 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
@@ -23,12 +23,18 @@
 
 package com.oracle.graal.compiler.amd64;
 
-import static com.oracle.graal.lir.amd64.AMD64Arithmetic.*;
+import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.*;
+import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp.*;
+import static com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize.*;
 
 import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.*;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MIOp;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp;
+import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
+import com.oracle.graal.asm.amd64.AMD64Assembler.SSEOp;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.gen.*;
@@ -108,6 +114,27 @@
         return (Kind) gen.getLIRKind(access.asNode().stamp()).getPlatformKind();
     }
 
+    protected OperandSize getMemorySize(Access access) {
+        switch (getMemoryKind(access)) {
+            case Boolean:
+            case Byte:
+                return OperandSize.BYTE;
+            case Char:
+            case Short:
+                return OperandSize.WORD;
+            case Int:
+                return OperandSize.DWORD;
+            case Long:
+                return OperandSize.QWORD;
+            case Float:
+                return OperandSize.SS;
+            case Double:
+                return OperandSize.SD;
+            default:
+                throw GraalInternalError.shouldNotReachHere("unsupported memory access type " + getMemoryKind(access));
+        }
+    }
+
     protected AMD64AddressValue makeAddress(Access access) {
         return (AMD64AddressValue) access.accessLocation().generateAddress(this, gen, operand(access.object()));
     }
@@ -176,6 +203,7 @@
         LabelRef falseLabel = getLIRBlock(x.falseSuccessor());
         double trueLabelProbability = x.probability(x.trueSuccessor());
         Kind kind = getMemoryKind(access);
+        OperandSize size = kind == Kind.Long ? QWORD : DWORD;
         if (value.isConstant()) {
             if (kind != kind.getStackKind()) {
                 return null;
@@ -186,83 +214,61 @@
                 return null;
             }
             return builder -> {
-                gen.append(new AMD64TestMemoryOp(kind, makeAddress(access), constant, getState(access)));
+                gen.append(new AMD64CompareMemoryConstOp(AMD64MIOp.TEST, size, makeAddress(access), constant, getState(access)));
                 gen.append(new BranchOp(Condition.EQ, trueLabel, falseLabel, trueLabelProbability));
                 return null;
             };
         } else {
             return builder -> {
-                gen.append(new AMD64TestMemoryOp(kind, makeAddress(access), operand(value), getState(access)));
+                gen.append(new AMD64CompareMemoryOp(AMD64RMOp.TEST, size, gen.asAllocatable(operand(value)), makeAddress(access), getState(access)));
                 gen.append(new BranchOp(Condition.EQ, trueLabel, falseLabel, trueLabelProbability));
                 return null;
             };
         }
     }
 
-    protected Value emitConvert2MemoryOp(PlatformKind kind, AMD64Arithmetic op, Access access) {
-        AMD64AddressValue address = makeAddress(access);
-        LIRFrameState state = getState(access);
-        return getLIRGeneratorTool().emitConvert2MemoryOp(kind, op, address, state);
-    }
-
-    private Value emitFloatConvertMemory(FloatConvertNode op, Access access) {
-        switch (op.getFloatConvert()) {
-            case D2F:
-                return emitConvert2MemoryOp(Kind.Float, D2F, access);
-            case D2I:
-                return emitConvert2MemoryOp(Kind.Int, D2I, access);
-            case D2L:
-                return emitConvert2MemoryOp(Kind.Long, D2L, access);
-            case F2D:
-                return emitConvert2MemoryOp(Kind.Double, F2D, access);
-            case F2I:
-                return emitConvert2MemoryOp(Kind.Int, F2I, access);
-            case F2L:
-                return emitConvert2MemoryOp(Kind.Long, F2L, access);
-            case I2D:
-                return emitConvert2MemoryOp(Kind.Double, I2D, access);
-            case I2F:
-                return emitConvert2MemoryOp(Kind.Float, I2F, access);
-            case L2D:
-                return emitConvert2MemoryOp(Kind.Double, L2D, access);
-            case L2F:
-                return emitConvert2MemoryOp(Kind.Float, L2F, access);
-            default:
-                throw GraalInternalError.shouldNotReachHere();
-        }
+    protected ComplexMatchResult emitConvertMemoryOp(PlatformKind kind, AMD64RMOp op, OperandSize size, Access access) {
+        return builder -> {
+            AMD64AddressValue address = makeAddress(access);
+            LIRFrameState state = getState(access);
+            return getLIRGeneratorTool().emitConvertMemoryOp(kind, op, size, address, state);
+        };
     }
 
     private ComplexMatchResult emitSignExtendMemory(Access access, int fromBits, int toBits) {
         assert fromBits <= toBits && toBits <= 64;
         Kind kind = null;
-        AMD64Arithmetic op = null;
+        AMD64RMOp op;
+        OperandSize size;
         if (fromBits == toBits) {
             return null;
         } else if (toBits > 32) {
             kind = Kind.Long;
+            size = QWORD;
             // sign extend to 64 bits
             switch (fromBits) {
                 case 8:
-                    op = B2L;
+                    op = MOVSXB;
                     break;
                 case 16:
-                    op = S2L;
+                    op = MOVSX;
                     break;
                 case 32:
-                    op = I2L;
+                    op = MOVSXD;
                     break;
                 default:
                     throw GraalInternalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
             }
         } else {
             kind = Kind.Int;
+            size = DWORD;
             // sign extend to 32 bits (smaller values are internally represented as 32 bit values)
             switch (fromBits) {
                 case 8:
-                    op = B2I;
+                    op = MOVSXB;
                     break;
                 case 16:
-                    op = S2I;
+                    op = MOVSX;
                     break;
                 case 32:
                     return null;
@@ -271,13 +277,7 @@
             }
         }
         if (kind != null && op != null) {
-            Kind localKind = kind;
-            AMD64Arithmetic localOp = op;
-            return new ComplexMatchResult() {
-                public Value evaluate(NodeLIRBuilder builder) {
-                    return emitConvert2MemoryOp(localKind, localOp, access);
-                }
-            };
+            return emitConvertMemoryOp(kind, op, size, access);
         }
         return null;
     }
@@ -288,66 +288,6 @@
         return getLIRGeneratorTool().emitLoad(to, address, state);
     }
 
-    protected AMD64Arithmetic getOp(ValueNode operation, Access access) {
-        Kind memoryKind = getMemoryKind(access);
-        if (operation.getClass() == AddNode.class) {
-            switch (memoryKind) {
-                case Int:
-                    return IADD;
-                case Long:
-                    return LADD;
-                case Float:
-                    return FADD;
-                case Double:
-                    return DADD;
-            }
-        } else if (operation.getClass() == AndNode.class) {
-            switch (memoryKind) {
-                case Int:
-                    return IAND;
-                case Long:
-                    return LAND;
-            }
-        } else if (operation.getClass() == OrNode.class) {
-            switch (memoryKind) {
-                case Int:
-                    return IOR;
-                case Long:
-                    return LOR;
-            }
-        } else if (operation.getClass() == XorNode.class) {
-            switch (memoryKind) {
-                case Int:
-                    return IXOR;
-                case Long:
-                    return LXOR;
-            }
-        } else if (operation.getClass() == SubNode.class) {
-            switch (memoryKind) {
-                case Int:
-                    return ISUB;
-                case Long:
-                    return LSUB;
-                case Float:
-                    return FSUB;
-                case Double:
-                    return DSUB;
-            }
-        } else if (operation.getClass() == MulNode.class) {
-            switch (memoryKind) {
-                case Int:
-                    return IMUL;
-                case Long:
-                    return LMUL;
-                case Float:
-                    return FMUL;
-                case Double:
-                    return DMUL;
-            }
-        }
-        return null;
-    }
-
     @MatchRule("(If (IntegerTest Read=access value))")
     @MatchRule("(If (IntegerTest FloatingRead=access value))")
     public ComplexMatchResult integerTestBranchMemory(IfNode root, Access access, ValueNode value) {
@@ -392,24 +332,74 @@
         return null;
     }
 
+    private ComplexMatchResult binaryRead(AMD64RMOp op, OperandSize size, ValueNode value, Access access) {
+        return builder -> getLIRGeneratorTool().emitBinaryMemory(op, size, getLIRGeneratorTool().asAllocatable(operand(value)), makeAddress(access), getState(access));
+    }
+
     @MatchRule("(Add value Read=access)")
+    @MatchRule("(Add value FloatingRead=access)")
+    public ComplexMatchResult addMemory(ValueNode value, Access access) {
+        OperandSize size = getMemorySize(access);
+        if (size.isXmmType()) {
+            return binaryRead(SSEOp.ADD, size, value, access);
+        } else {
+            return binaryRead(ADD.getRMOpcode(size), size, value, access);
+        }
+    }
+
     @MatchRule("(Sub value Read=access)")
+    @MatchRule("(Sub value FloatingRead=access)")
+    public ComplexMatchResult subMemory(ValueNode value, Access access) {
+        OperandSize size = getMemorySize(access);
+        if (size.isXmmType()) {
+            return binaryRead(SSEOp.SUB, size, value, access);
+        } else {
+            return binaryRead(SUB.getRMOpcode(size), size, value, access);
+        }
+    }
+
     @MatchRule("(Mul value Read=access)")
-    @MatchRule("(Or value Read=access)")
-    @MatchRule("(Xor value Read=access)")
-    @MatchRule("(And value Read=access)")
-    @MatchRule("(Add value FloatingRead=access)")
-    @MatchRule("(Sub value FloatingRead=access)")
     @MatchRule("(Mul value FloatingRead=access)")
-    @MatchRule("(Or value FloatingRead=access)")
-    @MatchRule("(Xor value FloatingRead=access)")
+    public ComplexMatchResult mulMemory(ValueNode value, Access access) {
+        OperandSize size = getMemorySize(access);
+        if (size.isXmmType()) {
+            return binaryRead(SSEOp.MUL, size, value, access);
+        } else {
+            return binaryRead(AMD64RMOp.IMUL, size, value, access);
+        }
+    }
+
+    @MatchRule("(And value Read=access)")
     @MatchRule("(And value FloatingRead=access)")
-    public ComplexMatchResult binaryRead(BinaryNode root, ValueNode value, Access access) {
-        AMD64Arithmetic op = getOp(root, access);
-        if (op != null) {
-            return builder -> getLIRGeneratorTool().emitBinaryMemory(op, getMemoryKind(access), getLIRGeneratorTool().asAllocatable(operand(value)), makeAddress(access), getState(access));
+    public ComplexMatchResult andMemory(ValueNode value, Access access) {
+        OperandSize size = getMemorySize(access);
+        if (size.isXmmType()) {
+            return null;
+        } else {
+            return binaryRead(AND.getRMOpcode(size), size, value, access);
         }
-        return null;
+    }
+
+    @MatchRule("(Or value Read=access)")
+    @MatchRule("(Or value FloatingRead=access)")
+    public ComplexMatchResult orMemory(ValueNode value, Access access) {
+        OperandSize size = getMemorySize(access);
+        if (size.isXmmType()) {
+            return null;
+        } else {
+            return binaryRead(OR.getRMOpcode(size), size, value, access);
+        }
+    }
+
+    @MatchRule("(Xor value Read=access)")
+    @MatchRule("(Xor value FloatingRead=access)")
+    public ComplexMatchResult xorMemory(ValueNode value, Access access) {
+        OperandSize size = getMemorySize(access);
+        if (size.isXmmType()) {
+            return null;
+        } else {
+            return binaryRead(XOR.getRMOpcode(size), size, value, access);
+        }
     }
 
     @MatchRule("(Write Narrow=narrow location value)")
@@ -447,8 +437,30 @@
     @MatchRule("(FloatConvert Read=access)")
     @MatchRule("(FloatConvert FloatingRead=access)")
     public ComplexMatchResult floatConvert(FloatConvertNode root, Access access) {
-        return builder -> emitFloatConvertMemory(root, access);
-
+        switch (root.getFloatConvert()) {
+            case D2F:
+                return emitConvertMemoryOp(Kind.Float, SSEOp.CVTSD2SS, SD, access);
+            case D2I:
+                return emitConvertMemoryOp(Kind.Int, SSEOp.CVTTSD2SI, DWORD, access);
+            case D2L:
+                return emitConvertMemoryOp(Kind.Long, SSEOp.CVTTSD2SI, QWORD, access);
+            case F2D:
+                return emitConvertMemoryOp(Kind.Double, SSEOp.CVTSS2SD, SS, access);
+            case F2I:
+                return emitConvertMemoryOp(Kind.Int, SSEOp.CVTTSS2SI, DWORD, access);
+            case F2L:
+                return emitConvertMemoryOp(Kind.Long, SSEOp.CVTTSS2SI, QWORD, access);
+            case I2D:
+                return emitConvertMemoryOp(Kind.Double, SSEOp.CVTSI2SD, DWORD, access);
+            case I2F:
+                return emitConvertMemoryOp(Kind.Float, SSEOp.CVTSI2SS, DWORD, access);
+            case L2D:
+                return emitConvertMemoryOp(Kind.Double, SSEOp.CVTSI2SD, QWORD, access);
+            case L2F:
+                return emitConvertMemoryOp(Kind.Float, SSEOp.CVTSI2SS, QWORD, access);
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
     }
 
     @MatchRule("(Reinterpret Read=access)")
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/AbstractControlFlowGraph.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/AbstractControlFlowGraph.java	Tue Mar 17 12:05:51 2015 +0100
@@ -89,6 +89,14 @@
     }
 
     /**
+     * True if block {@code a} dominates block {@code b} and {@code a} is not identical block to
+     * {@code b}.
+     */
+    static boolean strictlyDominates(AbstractBlockBase<?> a, AbstractBlockBase<?> b) {
+        return a != b && dominates(a, b);
+    }
+
+    /**
      * True if block {@code a} dominates block {@code b}.
      */
     static boolean dominates(AbstractBlockBase<?> a, AbstractBlockBase<?> b) {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Tue Mar 17 12:05:51 2015 +0100
@@ -305,7 +305,6 @@
 
     protected static String getCanonicalGraphString(StructuredGraph graph, boolean excludeVirtual, boolean checkConstants) {
         SchedulePhase schedule = new SchedulePhase(SchedulingStrategy.EARLIEST);
-        schedule.setScheduleConstants(true);
         schedule.apply(graph);
 
         NodeMap<Integer> canonicalId = graph.createNodeMap();
@@ -325,7 +324,7 @@
             }
             result.append("\n");
             for (Node node : schedule.getBlockToNodesMap().get(block)) {
-                if (node.isAlive()) {
+                if (node instanceof ValueNode && node.isAlive()) {
                     if (!excludeVirtual || !(node instanceof VirtualObjectNode || node instanceof ProxyNode)) {
                         if (node instanceof ConstantNode) {
                             String name = checkConstants ? node.toString(Verbosity.Name) : node.getClass().getSimpleName();
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraphScheduleTest.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraphScheduleTest.java	Tue Mar 17 12:05:51 2015 +0100
@@ -45,7 +45,7 @@
         Block aBlock = nodeToBlock.get(a);
 
         if (bBlock == aBlock) {
-            List<ValueNode> instructions = ibp.nodesFor(bBlock);
+            List<Node> instructions = ibp.nodesFor(bBlock);
             Assert.assertTrue(instructions.indexOf(b) > instructions.indexOf(a));
         } else {
             Block block = bBlock;
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java	Tue Mar 17 12:05:51 2015 +0100
@@ -23,10 +23,12 @@
 package com.oracle.graal.compiler.test;
 
 import static com.oracle.graal.compiler.common.GraalOptions.*;
+
 import java.util.*;
 
 import org.junit.*;
 
+import com.oracle.graal.api.directives.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.*;
@@ -251,6 +253,62 @@
     }
 
     /**
+     * Here the read should not float out of the loop.
+     */
+    public static int testLoop6Snippet(int a, int b, MemoryScheduleTest obj) {
+        int ret = 0;
+        int bb = b;
+        for (int i = 0; i < a; i++) {
+            ret = obj.hash;
+            if (a > 10) {
+                bb++;
+            } else {
+                bb--;
+                for (int j = 0; j < b; ++j) {
+                    obj.hash = 3;
+                }
+            }
+            ret = ret / 10;
+        }
+        return ret + bb;
+    }
+
+    @Test
+    public void testLoop6() {
+        SchedulePhase schedule = getFinalSchedule("testLoop6Snippet", TestMode.WITHOUT_FRAMESTATES);
+        assertDeepEquals(13, schedule.getCFG().getBlocks().size());
+        assertReadWithinStartBlock(schedule, false);
+        assertReadWithinAllReturnBlocks(schedule, false);
+    }
+
+    /**
+     * Here the read should not float to the end.
+     */
+    public static int testLoop7Snippet(int a, int b) {
+        int result = container.a;
+        for (int i = 0; i < a; i++) {
+            if (b < 0) {
+                container.b = 10;
+                break;
+            } else {
+                for (int j = 0; j < b; j++) {
+                    container.a = 0;
+                }
+            }
+        }
+        GraalDirectives.controlFlowAnchor();
+        return result;
+    }
+
+    @Test
+    public void testLoop7() {
+        SchedulePhase schedule = getFinalSchedule("testLoop7Snippet", TestMode.WITHOUT_FRAMESTATES);
+        assertDeepEquals(10, schedule.getCFG().getBlocks().size());
+        assertReadWithinStartBlock(schedule, true);
+        assertReadWithinAllReturnBlocks(schedule, false);
+    }
+
+    /**
      * Here the read should float to the end (into the same block as the return).
      */
     public static int testArrayCopySnippet(Integer intValue, char[] a, char[] b, int len) {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SchedulingTest.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SchedulingTest.java	Tue Mar 17 12:05:51 2015 +0100
@@ -60,10 +60,10 @@
         NodeMap<Block> nodeToBlock = schedule.getCFG().getNodeToBlock();
         assertTrue(graph.getNodes().filter(LoopExitNode.class).count() == 1);
         LoopExitNode loopExit = graph.getNodes().filter(LoopExitNode.class).first();
-        List<ValueNode> list = schedule.nodesFor(nodeToBlock.get(loopExit));
+        List<Node> list = schedule.nodesFor(nodeToBlock.get(loopExit));
         for (BinaryArithmeticNode<?> node : graph.getNodes().filter(BinaryArithmeticNode.class)) {
             if (!(node instanceof AddNode)) {
-                assertTrue(nodeToBlock.get(node) == nodeToBlock.get(loopExit));
+                assertTrue(node.toString(), nodeToBlock.get(node) == nodeToBlock.get(loopExit));
                 assertTrue(list.indexOf(node) + " < " + list.indexOf(loopExit) + ", " + node + ", " + loopExit, list.indexOf(node) < list.indexOf(loopExit));
             }
         }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Tue Mar 17 12:05:51 2015 +0100
@@ -269,7 +269,6 @@
             graph.maybeCompress();
 
             SchedulePhase schedule = new SchedulePhase();
-            schedule.setScheduleConstants(true);
             schedule.apply(graph);
             Debug.dump(schedule, "Final HIR schedule");
             return schedule;
@@ -284,7 +283,6 @@
             // Repeatedly run the LIR code generation pass to improve statistical profiling results.
             for (int i = 0; i < EmitLIRRepeatCount.getValue(); i++) {
                 SchedulePhase dummySchedule = new SchedulePhase();
-                dummySchedule.setScheduleConstants(true);
                 dummySchedule.apply(graph);
                 emitLIR(backend, target, dummySchedule, graph, stub, cc, registerConfig, lirSuites);
             }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/LIRGenerationPhase.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/LIRGenerationPhase.java	Tue Mar 17 12:05:51 2015 +0100
@@ -26,6 +26,7 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.phases.*;
 import com.oracle.graal.nodes.*;
@@ -61,7 +62,7 @@
         context.lirGen.beforeRegisterAllocation();
     }
 
-    private static void emitBlock(NodeLIRBuilderTool nodeLirGen, LIRGenerationResult lirGenRes, Block b, StructuredGraph graph, BlockMap<List<ValueNode>> blockMap) {
+    private static void emitBlock(NodeLIRBuilderTool nodeLirGen, LIRGenerationResult lirGenRes, Block b, StructuredGraph graph, BlockMap<List<Node>> blockMap) {
         if (lirGenRes.getLIR().getLIRforBlock(b) == null) {
             for (Block pred : b.getPredecessors()) {
                 if (!b.isLoopHeader() || !pred.isLoopEnd()) {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java	Tue Mar 17 12:05:51 2015 +0100
@@ -92,7 +92,7 @@
     private ValueNode currentInstruction;
     private ValueNode lastInstructionPrinted; // Debugging only
 
-    private Map<Class<? extends ValueNode>, List<MatchStatement>> matchRules;
+    private Map<Class<? extends Node>, List<MatchStatement>> matchRules;
 
     public NodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool gen) {
         this.gen = gen;
@@ -116,18 +116,18 @@
      * @param node A node that produces a result value.
      */
     @Override
-    public Value operand(ValueNode node) {
+    public Value operand(Node node) {
         Value operand = getOperand(node);
         assert operand != null : String.format("missing operand for %1s", node);
         return operand;
     }
 
     @Override
-    public boolean hasOperand(ValueNode node) {
+    public boolean hasOperand(Node node) {
         return getOperand(node) != null;
     }
 
-    private Value getOperand(ValueNode node) {
+    private Value getOperand(Node node) {
         if (nodeOperands == null) {
             return null;
         }
@@ -162,7 +162,7 @@
      * Used by the {@link MatchStatement} machinery to override the generation LIR for some
      * ValueNodes.
      */
-    public void setMatchResult(ValueNode x, Value operand) {
+    public void setMatchResult(Node x, Value operand) {
         assert operand.equals(ComplexMatchValue.INTERIOR_MATCH) || operand instanceof ComplexMatchValue;
         assert operand instanceof ComplexMatchValue || x.getUsageCount() == 1 : "interior matches must be single user";
         assert nodeOperands != null && nodeOperands.get(x) == null : "operand cannot be set twice";
@@ -191,7 +191,7 @@
         gen.append(op);
     }
 
-    public void doBlock(Block block, StructuredGraph graph, BlockMap<List<ValueNode>> blockMap) {
+    public void doBlock(Block block, StructuredGraph graph, BlockMap<List<Node>> blockMap) {
         gen.doBlockStart(block);
 
         if (block == gen.getResult().getLIR().getControlFlowGraph().getStartBlock()) {
@@ -201,41 +201,44 @@
             assert block.getPredecessorCount() > 0;
         }
 
-        List<ValueNode> nodes = blockMap.get(block);
+        List<Node> nodes = blockMap.get(block);
 
         // Allow NodeLIRBuilder subclass to specialize code generation of any interesting groups
         // of instructions
         matchComplexExpressions(nodes);
 
         for (int i = 0; i < nodes.size(); i++) {
-            ValueNode valueNode = nodes.get(i);
-            if (Options.TraceLIRGeneratorLevel.getValue() >= 3) {
-                TTY.println("LIRGen for " + valueNode);
-            }
-            Value operand = getOperand(valueNode);
-            if (operand == null) {
-                if (!peephole(valueNode)) {
-                    try {
-                        doRoot(valueNode);
-                    } catch (GraalInternalError e) {
-                        throw GraalGraphInternalError.transformAndAddContext(e, valueNode);
-                    } catch (Throwable e) {
-                        throw new GraalGraphInternalError(e).addContext(valueNode);
+            Node node = nodes.get(i);
+            if (node instanceof ValueNode) {
+                ValueNode valueNode = (ValueNode) node;
+                if (Options.TraceLIRGeneratorLevel.getValue() >= 3) {
+                    TTY.println("LIRGen for " + valueNode);
+                }
+                Value operand = getOperand(valueNode);
+                if (operand == null) {
+                    if (!peephole(valueNode)) {
+                        try {
+                            doRoot(valueNode);
+                        } catch (GraalInternalError e) {
+                            throw GraalGraphInternalError.transformAndAddContext(e, valueNode);
+                        } catch (Throwable e) {
+                            throw new GraalGraphInternalError(e).addContext(valueNode);
+                        }
                     }
+                } else if (ComplexMatchValue.INTERIOR_MATCH.equals(operand)) {
+                    // Doesn't need to be evaluated
+                    Debug.log("interior match for %s", valueNode);
+                } else if (operand instanceof ComplexMatchValue) {
+                    Debug.log("complex match for %s", valueNode);
+                    ComplexMatchValue match = (ComplexMatchValue) operand;
+                    operand = match.evaluate(this);
+                    if (operand != null) {
+                        setResult(valueNode, operand);
+                    }
+                } else {
+                    // There can be cases in which the result of an instruction is already set
+                    // before by other instructions.
                 }
-            } else if (ComplexMatchValue.INTERIOR_MATCH.equals(operand)) {
-                // Doesn't need to be evaluated
-                Debug.log("interior match for %s", valueNode);
-            } else if (operand instanceof ComplexMatchValue) {
-                Debug.log("complex match for %s", valueNode);
-                ComplexMatchValue match = (ComplexMatchValue) operand;
-                operand = match.evaluate(this);
-                if (operand != null) {
-                    setResult(valueNode, operand);
-                }
-            } else {
-                // There can be cases in which the result of an instruction is already set
-                // before by other instructions.
             }
         }
 
@@ -256,19 +259,19 @@
         gen.doBlockEnd(block);
     }
 
-    protected void matchComplexExpressions(List<ValueNode> nodes) {
+    protected void matchComplexExpressions(List<Node> nodes) {
         if (matchRules != null) {
             try (Scope s = Debug.scope("MatchComplexExpressions")) {
                 if (LogVerbose.getValue()) {
                     int i = 0;
-                    for (ValueNode node : nodes) {
+                    for (Node node : nodes) {
                         Debug.log("%d: (%s) %1S", i++, node.getUsageCount(), node);
                     }
                 }
 
                 // Match the nodes in backwards order to encourage longer matches.
                 for (int index = nodes.size() - 1; index >= 0; index--) {
-                    ValueNode node = nodes.get(index);
+                    Node node = nodes.get(index);
                     if (getOperand(node) != null) {
                         continue;
                     }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchContext.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchContext.java	Tue Mar 17 12:05:51 2015 +0100
@@ -30,7 +30,7 @@
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.match.MatchPattern.Result;
 import com.oracle.graal.debug.*;
-import com.oracle.graal.nodes.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.virtual.*;
 
@@ -39,15 +39,15 @@
  */
 public class MatchContext {
 
-    private final ValueNode root;
+    private final Node root;
 
-    private final List<ValueNode> nodes;
+    private final List<Node> nodes;
 
     private final MatchStatement rule;
 
     private Map<String, NamedNode> namedNodes;
 
-    private ArrayList<ValueNode> consumed;
+    private ArrayList<Node> consumed;
 
     private int startIndex;
 
@@ -56,16 +56,16 @@
     private final NodeLIRBuilder builder;
 
     private static class NamedNode {
-        final Class<? extends ValueNode> type;
-        final ValueNode value;
+        final Class<? extends Node> type;
+        final Node value;
 
-        NamedNode(Class<? extends ValueNode> type, ValueNode value) {
+        NamedNode(Class<? extends Node> type, Node value) {
             this.type = type;
             this.value = value;
         }
     }
 
-    public MatchContext(NodeLIRBuilder builder, MatchStatement rule, int index, ValueNode node, List<ValueNode> nodes) {
+    public MatchContext(NodeLIRBuilder builder, MatchStatement rule, int index, Node node, List<Node> nodes) {
         this.builder = builder;
         this.rule = rule;
         this.root = node;
@@ -75,11 +75,11 @@
         startIndex = endIndex = index;
     }
 
-    public ValueNode getRoot() {
+    public Node getRoot() {
         return root;
     }
 
-    public Result captureNamedValue(String name, Class<? extends ValueNode> type, ValueNode value) {
+    public Result captureNamedValue(String name, Class<? extends Node> type, Node value) {
         if (namedNodes == null) {
             namedNodes = new HashMap<>(2);
         }
@@ -99,7 +99,7 @@
     public Result validate() {
         // Ensure that there's no unsafe work in between these operations.
         for (int i = startIndex; i <= endIndex; i++) {
-            ValueNode node = nodes.get(i);
+            Node node = nodes.get(i);
             if (node instanceof VirtualObjectNode || node instanceof FloatingNode) {
                 // The order of evaluation of these nodes controlled by data dependence so they
                 // don't interfere with this match.
@@ -108,7 +108,7 @@
                 if (LogVerbose.getValue()) {
                     Debug.log("unexpected node %s", node);
                     for (int j = startIndex; j <= endIndex; j++) {
-                        ValueNode theNode = nodes.get(j);
+                        Node theNode = nodes.get(j);
                         Debug.log("%s(%s) %1s", (consumed != null && consumed.contains(theNode) || theNode == root) ? "*" : " ", theNode.getUsageCount(), theNode);
                     }
                 }
@@ -131,7 +131,7 @@
             Debug.log("with nodes %s", rule.formatMatch(root));
         }
         if (consumed != null) {
-            for (ValueNode node : consumed) {
+            for (Node node : consumed) {
                 // All the interior nodes should be skipped during the normal doRoot calls in
                 // NodeLIRBuilder so mark them as interior matches. The root of the match will get a
                 // closure which will be evaluated to produce the final LIR.
@@ -146,7 +146,7 @@
      *
      * @return Result.OK if the node can be safely consumed.
      */
-    public Result consume(ValueNode node) {
+    public Result consume(Node node) {
         assert node.getUsageCount() <= 1 : "should have already been checked";
 
         // Check NOT_IN_BLOCK first since that usually implies ALREADY_USED
@@ -174,7 +174,7 @@
      * @return the matched node
      * @throws GraalInternalError is the named node doesn't exist.
      */
-    public ValueNode namedNode(String name) {
+    public Node namedNode(String name) {
         if (namedNodes != null) {
             NamedNode value = namedNodes.get(name);
             if (value != null) {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchPattern.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchPattern.java	Tue Mar 17 12:05:51 2015 +0100
@@ -25,7 +25,6 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
 
 /**
  * A simple recursive pattern matcher for a DAG of nodes.
@@ -50,11 +49,11 @@
     static class Result {
         final MatchResultCode code;
 
-        final ValueNode node;
+        final Node node;
 
         final MatchPattern matcher;
 
-        Result(MatchResultCode result, ValueNode node, MatchPattern matcher) {
+        Result(MatchResultCode result, Node node, MatchPattern matcher) {
             this.code = result;
             this.node = node;
             this.matcher = matcher;
@@ -75,32 +74,32 @@
         private static final Result CACHED_NOT_SAFE = new Result(MatchResultCode.NOT_SAFE, null, null);
         private static final Result CACHED_ALREADY_USED = new Result(MatchResultCode.ALREADY_USED, null, null);
 
-        static Result wrongClass(ValueNode node, MatchPattern matcher) {
+        static Result wrongClass(Node node, MatchPattern matcher) {
             MatchResult_WRONG_CLASS.increment();
             return Debug.isEnabled() ? new Result(MatchResultCode.WRONG_CLASS, node, matcher) : CACHED_WRONG_CLASS;
         }
 
-        static Result namedValueMismatch(ValueNode node, MatchPattern matcher) {
+        static Result namedValueMismatch(Node node, MatchPattern matcher) {
             MatchResult_NAMED_VALUE_MISMATCH.increment();
             return Debug.isEnabled() ? new Result(MatchResultCode.NAMED_VALUE_MISMATCH, node, matcher) : CACHED_NAMED_VALUE_MISMATCH;
         }
 
-        static Result tooManyUsers(ValueNode node, MatchPattern matcher) {
+        static Result tooManyUsers(Node node, MatchPattern matcher) {
             MatchResult_TOO_MANY_USERS.increment();
             return Debug.isEnabled() ? new Result(MatchResultCode.TOO_MANY_USERS, node, matcher) : CACHED_TOO_MANY_USERS;
         }
 
-        static Result notInBlock(ValueNode node, MatchPattern matcher) {
+        static Result notInBlock(Node node, MatchPattern matcher) {
             MatchResult_NOT_IN_BLOCK.increment();
             return Debug.isEnabled() ? new Result(MatchResultCode.NOT_IN_BLOCK, node, matcher) : CACHED_NOT_IN_BLOCK;
         }
 
-        static Result notSafe(ValueNode node, MatchPattern matcher) {
+        static Result notSafe(Node node, MatchPattern matcher) {
             MatchResult_NOT_SAFE.increment();
             return Debug.isEnabled() ? new Result(MatchResultCode.NOT_SAFE, node, matcher) : CACHED_NOT_SAFE;
         }
 
-        static Result alreadyUsed(ValueNode node, MatchPattern matcher) {
+        static Result alreadyUsed(Node node, MatchPattern matcher) {
             MatchResult_ALREADY_USED.increment();
             return Debug.isEnabled() ? new Result(MatchResultCode.ALREADY_USED, node, matcher) : CACHED_ALREADY_USED;
         }
@@ -121,7 +120,7 @@
     /**
      * The expected type of the node. It must match exactly.
      */
-    private final Class<? extends ValueNode> nodeClass;
+    private final Class<? extends Node> nodeClass;
 
     /**
      * An optional name for this node. A name can occur multiple times in a match and that name must
@@ -151,7 +150,7 @@
         this(null, name, singleUser);
     }
 
-    public MatchPattern(Class<? extends ValueNode> nodeClass, String name, boolean singleUser) {
+    public MatchPattern(Class<? extends Node> nodeClass, String name, boolean singleUser) {
         this.nodeClass = nodeClass;
         this.name = name;
         this.singleUser = singleUser;
@@ -159,7 +158,7 @@
         this.inputs = null;
     }
 
-    private MatchPattern(Class<? extends ValueNode> nodeClass, String name, boolean singleUser, MatchPattern[] patterns, Position[] inputs) {
+    private MatchPattern(Class<? extends Node> nodeClass, String name, boolean singleUser, MatchPattern[] patterns, Position[] inputs) {
         assert inputs == null || inputs.length == patterns.length;
         this.nodeClass = nodeClass;
         this.name = name;
@@ -168,23 +167,23 @@
         this.inputs = inputs;
     }
 
-    public MatchPattern(Class<? extends ValueNode> nodeClass, String name, MatchPattern first, Position[] inputs, boolean singleUser) {
+    public MatchPattern(Class<? extends Node> nodeClass, String name, MatchPattern first, Position[] inputs, boolean singleUser) {
         this(nodeClass, name, singleUser, new MatchPattern[]{first}, inputs);
     }
 
-    public MatchPattern(Class<? extends ValueNode> nodeClass, String name, MatchPattern first, MatchPattern second, Position[] inputs, boolean singleUser) {
+    public MatchPattern(Class<? extends Node> nodeClass, String name, MatchPattern first, MatchPattern second, Position[] inputs, boolean singleUser) {
         this(nodeClass, name, singleUser, new MatchPattern[]{first, second}, inputs);
     }
 
-    public MatchPattern(Class<? extends ValueNode> nodeClass, String name, MatchPattern first, MatchPattern second, MatchPattern third, Position[] inputs, boolean singleUser) {
+    public MatchPattern(Class<? extends Node> nodeClass, String name, MatchPattern first, MatchPattern second, MatchPattern third, Position[] inputs, boolean singleUser) {
         this(nodeClass, name, singleUser, new MatchPattern[]{first, second, third}, inputs);
     }
 
-    Class<? extends ValueNode> nodeClass() {
+    Class<? extends Node> nodeClass() {
         return nodeClass;
     }
 
-    private Result matchType(ValueNode node) {
+    private Result matchType(Node node) {
         if (nodeClass != null && node.getClass() != nodeClass) {
             return Result.wrongClass(node, this);
         }
@@ -198,7 +197,7 @@
      * @param context
      * @return Result.OK is the pattern can be safely matched.
      */
-    Result matchUsage(ValueNode node, MatchContext context) {
+    Result matchUsage(Node node, MatchContext context) {
         Result result = matchUsage(node, context, true);
         if (result == Result.OK) {
             result = context.validate();
@@ -206,7 +205,7 @@
         return result;
     }
 
-    private Result matchUsage(ValueNode node, MatchContext context, boolean atRoot) {
+    private Result matchUsage(Node node, MatchContext context, boolean atRoot) {
         Result result = matchType(node);
         if (result != Result.OK) {
             return result;
@@ -240,11 +239,11 @@
      * @param statement
      * @return Result.OK if the shape of the pattern matches.
      */
-    public Result matchShape(ValueNode node, MatchStatement statement) {
+    public Result matchShape(Node node, MatchStatement statement) {
         return matchShape(node, statement, true);
     }
 
-    private Result matchShape(ValueNode node, MatchStatement statement, boolean atRoot) {
+    private Result matchShape(Node node, MatchStatement statement, boolean atRoot) {
         Result result = matchType(node);
         if (result != Result.OK) {
             return result;
@@ -271,7 +270,7 @@
      * rule. It's assumed that a match has already succeeded against this rule, otherwise the
      * printing may produce exceptions.
      */
-    public String formatMatch(ValueNode root) {
+    public String formatMatch(Node root) {
         String result = String.format("%s", root);
         if (patterns.length == 0) {
             return result;
@@ -288,8 +287,8 @@
         }
     }
 
-    private ValueNode getInput(int index, ValueNode node) {
-        return (ValueNode) inputs[index].get(node);
+    private Node getInput(int index, Node node) {
+        return inputs[index].get(node);
     }
 
     @Override
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java	Tue Mar 17 12:05:51 2015 +0100
@@ -32,7 +32,6 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
 
 public class MatchRuleRegistry {
 
@@ -45,7 +44,7 @@
      * @param names
      * @return an array of Position objects corresponding to the named fields.
      */
-    public static Position[] findPositions(NodeClass<? extends ValueNode> nodeClass, String[] names) {
+    public static Position[] findPositions(NodeClass<? extends Node> nodeClass, String[] names) {
         Position[] result = new Position[names.length];
         for (int i = 0; i < names.length; i++) {
             Edges edges = nodeClass.getInputEdges();
@@ -61,7 +60,7 @@
         return result;
     }
 
-    private static final HashMap<Class<? extends NodeLIRBuilder>, Map<Class<? extends ValueNode>, List<MatchStatement>>> registry = new HashMap<>();
+    private static final HashMap<Class<? extends NodeLIRBuilder>, Map<Class<? extends Node>, List<MatchStatement>>> registry = new HashMap<>();
 
     /**
      * Collect all the {@link MatchStatement}s defined by the superclass chain of theClass.
@@ -69,11 +68,11 @@
      * @param theClass
      * @return the set of {@link MatchStatement}s applicable to theClass.
      */
-    public static synchronized Map<Class<? extends ValueNode>, List<MatchStatement>> lookup(Class<? extends NodeLIRBuilder> theClass) {
-        Map<Class<? extends ValueNode>, List<MatchStatement>> result = registry.get(theClass);
+    public static synchronized Map<Class<? extends Node>, List<MatchStatement>> lookup(Class<? extends NodeLIRBuilder> theClass) {
+        Map<Class<? extends Node>, List<MatchStatement>> result = registry.get(theClass);
 
         if (result == null) {
-            Map<Class<? extends ValueNode>, List<MatchStatement>> rules = createRules(theClass);
+            Map<Class<? extends Node>, List<MatchStatement>> rules = createRules(theClass);
             registry.put(theClass, rules);
             assert registry.get(theClass) == rules;
             result = rules;
@@ -81,7 +80,7 @@
             if (LogVerbose.getValue()) {
                 try (Scope s = Debug.scope("MatchComplexExpressions")) {
                     Debug.log("Match rules for %s", theClass.getSimpleName());
-                    for (Entry<Class<? extends ValueNode>, List<MatchStatement>> entry : result.entrySet()) {
+                    for (Entry<Class<? extends Node>, List<MatchStatement>> entry : result.entrySet()) {
                         Debug.log("  For node class: %s", entry.getKey());
                         for (MatchStatement statement : entry.getValue()) {
                             Debug.log("    %s", statement.getPattern());
@@ -101,7 +100,7 @@
      * This is a separate, public method so that external clients can create rules with a custom
      * lookup and without the default caching behavior.
      */
-    public static Map<Class<? extends ValueNode>, List<MatchStatement>> createRules(Class<? extends NodeLIRBuilder> theClass) {
+    public static Map<Class<? extends Node>, List<MatchStatement>> createRules(Class<? extends NodeLIRBuilder> theClass) {
         HashMap<Class<? extends NodeLIRBuilder>, MatchStatementSet> matchSets = new HashMap<>();
         Iterable<MatchStatementSet> sl = Services.load(MatchStatementSet.class);
         for (MatchStatementSet rules : sl) {
@@ -110,14 +109,14 @@
 
         // Walk the class hierarchy collecting lists and merge them together. The subclass
         // rules are first which gives them preference over earlier rules.
-        Map<Class<? extends ValueNode>, List<MatchStatement>> rules = new HashMap<>();
+        Map<Class<? extends Node>, List<MatchStatement>> rules = new HashMap<>();
         Class<?> currentClass = theClass;
         do {
             MatchStatementSet matchSet = matchSets.get(currentClass);
             if (matchSet != null) {
                 List<MatchStatement> statements = matchSet.statements();
                 for (MatchStatement statement : statements) {
-                    Class<? extends ValueNode> nodeClass = statement.getPattern().nodeClass();
+                    Class<? extends Node> nodeClass = statement.getPattern().nodeClass();
                     List<MatchStatement> current = rules.get(nodeClass);
                     if (current == null) {
                         current = new ArrayList<>();
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatement.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatement.java	Tue Mar 17 12:05:51 2015 +0100
@@ -33,11 +33,10 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
 
 /**
  * A named {@link MatchPattern} along with a {@link MatchGenerator} that can be evaluated to replace
- * one or more {@link ValueNode}s with a single {@link Value}.
+ * one or more {@link Node}s with a single {@link Value}.
  */
 
 public class MatchStatement {
@@ -80,7 +79,7 @@
      * @return true if the statement matched something and set a {@link ComplexMatchResult} to be
      *         evaluated by the NodeLIRBuilder.
      */
-    public boolean generate(NodeLIRBuilder builder, int index, ValueNode node, List<ValueNode> nodes) {
+    public boolean generate(NodeLIRBuilder builder, int index, Node node, List<Node> nodes) {
         assert index == nodes.indexOf(node);
         // Check that the basic shape matches
         Result result = pattern.matchShape(node, this);
@@ -115,8 +114,7 @@
 
     /**
      * @param context
-     * @return the ValueNodes captured by the match rule in the order expected by the
-     *         generatorMethod
+     * @return the Nodes captured by the match rule in the order expected by the generatorMethod
      */
     private Object[] buildArgList(MatchContext context) {
         Object[] result = new Object[arguments.length];
@@ -133,7 +131,7 @@
         return result;
     }
 
-    public String formatMatch(ValueNode root) {
+    public String formatMatch(Node root) {
         return pattern.formatMatch(root);
     }
 
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Edges.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Edges.java	Tue Mar 17 12:05:51 2015 +0100
@@ -528,22 +528,56 @@
             }
             index++;
         }
-        int count = getCount();
+        int count = curOffsets.length;
         while (index < count) {
             NodeList<Node> list = getNodeList(node, curOffsets, index);
-            if (list != null) {
-                for (int i = 0; i < list.size(); ++i) {
-                    Node curNode = list.get(i);
-                    if (curNode != null) {
-                        consumer.accept(node, curNode);
-                    }
+            acceptHelper(node, consumer, list);
+            index++;
+        }
+    }
+
+    private static void acceptHelper(Node node, BiConsumer<Node, Node> consumer, NodeList<Node> list) {
+        if (list != null) {
+            for (int i = 0; i < list.size(); ++i) {
+                Node curNode = list.get(i);
+                if (curNode != null) {
+                    consumer.accept(node, curNode);
                 }
             }
-            index++;
         }
     }
 
     public long[] getOffsets() {
         return this.offsets;
     }
+
+    public void pushAll(Node node, NodeStack stack) {
+        int index = 0;
+        int curDirectCount = this.directCount;
+        final long[] curOffsets = this.offsets;
+        while (index < curDirectCount) {
+            Node curNode = getNode(node, curOffsets, index);
+            if (curNode != null) {
+                stack.push(curNode);
+            }
+            index++;
+        }
+        int count = curOffsets.length;
+        while (index < count) {
+            NodeList<Node> list = getNodeList(node, curOffsets, index);
+            pushAllHelper(stack, list);
+            index++;
+        }
+    }
+
+    private static void pushAllHelper(NodeStack stack, NodeList<Node> list) {
+        if (list != null) {
+            for (int i = 0; i < list.size(); ++i) {
+                Node curNode = list.get(i);
+                if (curNode != null) {
+                    stack.push(curNode);
+                }
+            }
+        }
+    }
 }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Tue Mar 17 12:05:51 2015 +0100
@@ -884,18 +884,22 @@
         if (condition) {
             return true;
         } else {
-            throw new VerificationError(message, args).addContext(this);
+            throw fail(message, args);
         }
     }
 
     public boolean assertFalse(boolean condition, String message, Object... args) {
         if (condition) {
-            throw new VerificationError(message, args).addContext(this);
+            throw fail(message, args);
         } else {
             return true;
         }
     }
 
+    protected VerificationError fail(String message, Object... args) throws GraalGraphInternalError {
+        throw new VerificationError(message, args).addContext(this);
+    }
+
     public Iterable<? extends Node> cfgPredecessors() {
         if (predecessor == null) {
             return Collections.emptySet();
@@ -1070,4 +1074,8 @@
     public boolean valueEquals(Node other) {
         return getNodeClass().dataEquals(this, other);
     }
+
+    public final void pushInputs(NodeStack stack) {
+        getNodeClass().getInputEdges().pushAll(this, stack);
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeStack.java	Tue Mar 17 12:05:51 2015 +0100
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2015, 2015, 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.graph;
+
+public class NodeStack {
+
+    private static final int INITIAL_SIZE = 8;
+
+    protected Node[] values;
+    protected int tos;
+
+    public NodeStack() {
+        values = new Node[INITIAL_SIZE];
+    }
+
+    public void push(Node n) {
+        int newIndex = tos++;
+        int valuesLength = values.length;
+        if (newIndex >= valuesLength) {
+            Node[] newValues = new Node[valuesLength << 1];
+            System.arraycopy(values, 0, newValues, 0, valuesLength);
+            values = newValues;
+        }
+        values[newIndex] = n;
+    }
+
+    public Node pop() {
+        assert tos > 0 : "stack must be non-empty";
+        return values[--tos];
+    }
+
+    public Node peek() {
+        assert tos > 0 : "stack must be non-empty";
+        return values[tos - 1];
+    }
+
+    public boolean isEmpty() {
+        return tos == 0;
+    }
+}
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Tue Mar 17 12:05:51 2015 +0100
@@ -333,7 +333,7 @@
                 return new AMD64RawNativeCallNode(returnType, functionPointer, args);
             }
         };
-        Backend backend = HotSpotGraalRuntime.runtime().getBackend(AMD64.class);
+        Backend backend = HotSpotGraalRuntime.runtime().getHostBackend();
         return new HotSpotNativeFunctionInterface(HotSpotGraalRuntime.runtime().getHostProviders(), factory, backend, config.dllLoad, config.dllLookup, config.rtldDefault);
     }
 
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCompare.java	Tue Mar 17 12:05:11 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,148 +0,0 @@
-/*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.amd64;
-
-import static com.oracle.graal.api.code.ValueUtil.*;
-import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
-
-import com.oracle.graal.hotspot.HotSpotGraalRuntime;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.asm.*;
-import com.oracle.graal.asm.amd64.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.amd64.*;
-import com.oracle.graal.lir.amd64.AMD64Move.MemOp;
-import com.oracle.graal.lir.asm.*;
-
-public class AMD64HotSpotCompare {
-
-    @Opcode("CMP")
-    public static final class HotSpotCompareConstantOp extends AMD64LIRInstruction {
-        public static final LIRInstructionClass<HotSpotCompareConstantOp> TYPE = LIRInstructionClass.create(HotSpotCompareConstantOp.class);
-
-        @Use({REG}) protected AllocatableValue x;
-        protected JavaConstant y;
-
-        public HotSpotCompareConstantOp(AllocatableValue x, JavaConstant y) {
-            super(TYPE);
-            this.x = x;
-            this.y = y;
-        }
-
-        @Override
-        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-            assert isRegister(x);
-            if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(y)) {
-                // compressed null
-                masm.testl(asRegister(x), asRegister(x));
-            } else if (y instanceof HotSpotObjectConstant) {
-                HotSpotObjectConstant yConst = (HotSpotObjectConstant) y;
-                if (yConst.isCompressed()) {
-                    // compressed oop
-                    crb.recordInlineDataInCode(y);
-                    masm.cmpl(asRegister(x), 0xDEADDEAD);
-                } else {
-                    // uncompressed oop
-                    AMD64Address patch = (AMD64Address) crb.recordDataReferenceInCode(y, 8);
-                    masm.cmpq(asRegister(x), patch);
-                }
-            } else if (y instanceof HotSpotMetaspaceConstant) {
-                boolean isImmutable = GraalOptions.ImmutableCode.getValue();
-                boolean generatePIC = GraalOptions.GeneratePIC.getValue();
-                if (y.getKind() == Kind.Int) {
-                    // compressed metaspace pointer
-                    crb.recordInlineDataInCode(y);
-                    if (isImmutable && generatePIC) {
-                        Kind hostWordKind = HotSpotGraalRuntime.getHostWordKind();
-                        int alignment = hostWordKind.getBitCount() / Byte.SIZE;
-                        // recordDataReferenceInCode forces the mov to be rip-relative
-                        masm.cmpl(asRegister(x), (AMD64Address) crb.recordDataReferenceInCode(JavaConstant.INT_0, alignment));
-                    } else {
-                        masm.cmpl(asRegister(x), y.asInt());
-                    }
-                } else {
-                    // uncompressed metaspace pointer
-                    if (isImmutable && generatePIC) {
-                        crb.recordInlineDataInCode(y);
-                        Kind hostWordKind = HotSpotGraalRuntime.getHostWordKind();
-                        int alignment = hostWordKind.getBitCount() / Byte.SIZE;
-                        // recordDataReferenceInCode forces the mov to be rip-relative
-                        masm.cmpq(asRegister(x), (AMD64Address) crb.recordDataReferenceInCode(JavaConstant.INT_0, alignment));
-                    } else {
-                        AMD64Address patch = (AMD64Address) crb.recordDataReferenceInCode(y, 8);
-                        masm.cmpq(asRegister(x), patch);
-                    }
-                }
-            } else {
-                throw GraalInternalError.shouldNotReachHere();
-            }
-        }
-    }
-
-    @Opcode("CMP")
-    public static final class HotSpotCompareMemoryConstantOp extends MemOp {
-        public static final LIRInstructionClass<HotSpotCompareMemoryConstantOp> TYPE = LIRInstructionClass.create(HotSpotCompareMemoryConstantOp.class);
-
-        protected JavaConstant y;
-
-        public HotSpotCompareMemoryConstantOp(Kind kind, AMD64AddressValue x, JavaConstant y, LIRFrameState state) {
-            super(TYPE, kind, x, state);
-            this.y = y;
-        }
-
-        @Override
-        protected void emitMemAccess(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-            if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(y)) {
-                // compressed null
-                masm.cmpl(address.toAddress(), 0);
-            } else if (y instanceof HotSpotObjectConstant) {
-                HotSpotObjectConstant yConst = (HotSpotObjectConstant) y;
-                if (yConst.isCompressed() && crb.target.inlineObjects) {
-                    // compressed oop
-                    crb.recordInlineDataInCode(y);
-                    masm.cmpl(address.toAddress(), 0xDEADDEAD);
-                } else {
-                    // uncompressed oop
-                    throw GraalInternalError.shouldNotReachHere();
-                }
-            } else if (y instanceof HotSpotMetaspaceConstant) {
-                if (y.getKind() == Kind.Int) {
-                    // compressed metaspace pointer
-                    crb.recordInlineDataInCode(y);
-                    masm.cmpl(address.toAddress(), y.asInt());
-                } else if (y.getKind() == Kind.Long && NumUtil.is32bit(y.asLong())) {
-                    // uncompressed metaspace pointer
-                    crb.recordInlineDataInCode(y);
-                    masm.cmpq(address.toAddress(), (int) y.asLong());
-                } else {
-                    throw GraalInternalError.shouldNotReachHere();
-                }
-            } else {
-                throw GraalInternalError.shouldNotReachHere();
-            }
-        }
-    }
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCompareConstOp.java	Tue Mar 17 12:05:51 2015 +0100
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.amd64;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MIOp;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.amd64.*;
+import com.oracle.graal.lir.asm.*;
+
+public class AMD64HotSpotCompareConstOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64HotSpotCompareConstOp> TYPE = LIRInstructionClass.create(AMD64HotSpotCompareConstOp.class);
+
+    @Opcode private final AMD64MIOp opcode;
+
+    @Use({REG, STACK}) protected AllocatableValue x;
+    protected HotSpotConstant y;
+
+    public AMD64HotSpotCompareConstOp(AMD64MIOp opcode, AllocatableValue x, HotSpotConstant y) {
+        super(TYPE);
+        this.opcode = opcode;
+        this.x = x;
+        this.y = y;
+
+        assert y.isCompressed();
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        int imm32;
+        if (y instanceof HotSpotMetaspaceConstant) {
+            imm32 = (int) ((HotSpotMetaspaceConstant) y).rawValue();
+        } else {
+            assert y instanceof HotSpotObjectConstant;
+            imm32 = 0xDEADDEAD;
+        }
+
+        crb.recordInlineDataInCode(y);
+        if (isRegister(x)) {
+            opcode.emit(masm, DWORD, asRegister(x), imm32);
+        } else {
+            assert isStackSlot(x);
+            opcode.emit(masm, DWORD, (AMD64Address) crb.asAddress(x), imm32);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCompareMemoryConstOp.java	Tue Mar 17 12:05:51 2015 +0100
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.amd64;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MIOp;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.ImplicitNullCheck;
+import com.oracle.graal.lir.amd64.*;
+import com.oracle.graal.lir.asm.*;
+
+public class AMD64HotSpotCompareMemoryConstOp extends AMD64LIRInstruction implements ImplicitNullCheck {
+    public static final LIRInstructionClass<AMD64HotSpotCompareMemoryConstOp> TYPE = LIRInstructionClass.create(AMD64HotSpotCompareMemoryConstOp.class);
+
+    @Opcode private final AMD64MIOp opcode;
+
+    @Use({COMPOSITE}) protected AMD64AddressValue x;
+    protected HotSpotConstant y;
+
+    @State protected LIRFrameState state;
+
+    public AMD64HotSpotCompareMemoryConstOp(AMD64MIOp opcode, AMD64AddressValue x, HotSpotConstant y, LIRFrameState state) {
+        super(TYPE);
+        this.opcode = opcode;
+        this.x = x;
+        this.y = y;
+        this.state = state;
+
+        assert y.isCompressed();
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        int imm32;
+        if (y instanceof HotSpotMetaspaceConstant) {
+            imm32 = (int) ((HotSpotMetaspaceConstant) y).rawValue();
+        } else {
+            assert y instanceof HotSpotObjectConstant;
+            imm32 = 0xDEADDEAD;
+        }
+
+        crb.recordInlineDataInCode(y);
+        if (isRegister(x)) {
+            opcode.emit(masm, DWORD, asRegister(x), imm32);
+        } else {
+            assert isStackSlot(x);
+            opcode.emit(masm, DWORD, (AMD64Address) crb.asAddress(x), imm32);
+        }
+    }
+
+    public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) {
+        if (state == null && x.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) {
+            state = nullCheckState;
+            return true;
+        }
+        return false;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotComparePatchOp.java	Tue Mar 17 12:05:51 2015 +0100
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.amd64;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp;
+import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.amd64.*;
+import com.oracle.graal.lir.asm.*;
+
+public class AMD64HotSpotComparePatchOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64HotSpotComparePatchOp> TYPE = LIRInstructionClass.create(AMD64HotSpotComparePatchOp.class);
+
+    @Opcode private final AMD64RMOp opcode;
+    private final OperandSize size;
+
+    @Use({REG}) protected AllocatableValue x;
+    protected HotSpotConstant y;
+
+    public AMD64HotSpotComparePatchOp(AMD64RMOp opcode, OperandSize size, AllocatableValue x, HotSpotConstant y) {
+        super(TYPE);
+        this.opcode = opcode;
+        this.size = size;
+
+        this.x = x;
+        this.y = y;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        AMD64Address addr = (AMD64Address) crb.recordDataReferenceInCode(y, size.getBytes());
+        opcode.emit(masm, size, asRegister(x), addr);
+    }
+}
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java	Tue Mar 17 12:05:51 2015 +0100
@@ -59,8 +59,8 @@
         RegisterValue exception = rax.asValue(LIRKind.reference(Kind.Object));
         RegisterValue exceptionPc = rdx.asValue(LIRKind.value(word));
         CallingConvention exceptionCc = new CallingConvention(0, ILLEGAL, exception, exceptionPc);
-        register(new HotSpotForeignCallLinkageImpl(EXCEPTION_HANDLER, 0L, PRESERVES_REGISTERS, LEAF_NOFP, null, exceptionCc, NOT_REEXECUTABLE, ANY_LOCATION));
-        register(new HotSpotForeignCallLinkageImpl(EXCEPTION_HANDLER_IN_CALLER, JUMP_ADDRESS, PRESERVES_REGISTERS, LEAF_NOFP, exceptionCc, null, NOT_REEXECUTABLE, ANY_LOCATION));
+        register(new HotSpotForeignCallLinkageImpl(EXCEPTION_HANDLER, 0L, PRESERVES_REGISTERS, LEAF_NOFP, null, exceptionCc, NOT_REEXECUTABLE, any()));
+        register(new HotSpotForeignCallLinkageImpl(EXCEPTION_HANDLER_IN_CALLER, JUMP_ADDRESS, PRESERVES_REGISTERS, LEAF_NOFP, exceptionCc, null, NOT_REEXECUTABLE, any()));
 
         if (PreferGraalStubs.getValue()) {
             link(new AMD64DeoptimizationStub(providers, target, config, registerStubCall(DEOPTIMIZATION_HANDLER, REEXECUTABLE, LEAF, NO_LOCATIONS)));
@@ -69,7 +69,7 @@
 
         if (config.useCRC32Intrinsics) {
             // This stub does callee saving
-            registerForeignCall(UPDATE_BYTES_CRC32, config.updateBytesCRC32Stub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, ANY_LOCATION);
+            registerForeignCall(UPDATE_BYTES_CRC32, config.updateBytesCRC32Stub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, any());
         }
 
         super.initialize(providers, config);
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Tue Mar 17 12:05:51 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,6 +24,9 @@
 
 import static com.oracle.graal.amd64.AMD64.*;
 import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.*;
+import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp.*;
+import static com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize.*;
 import static com.oracle.graal.hotspot.HotSpotBackend.*;
 
 import java.util.*;
@@ -31,6 +34,7 @@
 import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
 import com.oracle.graal.compiler.amd64.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
@@ -120,11 +124,12 @@
     List<AMD64HotSpotEpilogueOp> epilogueOps = new ArrayList<>(2);
 
     @Override
-    public void append(LIRInstruction op) {
-        super.append(op);
+    public <I extends LIRInstruction> I append(I op) {
+        I ret = super.append(op);
         if (op instanceof AMD64HotSpotEpilogueOp) {
             epilogueOps.add((AMD64HotSpotEpilogueOp) op);
         }
+        return ret;
     }
 
     @Override
@@ -579,19 +584,35 @@
 
     @Override
     protected void emitCompareOp(PlatformKind cmpKind, Variable left, Value right) {
-        if (right instanceof HotSpotConstant) {
-            append(new AMD64HotSpotCompare.HotSpotCompareConstantOp(left, (JavaConstant) right));
+        if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(right)) {
+            append(new AMD64CompareOp(TEST, DWORD, left, left));
+        } else if (right instanceof HotSpotConstant) {
+            HotSpotConstant c = (HotSpotConstant) right;
+
+            boolean isImmutable = GraalOptions.ImmutableCode.getValue();
+            boolean generatePIC = GraalOptions.GeneratePIC.getValue();
+            if (c.isCompressed() && !(isImmutable && generatePIC)) {
+                append(new AMD64HotSpotCompareConstOp(CMP.getMIOpcode(DWORD, false), left, c));
+            } else {
+                OperandSize size = c.isCompressed() ? DWORD : QWORD;
+                append(new AMD64HotSpotComparePatchOp(CMP.getRMOpcode(size), size, left, c));
+            }
         } else {
             super.emitCompareOp(cmpKind, left, right);
         }
     }
 
     @Override
-    protected void emitCompareMemoryConOp(Kind kind, AMD64AddressValue address, JavaConstant value, LIRFrameState state) {
-        if (value instanceof HotSpotConstant) {
-            append(new AMD64HotSpotCompare.HotSpotCompareMemoryConstantOp(kind, address, value, state));
+    protected boolean emitCompareMemoryConOp(OperandSize size, JavaConstant a, AMD64AddressValue b, LIRFrameState state) {
+        if (a.isNull()) {
+            append(new AMD64CompareMemoryConstOp(CMP.getMIOpcode(size, true), size, b, PrimitiveConstant.INT_0, state));
+            return true;
+        } else if (a instanceof HotSpotConstant && size == DWORD) {
+            assert ((HotSpotConstant) a).isCompressed();
+            append(new AMD64HotSpotCompareMemoryConstOp(CMP.getMIOpcode(size, false), b, (HotSpotConstant) a, state));
+            return true;
         } else {
-            super.emitCompareMemoryConOp(kind, address, value, state);
+            return super.emitCompareMemoryConOp(size, a, b, state);
         }
     }
 
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java	Tue Mar 17 12:05:51 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,12 +24,14 @@
 
 import static com.oracle.graal.amd64.AMD64.*;
 import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.*;
 import static com.oracle.graal.hotspot.HotSpotBackend.*;
 
 import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.*;
+import com.oracle.graal.asm.amd64.AMD64Assembler.*;
 import com.oracle.graal.compiler.amd64.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
@@ -270,27 +272,78 @@
         return null;
     }
 
+    private ComplexMatchResult binaryReadCompressed(AMD64RMOp op, OperandSize size, ValueNode value, Access access, CompressionNode compress, ConstantLocationNode location) {
+        if (canFormCompressedMemory(compress, location)) {
+            return builder -> getLIRGeneratorTool().emitBinaryMemory(op, size, getLIRGeneratorTool().asAllocatable(operand(value)), makeCompressedAddress(compress, location), getState(access));
+        } else {
+            return null;
+        }
+    }
+
     @MatchRule("(Add value (Read=access (Compression=compress object) ConstantLocation=location))")
+    @MatchRule("(Add value (FloatingRead=access (Compression=compress object) ConstantLocation=location))")
+    public ComplexMatchResult addMemoryCompressed(ValueNode value, Access access, CompressionNode compress, ConstantLocationNode location) {
+        OperandSize size = getMemorySize(access);
+        if (size.isXmmType()) {
+            return binaryReadCompressed(SSEOp.ADD, size, value, access, compress, location);
+        } else {
+            return binaryReadCompressed(ADD.getRMOpcode(size), size, value, access, compress, location);
+        }
+    }
+
     @MatchRule("(Sub value (Read=access (Compression=compress object) ConstantLocation=location))")
+    @MatchRule("(Sub value (FloatingRead=access (Compression=compress object) ConstantLocation=location))")
+    public ComplexMatchResult subMemoryCompressed(ValueNode value, Access access, CompressionNode compress, ConstantLocationNode location) {
+        OperandSize size = getMemorySize(access);
+        if (size.isXmmType()) {
+            return binaryReadCompressed(SSEOp.SUB, size, value, access, compress, location);
+        } else {
+            return binaryReadCompressed(SUB.getRMOpcode(size), size, value, access, compress, location);
+        }
+    }
+
     @MatchRule("(Mul value (Read=access (Compression=compress object) ConstantLocation=location))")
+    @MatchRule("(Mul value (FloatingRead=access (Compression=compress object) ConstantLocation=location))")
+    public ComplexMatchResult mulMemoryCompressed(ValueNode value, Access access, CompressionNode compress, ConstantLocationNode location) {
+        OperandSize size = getMemorySize(access);
+        if (size.isXmmType()) {
+            return binaryReadCompressed(SSEOp.MUL, size, value, access, compress, location);
+        } else {
+            return binaryReadCompressed(AMD64RMOp.IMUL, size, value, access, compress, location);
+        }
+    }
+
+    @MatchRule("(And value (Read=access (Compression=compress object) ConstantLocation=location))")
+    @MatchRule("(And value (FloatingRead=access (Compression=compress object) ConstantLocation=location))")
+    public ComplexMatchResult andMemoryCompressed(ValueNode value, Access access, CompressionNode compress, ConstantLocationNode location) {
+        OperandSize size = getMemorySize(access);
+        if (size.isXmmType()) {
+            return null;
+        } else {
+            return binaryReadCompressed(AND.getRMOpcode(size), size, value, access, compress, location);
+        }
+    }
+
     @MatchRule("(Or value (Read=access (Compression=compress object) ConstantLocation=location))")
+    @MatchRule("(Or value (FloatingRead=access (Compression=compress object) ConstantLocation=location))")
+    public ComplexMatchResult orMemoryCompressed(ValueNode value, Access access, CompressionNode compress, ConstantLocationNode location) {
+        OperandSize size = getMemorySize(access);
+        if (size.isXmmType()) {
+            return null;
+        } else {
+            return binaryReadCompressed(OR.getRMOpcode(size), size, value, access, compress, location);
+        }
+    }
+
     @MatchRule("(Xor value (Read=access (Compression=compress object) ConstantLocation=location))")
-    @MatchRule("(And value (Read=access (Compression=compress object) ConstantLocation=location))")
-    @MatchRule("(Add value (FloatingRead=access (Compression=compress object) ConstantLocation=location))")
-    @MatchRule("(Sub value (FloatingRead=access (Compression=compress object) ConstantLocation=location))")
-    @MatchRule("(Mul value (FloatingRead=access (Compression=compress object) ConstantLocation=location))")
-    @MatchRule("(Or value (FloatingRead=access (Compression=compress object) ConstantLocation=location))")
     @MatchRule("(Xor value (FloatingRead=access (Compression=compress object) ConstantLocation=location))")
-    @MatchRule("(And value (FloatingRead=access (Compression=compress object) ConstantLocation=location))")
-    public ComplexMatchResult binaryReadCompressed(BinaryNode root, ValueNode value, Access access, CompressionNode compress, ConstantLocationNode location) {
-        if (canFormCompressedMemory(compress, location)) {
-            AMD64Arithmetic op = getOp(root, access);
-            if (op != null) {
-                return builder -> getLIRGeneratorTool().emitBinaryMemory(op, getMemoryKind(access), getLIRGeneratorTool().asAllocatable(operand(value)), makeCompressedAddress(compress, location),
-                                getState(access));
-            }
+    public ComplexMatchResult xorMemoryCompressed(ValueNode value, Access access, CompressionNode compress, ConstantLocationNode location) {
+        OperandSize size = getMemorySize(access);
+        if (size.isXmmType()) {
+            return null;
+        } else {
+            return binaryReadCompressed(XOR.getRMOpcode(size), size, value, access, compress, location);
         }
-        return null;
     }
 
     @MatchRule("(Read (Compression=compress object) ConstantLocation=location)")
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotForeignCallsProvider.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotForeignCallsProvider.java	Tue Mar 17 12:05:51 2015 +0100
@@ -60,8 +60,8 @@
         RegisterValue incomingExceptionPc = i1.asValue(LIRKind.value(word));
         CallingConvention outgoingExceptionCc = new CallingConvention(0, ILLEGAL, outgoingException, outgoingExceptionPc);
         CallingConvention incomingExceptionCc = new CallingConvention(0, ILLEGAL, incomingException, incomingExceptionPc);
-        register(new HotSpotForeignCallLinkageImpl(EXCEPTION_HANDLER, 0L, PRESERVES_REGISTERS, LEAF_NOFP, outgoingExceptionCc, incomingExceptionCc, NOT_REEXECUTABLE, ANY_LOCATION));
-        register(new HotSpotForeignCallLinkageImpl(EXCEPTION_HANDLER_IN_CALLER, JUMP_ADDRESS, PRESERVES_REGISTERS, LEAF_NOFP, outgoingExceptionCc, incomingExceptionCc, NOT_REEXECUTABLE, ANY_LOCATION));
+        register(new HotSpotForeignCallLinkageImpl(EXCEPTION_HANDLER, 0L, PRESERVES_REGISTERS, LEAF_NOFP, outgoingExceptionCc, incomingExceptionCc, NOT_REEXECUTABLE, any()));
+        register(new HotSpotForeignCallLinkageImpl(EXCEPTION_HANDLER_IN_CALLER, JUMP_ADDRESS, PRESERVES_REGISTERS, LEAF_NOFP, outgoingExceptionCc, incomingExceptionCc, NOT_REEXECUTABLE, any()));
 
         if (PreferGraalStubs.getValue()) {
             link(new SPARCDeoptimizationStub(providers, target, registerStubCall(DEOPTIMIZATION_HANDLER, REEXECUTABLE, LEAF, NO_LOCATIONS)));
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotCryptoSubstitutionTest.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotCryptoSubstitutionTest.java	Tue Mar 17 12:05:51 2015 +0100
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.hotspot.test;
 
+import static com.oracle.graal.nodes.spi.Replacements.*;
+
 import java.io.*;
 import java.lang.reflect.*;
 import java.security.*;
@@ -58,6 +60,8 @@
 
     @Test
     public void testEncryptSubstitution() throws Exception {
+        Assume.assumeTrue(SELF_RECURSIVE_INTRINSICS_ENABLED);
+
         byte[] seed = {0x4, 0x7, 0x1, 0x1};
         SecureRandom random = new SecureRandom(seed);
         KeyGenerator aesKeyGen = KeyGenerator.getInstance("AES");
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierVerificationTest.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierVerificationTest.java	Tue Mar 17 12:05:51 2015 +0100
@@ -657,15 +657,13 @@
                     if (node instanceof WriteNode) {
                         WriteNode write = (WriteNode) node;
                         LocationIdentity obj = write.getLocationIdentity();
-                        if (obj instanceof ResolvedJavaField) {
-                            if (((ResolvedJavaField) obj).getName().equals("barrierIndex")) {
-                                /*
-                                 * A "barrierIndex" variable was found and is checked against the
-                                 * input barrier array.
-                                 */
-                                if (eliminateBarrier(write.value().asJavaConstant().asInt(), removedBarrierIndices)) {
-                                    return true;
-                                }
+                        if (obj.toString().equals("barrierIndex")) {
+                            /*
+                             * A "barrierIndex" variable was found and is checked against the input
+                             * barrier array.
+                             */
+                            if (eliminateBarrier(write.value().asJavaConstant().asInt(), removedBarrierIndices)) {
+                                return true;
                             }
                         }
                     } else if (node instanceof SerialWriteBarrier || node instanceof G1PostWriteBarrier) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java	Tue Mar 17 12:05:51 2015 +0100
@@ -119,17 +119,17 @@
     public static final ForeignCallDescriptor VM_ERROR = new ForeignCallDescriptor("vm_error", void.class, Object.class, Object.class, long.class);
 
     /**
-     * @see NewMultiArrayStubCall
+     * New multi array stub call.
      */
     public static final ForeignCallDescriptor NEW_MULTI_ARRAY = new ForeignCallDescriptor("new_multi_array", Object.class, Word.class, int.class, Word.class);
 
     /**
-     * @see NewArrayStubCall
+     * New array stub.
      */
     public static final ForeignCallDescriptor NEW_ARRAY = new ForeignCallDescriptor("new_array", Object.class, Word.class, int.class);
 
     /**
-     * @see NewInstanceStubCall
+     * New insstance stub.
      */
     public static final ForeignCallDescriptor NEW_INSTANCE = new ForeignCallDescriptor("new_instance", Object.class, Word.class);
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java	Tue Mar 17 12:05:51 2015 +0100
@@ -248,7 +248,7 @@
                     // compiled code entry as HotSpot does not guarantee they are final
                     // values.
                     int methodCompiledEntryOffset = runtime.getConfig().methodCompiledEntryOffset;
-                    ReadNode compiledEntry = graph.add(new ReadNode(metaspaceMethod, graph.unique(new ConstantLocationNode(ANY_LOCATION, methodCompiledEntryOffset)), StampFactory.forKind(wordKind),
+                    ReadNode compiledEntry = graph.add(new ReadNode(metaspaceMethod, graph.unique(new ConstantLocationNode(any(), methodCompiledEntryOffset)), StampFactory.forKind(wordKind),
                                     BarrierType.NONE));
 
                     loweredCallTarget = graph.add(new HotSpotIndirectCallTargetNode(metaspaceMethod, compiledEntry, parameters, invoke.asNode().stamp(), signature, callTarget.targetMethod(),
@@ -359,7 +359,7 @@
             for (OSRLocalNode osrLocal : graph.getNodes(OSRLocalNode.TYPE)) {
                 int size = osrLocal.getKind().getSlotCount();
                 int offset = localsOffset - (osrLocal.index() + size - 1) * 8;
-                IndexedLocationNode location = graph.unique(new IndexedLocationNode(ANY_LOCATION, offset, ConstantNode.forLong(0, graph), 1));
+                IndexedLocationNode location = graph.unique(new IndexedLocationNode(any(), offset, ConstantNode.forLong(0, graph), 1));
                 ReadNode load = graph.add(new ReadNode(buffer, location, osrLocal.stamp(), BarrierType.NONE));
                 osrLocal.replaceAndDelete(load);
                 graph.addBeforeFixed(migrationEnd, load);
@@ -444,7 +444,7 @@
         // We use LocationNode.ANY_LOCATION for the reads that access the vtable
         // entry as HotSpot does not guarantee that this is a final value.
         Stamp methodStamp = MethodPointerStamp.method();
-        ReadNode metaspaceMethod = graph.add(new ReadNode(hub, graph.unique(new ConstantLocationNode(ANY_LOCATION, vtableEntryOffset)), methodStamp, BarrierType.NONE));
+        ReadNode metaspaceMethod = graph.add(new ReadNode(hub, graph.unique(new ConstantLocationNode(any(), vtableEntryOffset)), methodStamp, BarrierType.NONE));
         return metaspaceMethod;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotCompressedNullConstant.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotCompressedNullConstant.java	Tue Mar 17 12:05:51 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2015, 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
@@ -43,6 +43,11 @@
     }
 
     @Override
+    public boolean isCompressed() {
+        return true;
+    }
+
+    @Override
     public boolean isDefaultForKind() {
         return true;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstant.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstant.java	Tue Mar 17 12:05:51 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2015, 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
@@ -28,4 +28,6 @@
  * Marker interface for hotspot specific constants.
  */
 public interface HotSpotConstant extends Constant {
+
+    boolean isCompressed();
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java	Tue Mar 17 12:05:51 2015 +0100
@@ -101,13 +101,17 @@
         Registration r = new Registration(plugins, metaAccess, System.class);
         r.register0("currentTimeMillis", new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) {
-                b.push(Kind.Long, b.append(new ForeignCallNode(foreignCalls, SystemSubstitutions.JAVA_TIME_MILLIS, StampFactory.forKind(Kind.Long))));
+                ForeignCallNode foreignCall = new ForeignCallNode(foreignCalls, SystemSubstitutions.JAVA_TIME_MILLIS, StampFactory.forKind(Kind.Long));
+                b.push(Kind.Long, b.append(foreignCall));
+                foreignCall.setStateAfter(b.createStateAfter());
                 return true;
             }
         });
         r.register0("nanoTime", new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) {
-                b.push(Kind.Long, b.append(new ForeignCallNode(foreignCalls, SystemSubstitutions.JAVA_TIME_NANOS, StampFactory.forKind(Kind.Long))));
+                ForeignCallNode foreignCall = new ForeignCallNode(foreignCalls, SystemSubstitutions.JAVA_TIME_NANOS, StampFactory.forKind(Kind.Long));
+                b.push(Kind.Long, b.append(foreignCall));
+                foreignCall.setStateAfter(b.createStateAfter());
                 return true;
             }
         });
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java	Tue Mar 17 12:05:51 2015 +0100
@@ -151,21 +151,21 @@
         registerForeignCall(ARITHMETIC_COS, c.arithmeticCosAddress, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS);
         registerForeignCall(ARITHMETIC_TAN, c.arithmeticTanAddress, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS);
         registerForeignCall(ARITHMETIC_POW, c.arithmeticPowAddress, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS);
-        registerForeignCall(LOAD_AND_CLEAR_EXCEPTION, c.loadAndClearExceptionAddress, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, ANY_LOCATION);
+        registerForeignCall(LOAD_AND_CLEAR_EXCEPTION, c.loadAndClearExceptionAddress, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, any());
 
-        registerForeignCall(EXCEPTION_HANDLER_FOR_PC, c.exceptionHandlerForPcAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, ANY_LOCATION);
-        registerForeignCall(EXCEPTION_HANDLER_FOR_RETURN_ADDRESS, c.exceptionHandlerForReturnAddressAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, ANY_LOCATION);
-        registerForeignCall(FETCH_UNROLL_INFO, c.deoptimizationFetchUnrollInfo, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, ANY_LOCATION);
-        registerForeignCall(NEW_ARRAY_C, c.newArrayAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, ANY_LOCATION);
-        registerForeignCall(NEW_INSTANCE_C, c.newInstanceAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, ANY_LOCATION);
-        registerForeignCall(UNCOMMON_TRAP, c.deoptimizationUncommonTrap, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, NOT_REEXECUTABLE, ANY_LOCATION);
+        registerForeignCall(EXCEPTION_HANDLER_FOR_PC, c.exceptionHandlerForPcAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, any());
+        registerForeignCall(EXCEPTION_HANDLER_FOR_RETURN_ADDRESS, c.exceptionHandlerForReturnAddressAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, any());
+        registerForeignCall(FETCH_UNROLL_INFO, c.deoptimizationFetchUnrollInfo, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, any());
+        registerForeignCall(NEW_ARRAY_C, c.newArrayAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, any());
+        registerForeignCall(NEW_INSTANCE_C, c.newInstanceAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, any());
+        registerForeignCall(UNCOMMON_TRAP, c.deoptimizationUncommonTrap, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, NOT_REEXECUTABLE, any());
 
         /*
          * We cannot use LEAF_SP here because on some architectures we have to align the stack
          * manually before calling into the VM. See {@link
          * AMD64HotSpotEnterUnpackFramesStackFrameOp#emitCode}.
          */
-        registerForeignCall(UNPACK_FRAMES, c.deoptimizationUnpackFrames, NativeCall, DESTROYS_REGISTERS, LEAF, NOT_REEXECUTABLE, ANY_LOCATION);
+        registerForeignCall(UNPACK_FRAMES, c.deoptimizationUnpackFrames, NativeCall, DESTROYS_REGISTERS, LEAF, NOT_REEXECUTABLE, any());
 
         /*
          * This message call is registered twice, where the second one must only be used for calls
@@ -174,32 +174,32 @@
         registerForeignCall(VM_MESSAGE_C, c.vmMessageAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, NO_LOCATIONS);
         registerForeignCall(ASSERTION_VM_MESSAGE_C, c.vmMessageAddress, NativeCall, PRESERVES_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS);
 
-        link(new NewInstanceStub(providers, registerStubCall(NEW_INSTANCE, REEXECUTABLE, NOT_LEAF, ANY_LOCATION)));
-        link(new NewArrayStub(providers, registerStubCall(NEW_ARRAY, REEXECUTABLE, NOT_LEAF, INIT_LOCATION)));
+        link(new NewInstanceStub(providers, registerStubCall(NEW_INSTANCE, REEXECUTABLE, NOT_LEAF, INIT_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION)));
+        link(new NewArrayStub(providers, registerStubCall(NEW_ARRAY, REEXECUTABLE, NOT_LEAF, INIT_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION)));
         link(new ExceptionHandlerStub(providers, foreignCalls.get(EXCEPTION_HANDLER)));
-        link(new UnwindExceptionToCallerStub(providers, registerStubCall(UNWIND_EXCEPTION_TO_CALLER, NOT_REEXECUTABLE, NOT_LEAF, ANY_LOCATION)));
+        link(new UnwindExceptionToCallerStub(providers, registerStubCall(UNWIND_EXCEPTION_TO_CALLER, NOT_REEXECUTABLE, NOT_LEAF, any())));
         link(new VerifyOopStub(providers, registerStubCall(VERIFY_OOP, REEXECUTABLE, LEAF_NOFP, NO_LOCATIONS)));
 
         linkForeignCall(providers, IDENTITY_HASHCODE, c.identityHashCodeAddress, PREPEND_THREAD, NOT_LEAF, NOT_REEXECUTABLE, MARK_WORD_LOCATION);
-        linkForeignCall(providers, REGISTER_FINALIZER, c.registerFinalizerAddress, PREPEND_THREAD, NOT_LEAF, NOT_REEXECUTABLE, ANY_LOCATION);
-        linkForeignCall(providers, CREATE_NULL_POINTER_EXCEPTION, c.createNullPointerExceptionAddress, PREPEND_THREAD, NOT_LEAF, REEXECUTABLE, ANY_LOCATION);
-        linkForeignCall(providers, CREATE_OUT_OF_BOUNDS_EXCEPTION, c.createOutOfBoundsExceptionAddress, PREPEND_THREAD, NOT_LEAF, REEXECUTABLE, ANY_LOCATION);
-        linkForeignCall(providers, MONITORENTER, c.monitorenterAddress, PREPEND_THREAD, NOT_LEAF, NOT_REEXECUTABLE, ANY_LOCATION);
-        linkForeignCall(providers, MONITOREXIT, c.monitorexitAddress, PREPEND_THREAD, LEAF_SP, NOT_REEXECUTABLE, ANY_LOCATION);
-        linkForeignCall(providers, NEW_MULTI_ARRAY, c.newMultiArrayAddress, PREPEND_THREAD, NOT_LEAF, REEXECUTABLE, INIT_LOCATION);
+        linkForeignCall(providers, REGISTER_FINALIZER, c.registerFinalizerAddress, PREPEND_THREAD, NOT_LEAF, NOT_REEXECUTABLE, any());
+        linkForeignCall(providers, CREATE_NULL_POINTER_EXCEPTION, c.createNullPointerExceptionAddress, PREPEND_THREAD, NOT_LEAF, REEXECUTABLE, any());
+        linkForeignCall(providers, CREATE_OUT_OF_BOUNDS_EXCEPTION, c.createOutOfBoundsExceptionAddress, PREPEND_THREAD, NOT_LEAF, REEXECUTABLE, any());
+        linkForeignCall(providers, MONITORENTER, c.monitorenterAddress, PREPEND_THREAD, NOT_LEAF, NOT_REEXECUTABLE, any());
+        linkForeignCall(providers, MONITOREXIT, c.monitorexitAddress, PREPEND_THREAD, LEAF_SP, NOT_REEXECUTABLE, any());
+        linkForeignCall(providers, NEW_MULTI_ARRAY, c.newMultiArrayAddress, PREPEND_THREAD, NOT_LEAF, REEXECUTABLE, INIT_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION);
         linkForeignCall(providers, DYNAMIC_NEW_ARRAY, c.dynamicNewArrayAddress, PREPEND_THREAD, NOT_LEAF, REEXECUTABLE, INIT_LOCATION);
         linkForeignCall(providers, DYNAMIC_NEW_INSTANCE, c.dynamicNewInstanceAddress, PREPEND_THREAD, NOT_LEAF, REEXECUTABLE, INIT_LOCATION);
         linkForeignCall(providers, LOG_PRINTF, c.logPrintfAddress, PREPEND_THREAD, LEAF, REEXECUTABLE, NO_LOCATIONS);
         linkForeignCall(providers, LOG_OBJECT, c.logObjectAddress, PREPEND_THREAD, LEAF, REEXECUTABLE, NO_LOCATIONS);
         linkForeignCall(providers, LOG_PRIMITIVE, c.logPrimitiveAddress, PREPEND_THREAD, LEAF, REEXECUTABLE, NO_LOCATIONS);
-        linkForeignCall(providers, THREAD_IS_INTERRUPTED, c.threadIsInterruptedAddress, PREPEND_THREAD, NOT_LEAF, NOT_REEXECUTABLE, ANY_LOCATION);
+        linkForeignCall(providers, THREAD_IS_INTERRUPTED, c.threadIsInterruptedAddress, PREPEND_THREAD, NOT_LEAF, NOT_REEXECUTABLE, any());
         linkForeignCall(providers, VM_ERROR, c.vmErrorAddress, PREPEND_THREAD, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS);
         linkForeignCall(providers, OSR_MIGRATION_END, c.osrMigrationEndAddress, DONT_PREPEND_THREAD, LEAF_NOFP, NOT_REEXECUTABLE, NO_LOCATIONS);
         linkForeignCall(providers, G1WBPRECALL, c.writeBarrierPreAddress, PREPEND_THREAD, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS);
         linkForeignCall(providers, G1WBPOSTCALL, c.writeBarrierPostAddress, PREPEND_THREAD, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS);
         linkForeignCall(providers, VALIDATE_OBJECT, c.validateObject, PREPEND_THREAD, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS);
 
-        linkForeignCall(providers, TEST_DEOPTIMIZE_CALL_INT, c.testDeoptimizeCallInt, PREPEND_THREAD, NOT_LEAF, NOT_REEXECUTABLE, ANY_LOCATION);
+        linkForeignCall(providers, TEST_DEOPTIMIZE_CALL_INT, c.testDeoptimizeCallInt, PREPEND_THREAD, NOT_LEAF, NOT_REEXECUTABLE, any());
 
         // sometimes the same function is used for different kinds of arraycopy so check for
         // duplicates using a map.
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInlineInvokePlugin.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInlineInvokePlugin.java	Tue Mar 17 12:05:51 2015 +0100
@@ -48,20 +48,22 @@
     public InlineInfo getInlineInfo(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType) {
         ResolvedJavaMethod subst = replacements.getMethodSubstitutionMethod(method);
         if (subst != null) {
-            // Forced inlining of intrinsics
-            return new InlineInfo(subst, true);
+            if (b.parsingReplacement() || InlineDuringParsing.getValue()) {
+                // Forced inlining of intrinsics
+                return new InlineInfo(subst, true, true);
+            }
         }
         if (b.parsingReplacement()) {
             assert nodeIntrinsification.getIntrinsic(method) == null && method.getAnnotation(Word.Operation.class) == null && method.getAnnotation(HotSpotOperation.class) == null &&
                             !nodeIntrinsification.isFoldable(method) : format("%s should have been handled by %s", method.format("%H.%n(%p)"), DefaultGenericInvocationPlugin.class.getName());
 
             // Force inlining when parsing replacements
-            return new InlineInfo(method, true);
+            return new InlineInfo(method, true, true);
         } else {
             assert nodeIntrinsification.getIntrinsic(method) == null : String.format("@%s method %s must only be called from within a replacement%n%s", NodeIntrinsic.class.getSimpleName(),
                             method.format("%h.%n"), b);
             if (InlineDuringParsing.getValue() && method.hasBytecodes() && method.getCode().length <= TrivialInliningSize.getValue() && b.getDepth() < InlineDuringParsingMaxDepth.getValue()) {
-                return new InlineInfo(method, false);
+                return new InlineInfo(method, false, false);
             }
         }
         return null;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMetaspaceConstant.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMetaspaceConstant.java	Tue Mar 17 12:05:51 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2015, 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
@@ -27,8 +27,6 @@
 
 public interface HotSpotMetaspaceConstant extends HotSpotConstant, VMConstant {
 
-    boolean isCompressed();
-
     Constant compress(CompressEncoding encoding);
 
     Constant uncompress(CompressEncoding encoding);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotObjectConstant.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotObjectConstant.java	Tue Mar 17 12:05:51 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2015, 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
@@ -38,8 +38,6 @@
 
     JavaConstant uncompress();
 
-    boolean isCompressed();
-
     /**
      * Gets the resolved Java type of the object represented by this constant.
      */
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaFieldImpl.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaFieldImpl.java	Tue Mar 17 12:05:51 2015 +0100
@@ -48,6 +48,39 @@
      * This value contains all flags as stored in the VM including internal ones.
      */
     private final int modifiers;
+    private final LocationIdentity locationIdentity = new FieldLocationIdentity(this);
+
+    public static class FieldLocationIdentity extends LocationIdentity {
+        HotSpotResolvedJavaFieldImpl inner;
+
+        public FieldLocationIdentity(HotSpotResolvedJavaFieldImpl inner) {
+            super(false);
+            this.inner = inner;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj instanceof FieldLocationIdentity) {
+                FieldLocationIdentity fieldLocationIdentity = (FieldLocationIdentity) obj;
+                return inner.equals(fieldLocationIdentity.inner);
+
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            return inner.hashCode();
+        }
+
+        @Override
+        public String toString() {
+            return inner.name;
+        }
+    }
 
     public HotSpotResolvedJavaFieldImpl(HotSpotResolvedObjectTypeImpl holder, String name, JavaType type, long offset, int modifiers) {
         this.holder = holder;
@@ -229,4 +262,8 @@
             }
         }
     }
+
+    public LocationIdentity getLocationIdentity() {
+        return locationIdentity;
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotWordOperationPlugin.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotWordOperationPlugin.java	Tue Mar 17 12:05:51 2015 +0100
@@ -114,7 +114,7 @@
                 Stamp readStamp = KlassPointerStamp.klass();
                 LocationNode location;
                 if (args.length == 2) {
-                    location = makeLocation(b, args[1], ANY_LOCATION);
+                    location = makeLocation(b, args[1], any());
                 } else {
                     location = makeLocation(b, args[1], args[2]);
                 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/HotSpotNativeFunctionInterface.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/HotSpotNativeFunctionInterface.java	Tue Mar 17 12:05:51 2015 +0100
@@ -57,6 +57,7 @@
     public HotSpotNativeFunctionInterface(HotSpotProviders providers, RawNativeCallNodeFactory factory, Backend backend, long dlopen, long dlsym, long rtldDefault) {
         this.rtldDefault = rtldDefault == HotSpotVMConfig.INVALID_RTLD_DEFAULT_HANDLE ? null : new HotSpotNativeLibraryHandle("RTLD_DEFAULT", rtldDefault);
         this.providers = providers;
+        assert backend != null;
         this.backend = backend;
         this.factory = factory;
         this.libraryLoadFunctionPointer = new HotSpotNativeFunctionPointer(dlopen, "os::dll_load");
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java	Tue Mar 17 12:05:51 2015 +0100
@@ -57,7 +57,7 @@
 
     @Override
     public LocationIdentity getLocationIdentity() {
-        return LocationIdentity.ANY_LOCATION;
+        return LocationIdentity.any();
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizationFetchUnrollInfoCallNode.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizationFetchUnrollInfoCallNode.java	Tue Mar 17 12:05:51 2015 +0100
@@ -40,7 +40,7 @@
  * A call to the runtime code {@code Deoptimization::fetch_unroll_info}.
  */
 @NodeInfo(allowedUsageTypes = {InputType.Memory})
-public final class DeoptimizationFetchUnrollInfoCallNode extends FixedWithNextNode implements LIRLowerable, MemoryCheckpoint.Multi {
+public final class DeoptimizationFetchUnrollInfoCallNode extends FixedWithNextNode implements LIRLowerable, MemoryCheckpoint.Single {
 
     public static final NodeClass<DeoptimizationFetchUnrollInfoCallNode> TYPE = NodeClass.create(DeoptimizationFetchUnrollInfoCallNode.class);
     @Input SaveAllRegistersNode registerSaver;
@@ -53,8 +53,8 @@
     }
 
     @Override
-    public LocationIdentity[] getLocationIdentities() {
-        return foreignCalls.getKilledLocations(FETCH_UNROLL_INFO);
+    public LocationIdentity getLocationIdentity() {
+        return LocationIdentity.any();
     }
 
     public SaveRegistersOp getSaveRegistersOp() {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EndLockScopeNode.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EndLockScopeNode.java	Tue Mar 17 12:05:51 2015 +0100
@@ -49,7 +49,7 @@
 
     @Override
     public LocationIdentity getLocationIdentity() {
-        return LocationIdentity.ANY_LOCATION;
+        return LocationIdentity.any();
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArrayStubCall.java	Tue Mar 17 12:05:11 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +0,0 @@
-/*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.nodes;
-
-import static com.oracle.graal.hotspot.HotSpotBackend.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.hotspot.stubs.*;
-import com.oracle.graal.hotspot.word.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-
-/**
- * A call to the {@link NewArrayStub}.
- */
-@NodeInfo
-public final class NewArrayStubCall extends DeoptimizingStubCall implements LIRLowerable {
-
-    public static final NodeClass<NewArrayStubCall> TYPE = NodeClass.create(NewArrayStubCall.class);
-    private static final Stamp defaultStamp = StampFactory.objectNonNull();
-
-    @Input ValueNode hub;
-    @Input ValueNode length;
-
-    public NewArrayStubCall(ValueNode hub, ValueNode length) {
-        super(TYPE, defaultStamp);
-        this.hub = hub;
-        this.length = length;
-    }
-
-    @Override
-    public boolean inferStamp() {
-        if (stamp() == defaultStamp && hub.isConstant()) {
-            updateStamp(StampFactory.exactNonNull(((HotSpotMetaspaceConstant) hub.asJavaConstant()).asResolvedJavaType()));
-            return true;
-        }
-        return false;
-    }
-
-    @Override
-    public void generate(NodeLIRBuilderTool gen) {
-        ForeignCallLinkage linkage = gen.getLIRGeneratorTool().getForeignCalls().lookupForeignCall(NEW_ARRAY);
-        Variable result = gen.getLIRGeneratorTool().emitForeignCall(linkage, gen.state(this), gen.operand(hub), gen.operand(length));
-        gen.setResult(this, result);
-    }
-
-    @NodeIntrinsic
-    public static native Object call(KlassPointer hub, int length);
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceStubCall.java	Tue Mar 17 12:05:11 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,72 +0,0 @@
-/*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.nodes;
-
-import static com.oracle.graal.hotspot.HotSpotBackend.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.hotspot.stubs.*;
-import com.oracle.graal.hotspot.word.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-
-/**
- * A call to the {@link NewInstanceStub}.
- */
-@NodeInfo
-public final class NewInstanceStubCall extends DeoptimizingStubCall implements LIRLowerable {
-
-    public static final NodeClass<NewInstanceStubCall> TYPE = NodeClass.create(NewInstanceStubCall.class);
-    private static final Stamp defaultStamp = StampFactory.objectNonNull();
-
-    @Input ValueNode hub;
-
-    public NewInstanceStubCall(ValueNode hub) {
-        super(TYPE, defaultStamp);
-        this.hub = hub;
-    }
-
-    @Override
-    public boolean inferStamp() {
-        if (stamp() == defaultStamp && hub.isConstant()) {
-            updateStamp(StampFactory.exactNonNull(((HotSpotMetaspaceConstant) hub.asJavaConstant()).asResolvedJavaType()));
-            return true;
-        }
-        return false;
-    }
-
-    @Override
-    public void generate(NodeLIRBuilderTool gen) {
-        ForeignCallLinkage linkage = gen.getLIRGeneratorTool().getForeignCalls().lookupForeignCall(NEW_INSTANCE);
-        Value result = gen.getLIRGeneratorTool().emitForeignCall(linkage, gen.state(this), gen.operand(hub));
-        gen.setResult(this, result);
-    }
-
-    @NodeIntrinsic
-    public static native Object call(KlassPointer hub);
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewMultiArrayStubCall.java	Tue Mar 17 12:05:11 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +0,0 @@
-/*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.nodes;
-
-import static com.oracle.graal.hotspot.HotSpotBackend.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.word.*;
-
-/**
- * Node implementing a call to {@code GraalRuntime::new_multi_array}.
- */
-@NodeInfo
-public final class NewMultiArrayStubCall extends ForeignCallNode {
-
-    public static final NodeClass<NewMultiArrayStubCall> TYPE = NodeClass.create(NewMultiArrayStubCall.class);
-    private static final Stamp defaultStamp = StampFactory.objectNonNull();
-
-    @Input ValueNode hub;
-    @Input ValueNode dims;
-    protected final int rank;
-
-    public NewMultiArrayStubCall(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ValueNode hub, int rank, ValueNode dims) {
-        super(TYPE, foreignCalls, NEW_MULTI_ARRAY, defaultStamp);
-        this.hub = hub;
-        this.rank = rank;
-        this.dims = dims;
-    }
-
-    @Override
-    public boolean inferStamp() {
-        if (stamp() == defaultStamp && hub.isConstant()) {
-            updateStamp(StampFactory.exactNonNull(((HotSpotMetaspaceConstant) hub.asJavaConstant()).asResolvedJavaType()));
-            return true;
-        }
-        return false;
-    }
-
-    @Override
-    protected Value[] operands(NodeLIRBuilderTool gen) {
-        return new Value[]{gen.operand(hub), JavaConstant.forInt(rank), gen.operand(dims)};
-    }
-
-    @NodeIntrinsic
-    public static native Object call(Word hub, @ConstantNodeParameter int rank, Word dims);
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SaveAllRegistersNode.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SaveAllRegistersNode.java	Tue Mar 17 12:05:51 2015 +0100
@@ -66,6 +66,6 @@
     public static native long saveAllRegisters();
 
     public LocationIdentity getLocationIdentity() {
-        return LocationIdentity.ANY_LOCATION;
+        return LocationIdentity.any();
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/UncommonTrapCallNode.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/UncommonTrapCallNode.java	Tue Mar 17 12:05:51 2015 +0100
@@ -40,7 +40,7 @@
  * A call to the runtime code implementing the uncommon trap logic.
  */
 @NodeInfo(allowedUsageTypes = {InputType.Memory})
-public final class UncommonTrapCallNode extends FixedWithNextNode implements LIRLowerable, MemoryCheckpoint.Multi {
+public final class UncommonTrapCallNode extends FixedWithNextNode implements LIRLowerable, MemoryCheckpoint.Single {
 
     public static final NodeClass<UncommonTrapCallNode> TYPE = NodeClass.create(UncommonTrapCallNode.class);
     @Input ValueNode trapRequest;
@@ -55,8 +55,8 @@
     }
 
     @Override
-    public LocationIdentity[] getLocationIdentities() {
-        return foreignCalls.getKilledLocations(UNCOMMON_TRAP);
+    public LocationIdentity getLocationIdentity() {
+        return LocationIdentity.any();
     }
 
     public SaveRegistersOp getSaveRegistersOp() {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AESCryptSubstitutions.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AESCryptSubstitutions.java	Tue Mar 17 12:05:51 2015 +0100
@@ -89,7 +89,7 @@
 
     private static void crypt(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset, boolean encrypt) {
         Object realReceiver = PiNode.piCastNonNull(rcvr, AESCryptClass);
-        Object kObject = UnsafeLoadNode.load(realReceiver, kOffset, Kind.Object, LocationIdentity.ANY_LOCATION);
+        Object kObject = UnsafeLoadNode.load(realReceiver, kOffset, Kind.Object, LocationIdentity.any());
         Word kAddr = fromWordBase(Word.fromObject(kObject).add(arrayBaseOffset(Kind.Byte)));
         Word inAddr = Word.unsigned(GetObjectAddressNode.get(in) + arrayBaseOffset(Kind.Byte) + inOffset);
         Word outAddr = Word.unsigned(GetObjectAddressNode.get(out) + arrayBaseOffset(Kind.Byte) + outOffset);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java	Tue Mar 17 12:05:51 2015 +0100
@@ -70,7 +70,7 @@
     @MethodSubstitution(isStatic = false)
     static int encrypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) {
         Object realReceiver = PiNode.piCastNonNull(rcvr, cipherBlockChainingClass);
-        Object embeddedCipher = UnsafeLoadNode.load(realReceiver, embeddedCipherOffset, Kind.Object, LocationIdentity.ANY_LOCATION);
+        Object embeddedCipher = UnsafeLoadNode.load(realReceiver, embeddedCipherOffset, Kind.Object, LocationIdentity.any());
         if (getAESCryptClass().isInstance(embeddedCipher)) {
             Object aesCipher = PiNode.piCastNonNull(embeddedCipher, AESCryptSubstitutions.AESCryptClass);
             crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, true);
@@ -83,7 +83,7 @@
     @MethodSubstitution(isStatic = false)
     static int decrypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) {
         Object realReceiver = PiNode.piCastNonNull(rcvr, cipherBlockChainingClass);
-        Object embeddedCipher = UnsafeLoadNode.load(realReceiver, embeddedCipherOffset, Kind.Object, LocationIdentity.ANY_LOCATION);
+        Object embeddedCipher = UnsafeLoadNode.load(realReceiver, embeddedCipherOffset, Kind.Object, LocationIdentity.any());
         if (in != out && getAESCryptClass().isInstance(embeddedCipher)) {
             Object aesCipher = PiNode.piCastNonNull(embeddedCipher, AESCryptSubstitutions.AESCryptClass);
             crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, false);
@@ -95,8 +95,8 @@
 
     private static void crypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset, Object embeddedCipher, boolean encrypt) {
         Object realReceiver = PiNode.piCastNonNull(rcvr, cipherBlockChainingClass);
-        Object kObject = UnsafeLoadNode.load(embeddedCipher, AESCryptSubstitutions.kOffset, Kind.Object, LocationIdentity.ANY_LOCATION);
-        Object rObject = UnsafeLoadNode.load(realReceiver, rOffset, Kind.Object, LocationIdentity.ANY_LOCATION);
+        Object kObject = UnsafeLoadNode.load(embeddedCipher, AESCryptSubstitutions.kOffset, Kind.Object, LocationIdentity.any());
+        Object rObject = UnsafeLoadNode.load(realReceiver, rOffset, Kind.Object, LocationIdentity.any());
         Word kAddr = Word.fromWordBase(Word.fromObject(kObject).add(arrayBaseOffset(Kind.Byte)));
         Word rAddr = Word.fromWordBase(Word.fromObject(rObject).add(arrayBaseOffset(Kind.Byte)));
         Word inAddr = Word.unsigned(GetObjectAddressNode.get(in) + arrayBaseOffset(Kind.Byte) + inOffset);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java	Tue Mar 17 12:05:51 2015 +0100
@@ -569,7 +569,7 @@
 
     public static Word loadWordFromObject(Object object, int offset) {
         ReplacementsUtil.staticAssert(offset != hubOffset(), "Use loadHubIntrinsic instead of loadWordFromObject");
-        return loadWordFromObjectIntrinsic(object, offset, getWordKind(), LocationIdentity.ANY_LOCATION);
+        return loadWordFromObjectIntrinsic(object, offset, getWordKind(), LocationIdentity.any());
     }
 
     public static Word loadWordFromObject(Object object, int offset, LocationIdentity identity) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java	Tue Mar 17 12:05:51 2015 +0100
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
+import static com.oracle.graal.nodes.spi.Replacements.*;
+
 import java.lang.reflect.*;
 import java.util.zip.*;
 
@@ -62,7 +64,9 @@
         replacements.registerSubstitutions(CRC32.class, CRC32Substitutions.class);
         replacements.registerSubstitutions(Reflection.class, ReflectionSubstitutions.class);
         replacements.registerSubstitutions(CompilerToVMImpl.class, CompilerToVMImplSubstitutions.class);
-        replacements.registerSubstitutions(new NamedType("com.sun.crypto.provider.AESCrypt"), AESCryptSubstitutions.class);
-        replacements.registerSubstitutions(new NamedType("com.sun.crypto.provider.CipherBlockChaining"), CipherBlockChainingSubstitutions.class);
+        if (SELF_RECURSIVE_INTRINSICS_ENABLED) {
+            replacements.registerSubstitutions(new NamedType("com.sun.crypto.provider.AESCrypt"), AESCryptSubstitutions.class);
+            replacements.registerSubstitutions(new NamedType("com.sun.crypto.provider.CipherBlockChaining"), CipherBlockChainingSubstitutions.class);
+        }
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Tue Mar 17 12:05:51 2015 +0100
@@ -147,12 +147,15 @@
             result = formatObject(hub, size, top, prototypeMarkWord, fillContents, constantSize, true);
         } else {
             new_stub.inc();
-            result = NewInstanceStubCall.call(hub);
+            result = newInstance(HotSpotBackend.NEW_INSTANCE, hub);
         }
         profileAllocation("instance", size, typeContext);
         return piCast(verifyOop(result), StampFactory.forNodeIntrinsic());
     }
 
+    @NodeIntrinsic(ForeignCallNode.class)
+    public static native Object newInstance(@ConstantNodeParameter ForeignCallDescriptor descriptor, KlassPointer hub);
+
     @Snippet
     public static Object allocateInstanceDynamic(Class<?> type, @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister, @ConstantParameter String typeContext) {
         KlassPointer hub = ClassGetHubNode.readClass(type);
@@ -201,12 +204,15 @@
             result = formatArray(hub, allocationSize, length, headerSize, top, prototypeMarkWord, fillContents, maybeUnroll, true);
         } else {
             newarray_stub.inc();
-            result = NewArrayStubCall.call(hub, length);
+            result = newArray(HotSpotBackend.NEW_ARRAY, hub, length);
         }
         profileAllocation("array", allocationSize, typeContext);
         return piArrayCast(verifyOop(result), length, StampFactory.forNodeIntrinsic());
     }
 
+    @NodeIntrinsic(ForeignCallNode.class)
+    public static native Object newArray(@ConstantNodeParameter ForeignCallDescriptor descriptor, KlassPointer hub, int length);
+
     public static final ForeignCallDescriptor DYNAMIC_NEW_ARRAY = new ForeignCallDescriptor("dynamic_new_array", Object.class, Class.class, int.class);
     public static final ForeignCallDescriptor DYNAMIC_NEW_INSTANCE = new ForeignCallDescriptor("dynamic_new_instance", Object.class, Class.class);
 
@@ -275,9 +281,12 @@
         for (int i = 0; i < rank; i++) {
             dims.writeInt(i * 4, dimensions[i], INIT_LOCATION);
         }
-        return NewMultiArrayStubCall.call(hub, rank, dims);
+        return newArrayCall(HotSpotBackend.NEW_MULTI_ARRAY, hub, rank, dims);
     }
 
+    @NodeIntrinsic(ForeignCallNode.class)
+    public static native Object newArrayCall(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word hub, int rank, Word dims);
+
     /**
      * Maximum number of long stores to emit when zeroing an object with a constant size. Larger
      * objects have their bodies initialized in a loop.
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ThreadSubstitutions.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ThreadSubstitutions.java	Tue Mar 17 12:05:51 2015 +0100
@@ -45,7 +45,7 @@
         Object thread = javaThread.readObject(threadObjectOffset(), JAVA_THREAD_THREAD_OBJECT_LOCATION);
         if (thisObject == thread) {
             Word osThread = javaThread.readWord(osThreadOffset(), JAVA_THREAD_OSTHREAD_LOCATION);
-            boolean interrupted = osThread.readInt(osThreadInterruptedOffset(), ANY_LOCATION) != 0;
+            boolean interrupted = osThread.readInt(osThreadInterruptedOffset(), any()) != 0;
             if (!interrupted || !clearInterrupted) {
                 return interrupted;
             }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/WriteBarrierSnippets.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/WriteBarrierSnippets.java	Tue Mar 17 12:05:51 2015 +0100
@@ -483,7 +483,7 @@
     public static void validateObject(Object parent, Object child) {
         if (verifyOops() && child != null && !validateOop(VALIDATE_OBJECT, parent, child)) {
             log(true, "Verification ERROR, Parent: %p Child: %p\n", Word.fromObject(parent).rawValue(), Word.fromObject(child).rawValue());
-            DirectObjectStoreNode.storeObject(null, 0, 0, null, LocationIdentity.ANY_LOCATION, Kind.Object);
+            DirectObjectStoreNode.storeObject(null, 0, 0, null, LocationIdentity.any(), Kind.Object);
         }
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopyCallNode.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopyCallNode.java	Tue Mar 17 12:05:51 2015 +0100
@@ -141,7 +141,7 @@
         if (elementKind != null) {
             return NamedLocationIdentity.getArrayLocation(elementKind);
         }
-        return ANY_LOCATION;
+        return any();
     }
 
     @NodeIntrinsic
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/UnsafeArrayCopyNode.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/UnsafeArrayCopyNode.java	Tue Mar 17 12:05:51 2015 +0100
@@ -119,7 +119,7 @@
         if (elementKind != null) {
             return NamedLocationIdentity.getArrayLocation(elementKind);
         }
-        return ANY_LOCATION;
+        return any();
     }
 
     @NodeIntrinsic
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/UnsafeArrayCopySnippets.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/UnsafeArrayCopySnippets.java	Tue Mar 17 12:05:51 2015 +0100
@@ -243,19 +243,19 @@
 
         Unsigned destNonVectorEnd = destStart.add(nonVectorBytes);
         while (destOffset.belowThan(destNonVectorEnd)) {
-            ObjectAccess.writeByte(dest, destOffset, ObjectAccess.readByte(src, srcOffset, ANY_LOCATION), ANY_LOCATION);
+            ObjectAccess.writeByte(dest, destOffset, ObjectAccess.readByte(src, srcOffset, any()), any());
             destOffset = destOffset.add(1);
             srcOffset = srcOffset.add(1);
         }
         // Unsigned destVectorEnd = destEnd.subtract(destEnd.unsignedRemainder(8));
         while (destOffset.belowThan(destVectorEnd)) {
-            ObjectAccess.writeWord(dest, destOffset, ObjectAccess.readWord(src, srcOffset, ANY_LOCATION), ANY_LOCATION);
+            ObjectAccess.writeWord(dest, destOffset, ObjectAccess.readWord(src, srcOffset, any()), any());
             destOffset = destOffset.add(wordSize());
             srcOffset = srcOffset.add(wordSize());
         }
         // Do the last bytes each when it is required to have absolute alignment.
         while (!supportsUnalignedMemoryAccess && destOffset.belowThan(destEnd)) {
-            ObjectAccess.writeByte(dest, destOffset, ObjectAccess.readByte(src, srcOffset, ANY_LOCATION), ANY_LOCATION);
+            ObjectAccess.writeByte(dest, destOffset, ObjectAccess.readByte(src, srcOffset, any()), any());
             destOffset = destOffset.add(1);
             srcOffset = srcOffset.add(1);
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java	Tue Mar 17 12:05:51 2015 +0100
@@ -45,9 +45,9 @@
 
 /**
  * Stub implementing the fast path for TLAB refill during instance class allocation. This stub is
- * called via {@link NewArrayStubCall} from the {@linkplain NewObjectSnippets inline} allocation
- * code when TLAB allocation fails. If this stub fails to refill the TLAB or allocate the object, it
- * calls out to the HotSpot C++ runtime to complete the allocation.
+ * called from the {@linkplain NewObjectSnippets inline} allocation code when TLAB allocation fails.
+ * If this stub fails to refill the TLAB or allocate the object, it calls out to the HotSpot C++
+ * runtime to complete the allocation.
  */
 public class NewArrayStub extends SnippetStub {
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java	Tue Mar 17 12:05:51 2015 +0100
@@ -45,9 +45,9 @@
 
 /**
  * Stub implementing the fast path for TLAB refill during instance class allocation. This stub is
- * called via {@link NewInstanceStubCall} from the {@linkplain NewObjectSnippets inline} allocation
- * code when TLAB allocation fails. If this stub fails to refill the TLAB or allocate the object, it
- * calls out to the HotSpot C++ runtime for to complete the allocation.
+ * called from the {@linkplain NewObjectSnippets inline} allocation code when TLAB allocation fails.
+ * If this stub fails to refill the TLAB or allocate the object, it calls out to the HotSpot C++
+ * runtime for to complete the allocation.
  */
 public class NewInstanceStub extends SnippetStub {
 
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java	Tue Mar 17 12:05:51 2015 +0100
@@ -358,7 +358,7 @@
         }
     }
 
-    protected abstract ValueNode genStoreIndexed(ValueNode array, ValueNode index, Kind kind, ValueNode value);
+    protected abstract void genStoreIndexed(ValueNode array, ValueNode index, Kind kind, ValueNode value);
 
     private void genStoreIndexed(Kind kind) {
         emitExplicitExceptions(frameState.peek(2), frameState.peek(1));
@@ -366,7 +366,7 @@
         ValueNode value = frameState.pop(kind.getStackKind());
         ValueNode index = frameState.ipop();
         ValueNode array = frameState.apop();
-        append(genStoreIndexed(array, index, kind, value));
+        genStoreIndexed(array, index, kind, value);
     }
 
     private void stackOp(int opcode) {
@@ -698,7 +698,7 @@
     }
 
     private void maybeEagerlyResolve(int cpi, int bytecode) {
-        if (graphBuilderConfig.eagerResolving() || parsingReplacement()) {
+        if (graphBuilderConfig.eagerResolving() || replacementContext instanceof IntrinsicContext) {
             constantPool.loadReferencedType(cpi, bytecode);
         }
     }
@@ -870,7 +870,7 @@
         EXPLICIT_EXCEPTIONS.increment();
     }
 
-    protected abstract ValueNode genStoreField(ValueNode receiver, ResolvedJavaField field, ValueNode value);
+    protected abstract void genStoreField(ValueNode receiver, ResolvedJavaField field, ValueNode value);
 
     private void genPutField(JavaField field) {
         emitExplicitExceptions(frameState.peek(1), null);
@@ -878,7 +878,7 @@
         ValueNode value = frameState.pop(field.getKind().getStackKind());
         ValueNode receiver = frameState.apop();
         if (field instanceof ResolvedJavaField && ((ResolvedJavaField) field).getDeclaringClass().isInitialized()) {
-            appendOptimizedStoreField(genStoreField(receiver, (ResolvedJavaField) field, value));
+            genStoreField(receiver, (ResolvedJavaField) field, value);
         } else {
             handleUnresolvedStoreField(field, value, receiver);
         }
@@ -903,16 +903,12 @@
     private void genPutStatic(JavaField field) {
         ValueNode value = frameState.pop(field.getKind().getStackKind());
         if (field instanceof ResolvedJavaField && ((ResolvedJavaType) field.getDeclaringClass()).isInitialized()) {
-            appendOptimizedStoreField(genStoreField(null, (ResolvedJavaField) field, value));
+            genStoreField(null, (ResolvedJavaField) field, value);
         } else {
             handleUnresolvedStoreField(field, value, null);
         }
     }
 
-    protected void appendOptimizedStoreField(ValueNode store) {
-        append(store);
-    }
-
     protected void appendOptimizedLoadField(Kind kind, ValueNode load) {
         // append the load to the instruction
         ValueNode optimized = append(load);
@@ -931,9 +927,9 @@
 
     protected abstract void genReturn(ValueNode x, Kind kind);
 
-    protected abstract ValueNode genMonitorEnter(ValueNode x);
+    protected abstract void genMonitorEnter(ValueNode x, int bci);
 
-    protected abstract ValueNode genMonitorExit(ValueNode x, ValueNode returnValue);
+    protected abstract void genMonitorExit(ValueNode x, ValueNode returnValue, int bci);
 
     protected abstract void genJsr(int dest);
 
@@ -1293,8 +1289,8 @@
         case ATHROW         : genThrow(); break;
         case CHECKCAST      : genCheckCast(); break;
         case INSTANCEOF     : genInstanceOf(); break;
-        case MONITORENTER   : genMonitorEnter(frameState.apop()); break;
-        case MONITOREXIT    : genMonitorExit(frameState.apop(), null); break;
+        case MONITORENTER   : genMonitorEnter(frameState.apop(), stream.nextBCI()); break;
+        case MONITOREXIT    : genMonitorExit(frameState.apop(), null, stream.nextBCI()); break;
         case MULTIANEWARRAY : genNewMultiArray(stream.readCPI()); break;
         case IFNULL         : genIfNull(Condition.EQ); break;
         case IFNONNULL      : genIfNull(Condition.NE); break;
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderContext.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderContext.java	Tue Mar 17 12:05:51 2015 +0100
@@ -36,7 +36,9 @@
 
     /**
      * Information about a snippet or method substitution currently being processed by the graph
-     * builder.
+     * builder. When in the scope of a replacement, the graph builder does not check the value kinds
+     * flowing through the JVM state since replacements can employ non-Java kinds to represent
+     * values such as raw machine words and pointers.
      */
     public interface Replacement {
 
@@ -82,6 +84,8 @@
 
     StructuredGraph getGraph();
 
+    FrameState createStateAfter();
+
     /**
      * Gets the parsing context for the method that inlines the method being parsed by this context.
      */
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Tue Mar 17 12:05:51 2015 +0100
@@ -352,10 +352,9 @@
                     if (method.isSynchronized()) {
                         // add a monitor enter to the start block
                         methodSynchronizedObject = synchronizedObject(frameState, method);
-                        MonitorEnterNode monitorEnter = genMonitorEnter(methodSynchronizedObject);
                         frameState.clearNonLiveLocals(startBlock, liveness, true);
                         assert bci() == 0;
-                        monitorEnter.setStateAfter(createFrameState(bci()));
+                        genMonitorEnter(methodSynchronizedObject, bci());
                     }
 
                     if (graphBuilderConfig.insertNonSafepointDebugInfo()) {
@@ -761,8 +760,10 @@
             }
 
             @Override
-            protected ValueNode genStoreIndexed(ValueNode array, ValueNode index, Kind kind, ValueNode value) {
-                return new StoreIndexedNode(array, index, kind, value);
+            protected void genStoreIndexed(ValueNode array, ValueNode index, Kind kind, ValueNode value) {
+                StoreIndexedNode storeIndexed = new StoreIndexedNode(array, index, kind, value);
+                append(storeIndexed);
+                storeIndexed.setStateAfter(this.createStateAfter());
             }
 
             @Override
@@ -978,8 +979,10 @@
             }
 
             @Override
-            protected ValueNode genStoreField(ValueNode receiver, ResolvedJavaField field, ValueNode value) {
-                return new StoreFieldNode(receiver, field, value);
+            protected void genStoreField(ValueNode receiver, ResolvedJavaField field, ValueNode value) {
+                StoreFieldNode storeFieldNode = new StoreFieldNode(receiver, field, value);
+                append(storeFieldNode);
+                storeFieldNode.setStateAfter(this.createFrameState(stream.nextBCI()));
             }
 
             /**
@@ -1135,7 +1138,7 @@
                     invoke = createInvoke(callTarget, resultType);
                 } else {
                     invoke = createInvokeWithException(callTarget, resultType);
-                    AbstractBeginNode beginNode = currentGraph.add(new KillingBeginNode(LocationIdentity.ANY_LOCATION));
+                    AbstractBeginNode beginNode = currentGraph.add(new KillingBeginNode(LocationIdentity.any()));
                     invoke.setNext(beginNode);
                     lastInstr = beginNode;
                 }
@@ -1219,8 +1222,9 @@
                         return false;
                     }
                 } else {
-                    if (context == null && !inlinedMethod.equals(targetMethod)) {
-                        if (inlineInfo.adoptBeforeCallFrameState) {
+                    if (context == null && inlineInfo.isReplacement) {
+                        assert !inlinedMethod.equals(targetMethod);
+                        if (inlineInfo.isIntrinsic) {
                             context = new IntrinsicContext(targetMethod, inlinedMethod, args, bci);
                         } else {
                             context = new ReplacementContext(targetMethod, inlinedMethod);
@@ -1306,6 +1310,7 @@
             protected InvokeNode createInvoke(CallTargetNode callTarget, Kind resultType) {
                 InvokeNode invoke = append(new InvokeNode(callTarget, bci()));
                 frameState.pushReturn(resultType, invoke);
+                invoke.setStateAfter(createFrameState(stream.nextBCI()));
                 return invoke;
             }
 
@@ -1356,22 +1361,22 @@
             }
 
             @Override
-            protected MonitorEnterNode genMonitorEnter(ValueNode x) {
+            protected void genMonitorEnter(ValueNode x, int bci) {
                 MonitorIdNode monitorId = currentGraph.add(new MonitorIdNode(frameState.lockDepth()));
                 MonitorEnterNode monitorEnter = append(new MonitorEnterNode(x, monitorId));
                 frameState.pushLock(x, monitorId);
-                return monitorEnter;
+                monitorEnter.setStateAfter(createFrameState(bci));
             }
 
             @Override
-            protected MonitorExitNode genMonitorExit(ValueNode x, ValueNode escapedReturnValue) {
+            protected void genMonitorExit(ValueNode x, ValueNode escapedReturnValue, int bci) {
                 MonitorIdNode monitorId = frameState.peekMonitorId();
                 ValueNode lockedObject = frameState.popLock();
                 if (GraphUtil.originalValue(lockedObject) != GraphUtil.originalValue(x)) {
                     throw bailout(String.format("unbalanced monitors: mismatch at monitorexit, %s != %s", GraphUtil.originalValue(x), GraphUtil.originalValue(lockedObject)));
                 }
                 MonitorExitNode monitorExit = append(new MonitorExitNode(x, monitorId, escapedReturnValue));
-                return monitorExit;
+                monitorExit.setStateAfter(createFrameState(bci));
             }
 
             @Override
@@ -1926,11 +1931,10 @@
 
             private void synchronizedEpilogue(int bci, ValueNode currentReturnValue, Kind currentReturnValueKind) {
                 if (method.isSynchronized()) {
-                    MonitorExitNode monitorExit = genMonitorExit(methodSynchronizedObject, currentReturnValue);
                     if (currentReturnValue != null) {
                         frameState.push(currentReturnValueKind, currentReturnValue);
                     }
-                    monitorExit.setStateAfter(createFrameState(bci));
+                    genMonitorExit(methodSynchronizedObject, currentReturnValue, bci);
                     assert !frameState.rethrowException();
                 }
             }
@@ -1986,10 +1990,6 @@
                 }
             }
 
-            private boolean isBlockEnd(Node n) {
-                return n instanceof ControlSplitNode || n instanceof ControlSinkNode;
-            }
-
             @Override
             protected void iterateBytecodesForBlock(BciBlock block) {
                 if (block.isLoopHeader && !explodeLoops) {
@@ -2058,26 +2058,15 @@
                         throw asParserError(e);
                     }
 
-                    if (lastInstr == null || isBlockEnd(lastInstr) || lastInstr.next() != null) {
+                    if (lastInstr == null || lastInstr.next() != null) {
                         break;
                     }
 
                     stream.next();
                     bci = stream.currentBCI();
 
-                    if (bci > block.endBci) {
-                        frameState.clearNonLiveLocals(currentBlock, liveness, false);
-                    }
-                    if (lastInstr instanceof StateSplit) {
-                        if (lastInstr instanceof BeginNode) {
-                            // BeginNodes do not need a frame state
-                        } else {
-                            StateSplit stateSplit = (StateSplit) lastInstr;
-                            if (stateSplit.stateAfter() == null) {
-                                stateSplit.setStateAfter(createFrameState(bci));
-                            }
-                        }
-                    }
+                    assert block == currentBlock;
+                    assert !(lastInstr instanceof StateSplit) || lastInstr instanceof BeginNode || ((StateSplit) lastInstr).stateAfter() != null : lastInstr;
                     lastInstr = finishInstruction(lastInstr, frameState);
                     if (bci < endBCI) {
                         if (bci > block.endBci) {
@@ -2391,8 +2380,15 @@
             }
 
             private FrameState createFrameState(int bci) {
+                if (currentBlock != null && bci > currentBlock.endBci) {
+                    frameState.clearNonLiveLocals(currentBlock, liveness, false);
+                }
                 return frameState.create(bci);
             }
+
+            public FrameState createStateAfter() {
+                return createFrameState(stream.nextBCI());
+            }
         }
     }
 
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugin.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugin.java	Tue Mar 17 12:05:51 2015 +0100
@@ -75,22 +75,29 @@
         public static class InlineInfo {
 
             /**
-             * The method to be inlined. If this is not equal to the {@code method} argument passed
-             * to {@link InlineInvokePlugin#getClass()}, the graph builder context interprets it as
-             * a {@linkplain GraphBuilderContext.Replacement replacement}.
+             * The method to be inlined.
              */
             public final ResolvedJavaMethod methodToInline;
 
             /**
+             * Specifies if {@link #methodToInline} is to be considered a
+             * {@linkplain GraphBuilderContext.Replacement replacement} for the {@code method}
+             * passed to {@link InlineInvokePlugin#getInlineInfo}.
+             */
+            public final boolean isReplacement;
+
+            /**
              * Specifies if {@link #methodToInline} is an intrinsic for the original method. If so,
              * any {@link StateSplit} node created in the (recursive) inlining scope will be given a
              * frame state that restarts the interpreter just before the intrinsified invocation.
              */
-            public final boolean adoptBeforeCallFrameState;
+            public final boolean isIntrinsic;
 
-            public InlineInfo(ResolvedJavaMethod methodToInline, boolean adoptBeforeCallFrameState) {
+            public InlineInfo(ResolvedJavaMethod methodToInline, boolean isReplacement, boolean isIntrinsic) {
                 this.methodToInline = methodToInline;
-                this.adoptBeforeCallFrameState = adoptBeforeCallFrameState;
+                this.isIntrinsic = isIntrinsic;
+                this.isReplacement = isReplacement;
+                assert !isIntrinsic || isReplacement : "cannot be an intrinsic without also being a replacement";
             }
         }
 
@@ -211,7 +218,7 @@
             if (ALLOW_INVOCATION_PLUGIN_TO_DO_INLINING) {
                 ResolvedJavaMethod subst = plugin.getSubstitute();
                 if (subst != null) {
-                    return ((BytecodeParser) b).inline(null, targetMethod, new InlineInfo(subst, false), args);
+                    return ((BytecodeParser) b).inline(null, targetMethod, new InlineInfo(subst, true, false), args);
                 }
             }
             if (args.length == 0) {
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/LocalLiveness.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/LocalLiveness.java	Tue Mar 17 12:05:51 2015 +0100
@@ -53,24 +53,18 @@
         boolean changed;
         int iteration = 0;
         do {
-            Debug.log("Iteration %d", iteration);
+            assert traceIteration(iteration);
             changed = false;
             for (int i = blocks.length - 1; i >= 0; i--) {
                 BciBlock block = blocks[i];
                 int blockID = block.getId();
-                // log statements in IFs because debugLiveX creates a new String
-                if (Debug.isLogEnabled()) {
-                    Debug.logv("  start B%d  [%d, %d]  in: %s  out: %s  gen: %s  kill: %s", block.getId(), block.startBci, block.endBci, debugLiveIn(blockID), debugLiveOut(blockID),
-                                    debugLiveGen(blockID), debugLiveKill(blockID));
-                }
+                assert traceStart(block, blockID);
 
                 boolean blockChanged = (iteration == 0);
                 if (block.getSuccessorCount() > 0) {
                     int oldCardinality = liveOutCardinality(blockID);
                     for (BciBlock sux : block.getSuccessors()) {
-                        if (Debug.isLogEnabled()) {
-                            Debug.log("    Successor B%d: %s", sux.getId(), debugLiveIn(sux.getId()));
-                        }
+                        assert traceSuccessor(sux);
                         propagateLiveness(blockID, sux.getId());
                     }
                     blockChanged |= (oldCardinality != liveOutCardinality(blockID));
@@ -78,10 +72,7 @@
 
                 if (blockChanged) {
                     updateLiveness(blockID);
-                    if (Debug.isLogEnabled()) {
-                        Debug.logv("  end   B%d  [%d, %d]  in: %s  out: %s  gen: %s  kill: %s", block.getId(), block.startBci, block.endBci, debugLiveIn(blockID), debugLiveOut(blockID),
-                                        debugLiveGen(blockID), debugLiveKill(blockID));
-                    }
+                    assert traceEnd(block, blockID);
                 }
                 changed |= blockChanged;
             }
@@ -89,6 +80,34 @@
         } while (changed);
     }
 
+    private static boolean traceIteration(int iteration) {
+        Debug.log("Iteration %d", iteration);
+        return true;
+    }
+
+    private boolean traceEnd(BciBlock block, int blockID) {
+        if (Debug.isLogEnabled()) {
+            Debug.logv("  end   B%d  [%d, %d]  in: %s  out: %s  gen: %s  kill: %s", block.getId(), block.startBci, block.endBci, debugLiveIn(blockID), debugLiveOut(blockID), debugLiveGen(blockID),
+                            debugLiveKill(blockID));
+        }
+        return true;
+    }
+
+    private boolean traceSuccessor(BciBlock sux) {
+        if (Debug.isLogEnabled()) {
+            Debug.log("    Successor B%d: %s", sux.getId(), debugLiveIn(sux.getId()));
+        }
+        return true;
+    }
+
+    private boolean traceStart(BciBlock block, int blockID) {
+        if (Debug.isLogEnabled()) {
+            Debug.logv("  start B%d  [%d, %d]  in: %s  out: %s  gen: %s  kill: %s", block.getId(), block.startBci, block.endBci, debugLiveIn(blockID), debugLiveOut(blockID), debugLiveGen(blockID),
+                            debugLiveKill(blockID));
+        }
+        return true;
+    }
+
     /**
      * Returns whether the local is live at the beginning of the given block.
      */
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64AddressValue.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64AddressValue.java	Tue Mar 17 12:05:51 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, 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
@@ -90,6 +90,10 @@
         return s.toString();
     }
 
+    public boolean isValidImplicitNullCheckFor(Value value, int implicitNullCheckLimit) {
+        return value.equals(base) && index.equals(Value.ILLEGAL) && displacement >= 0 && displacement < implicitNullCheckLimit;
+    }
+
     @Override
     public boolean equals(Object obj) {
         if (obj instanceof AMD64AddressValue) {
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java	Tue Mar 17 12:05:51 2015 +0100
@@ -23,460 +23,18 @@
 package com.oracle.graal.lir.amd64;
 
 import static com.oracle.graal.api.code.ValueUtil.*;
-import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 
 import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.*;
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.asm.amd64.AMD64Assembler.ConditionFlag;
-import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.amd64.AMD64Move.MemOp;
 import com.oracle.graal.lir.asm.*;
 
 public enum AMD64Arithmetic {
-
-    // @formatter:off
-
-    IADD, ISUB, IMUL, IUMUL, IDIV, IDIVREM, IREM, IUDIV, IUREM, IAND, IOR, IXOR, ISHL, ISHR, IUSHR, IROL, IROR,
-    LADD, LSUB, LMUL, LUMUL, LDIV, LDIVREM, LREM, LUDIV, LUREM, LAND, LOR, LXOR, LSHL, LSHR, LUSHR, LROL, LROR,
-    FADD, FSUB, FMUL, FDIV, FREM, FAND, FOR, FXOR,
-    DADD, DSUB, DMUL, DDIV, DREM, DAND, DOR, DXOR,
-    INEG, LNEG, INOT, LNOT,
-    SQRT,
-    L2I, B2I, S2I, B2L, S2L, I2L,
-    F2D, D2F,
-    I2F, I2D,
-    L2F, L2D,
-    MOV_I2F, MOV_L2D, MOV_F2I, MOV_D2L,
-    MOV_B2UI, MOV_B2UL, // Zero extending byte loads
-
-    /*
-     * Converts a float/double to an int/long. The result of the conversion does not comply with Java semantics
-     * when the input is a NaN, infinity or the conversion result is greater than Integer.MAX_VALUE/Long.MAX_VALUE.
-     */
-    F2I, D2I, F2L, D2L;
-
-    // @formatter:on
-
-    /**
-     * Unary operation with separate source and destination operand.
-     */
-    public static final class Unary2Op extends AMD64LIRInstruction {
-
-        public static final LIRInstructionClass<Unary2Op> TYPE = LIRInstructionClass.create(Unary2Op.class);
-        @Opcode private final AMD64Arithmetic opcode;
-        @Def({REG}) protected AllocatableValue result;
-        @Use({REG, STACK}) protected AllocatableValue x;
-
-        public Unary2Op(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x) {
-            super(TYPE);
-            this.opcode = opcode;
-            this.result = result;
-            this.x = x;
-        }
-
-        @Override
-        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-            emit(crb, masm, opcode, result, x, null);
-        }
-    }
-
-    /**
-     * Unary operation with separate source and destination operand but register only.
-     */
-    public static final class Unary2RegOp extends AMD64LIRInstruction {
-        public static final LIRInstructionClass<Unary2RegOp> TYPE = LIRInstructionClass.create(Unary2RegOp.class);
-
-        @Opcode private final AMD64Arithmetic opcode;
-        @Def({REG}) protected AllocatableValue result;
-        @Use({REG}) protected AllocatableValue x;
-
-        public Unary2RegOp(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x) {
-            super(TYPE);
-            this.opcode = opcode;
-            this.result = result;
-            this.x = x;
-        }
-
-        @Override
-        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-            emit(crb, masm, opcode, result, x, null);
-        }
-    }
-
-    /**
-     * Unary operation with single operand for source and destination.
-     */
-    public static class Unary1Op extends AMD64LIRInstruction {
-        public static final LIRInstructionClass<Unary1Op> TYPE = LIRInstructionClass.create(Unary1Op.class);
-
-        @Opcode private final AMD64Arithmetic opcode;
-        @Def({REG, HINT}) protected AllocatableValue result;
-        @Use({REG, STACK}) protected AllocatableValue x;
-
-        public Unary1Op(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x) {
-            super(TYPE);
-            this.opcode = opcode;
-            this.result = result;
-            this.x = x;
-        }
-
-        @Override
-        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-            AMD64Move.move(crb, masm, result, x);
-            emit(crb, masm, opcode, result);
-        }
-    }
-
-    /**
-     * Unary operation with separate memory source and destination operand.
-     */
-    public static final class Unary2MemoryOp extends MemOp {
-        public static final LIRInstructionClass<Unary2MemoryOp> TYPE = LIRInstructionClass.create(Unary2MemoryOp.class);
-
-        @Opcode private final AMD64Arithmetic opcode;
-        @Def({REG}) protected AllocatableValue result;
-
-        public Unary2MemoryOp(AMD64Arithmetic opcode, AllocatableValue result, Kind kind, AMD64AddressValue address, LIRFrameState state) {
-            super(TYPE, kind, address, state);
-            this.opcode = opcode;
-            this.result = result;
-        }
-
-        @Override
-        public void emitMemAccess(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-            emit(crb, masm, opcode, result, address, null);
-        }
-    }
-
-    /**
-     * Binary operation with two operands. The first source operand is combined with the
-     * destination. The second source operand may be a stack slot.
-     */
-    public static class BinaryRegStack extends AMD64LIRInstruction {
-        public static final LIRInstructionClass<BinaryRegStack> TYPE = LIRInstructionClass.create(BinaryRegStack.class);
-
-        @Opcode private final AMD64Arithmetic opcode;
-        @Def({REG, HINT}) protected AllocatableValue result;
-        @Use({REG, STACK}) protected AllocatableValue x;
-        @Alive({REG, STACK}) protected AllocatableValue y;
-
-        public BinaryRegStack(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x, AllocatableValue y) {
-            super(TYPE);
-            this.opcode = opcode;
-            this.result = result;
-            this.x = x;
-            this.y = y;
-        }
-
-        @Override
-        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-            AMD64Move.move(crb, masm, result, x);
-            emit(crb, masm, opcode, result, y, null);
-        }
-
-        @Override
-        public void verify() {
-            super.verify();
-            assert differentRegisters(result, y) || sameRegister(x, y);
-            verifyKind(opcode, result, x, y);
-        }
-    }
-
-    /**
-     * Binary operation with two operands. The first source operand is combined with the
-     * destination. The second source operand may be a stack slot.
-     */
-    public static final class BinaryMemory extends AMD64LIRInstruction {
-        public static final LIRInstructionClass<BinaryMemory> TYPE = LIRInstructionClass.create(BinaryMemory.class);
-
-        @Opcode private final AMD64Arithmetic opcode;
-        @Def({REG, HINT}) protected AllocatableValue result;
-        @Use({REG}) protected AllocatableValue x;
-        protected final Kind kind;
-        @Alive({COMPOSITE}) protected AMD64AddressValue location;
-        @State protected LIRFrameState state;
-
-        public BinaryMemory(AMD64Arithmetic opcode, Kind kind, AllocatableValue result, AllocatableValue x, AMD64AddressValue location, LIRFrameState state) {
-            super(TYPE);
-            this.opcode = opcode;
-            this.result = result;
-            this.x = x;
-            this.location = location;
-            this.kind = kind;
-            this.state = state;
-        }
-
-        @Override
-        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-            AMD64Move.move(crb, masm, result, x);
-            if (state != null) {
-                crb.recordImplicitException(masm.position(), state);
-            }
-            emit(crb, masm, opcode, result, location, null);
-        }
-
-        @Override
-        public void verify() {
-            super.verify();
-            assert differentRegisters(result, location) || sameRegister(x, location);
-            // verifyKind(opcode, result, x, location);
-        }
-    }
-
-    /**
-     * Binary operation with two operands. The first source operand is combined with the
-     * destination. The second source operand must be a register.
-     */
-    public static final class BinaryRegReg extends AMD64LIRInstruction {
-        public static final LIRInstructionClass<BinaryRegReg> TYPE = LIRInstructionClass.create(BinaryRegReg.class);
-
-        @Opcode private final AMD64Arithmetic opcode;
-        @Def({REG, HINT}) protected AllocatableValue result;
-        @Use({REG, STACK}) protected AllocatableValue x;
-        @Alive({REG}) protected AllocatableValue y;
-
-        public BinaryRegReg(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x, AllocatableValue y) {
-            super(TYPE);
-            this.opcode = opcode;
-            this.result = result;
-            this.x = x;
-            this.y = y;
-        }
-
-        @Override
-        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-            AMD64Move.move(crb, masm, result, x);
-            emit(crb, masm, opcode, result, y, null);
-        }
-
-        @Override
-        public void verify() {
-            super.verify();
-            assert differentRegisters(result, y) || sameRegister(x, y);
-            verifyKind(opcode, result, x, y);
-        }
-    }
-
-    /**
-     * Binary operation with single source/destination operand and one constant.
-     */
-    public static final class BinaryRegConst extends AMD64LIRInstruction {
-        public static final LIRInstructionClass<BinaryRegConst> TYPE = LIRInstructionClass.create(BinaryRegConst.class);
-
-        @Opcode private final AMD64Arithmetic opcode;
-        @Def({REG, HINT}) protected AllocatableValue result;
-        @Use({REG, STACK}) protected AllocatableValue x;
-        protected JavaConstant y;
-
-        public BinaryRegConst(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x, JavaConstant y) {
-            super(TYPE);
-            this.opcode = opcode;
-            this.result = result;
-            this.x = x;
-            this.y = y;
-        }
-
-        @Override
-        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-            AMD64Move.move(crb, masm, result, x);
-            emit(crb, masm, opcode, result, y, null);
-        }
-
-        @Override
-        public void verify() {
-            super.verify();
-            verifyKind(opcode, result, x, y);
-        }
-    }
-
-    /**
-     * Commutative binary operation with two operands. One of the operands is combined with the
-     * result.
-     */
-    public static final class BinaryCommutative extends AMD64LIRInstruction {
-        public static final LIRInstructionClass<BinaryCommutative> TYPE = LIRInstructionClass.create(BinaryCommutative.class);
-
-        @Opcode private final AMD64Arithmetic opcode;
-        @Def({REG, HINT}) protected AllocatableValue result;
-        @Use({REG, STACK}) protected AllocatableValue x;
-        @Use({REG, STACK}) protected AllocatableValue y;
-
-        public BinaryCommutative(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x, AllocatableValue y) {
-            super(TYPE);
-            this.opcode = opcode;
-            this.result = result;
-            this.x = x;
-            this.y = y;
-        }
-
-        @Override
-        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-            if (sameRegister(result, y)) {
-                emit(crb, masm, opcode, result, x, null);
-            } else {
-                AMD64Move.move(crb, masm, result, x);
-                emit(crb, masm, opcode, result, y, null);
-            }
-        }
-
-        @Override
-        public void verify() {
-            super.verify();
-            verifyKind(opcode, result, x, y);
-        }
-    }
-
-    /**
-     * Binary operation with separate source and destination and one constant operand.
-     */
-    public static final class BinaryRegStackConst extends AMD64LIRInstruction {
-        public static final LIRInstructionClass<BinaryRegStackConst> TYPE = LIRInstructionClass.create(BinaryRegStackConst.class);
-
-        @Opcode private final AMD64Arithmetic opcode;
-        @Def({REG}) protected AllocatableValue result;
-        @Use({REG, STACK}) protected AllocatableValue x;
-        protected JavaConstant y;
-
-        public BinaryRegStackConst(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x, JavaConstant y) {
-            super(TYPE);
-            this.opcode = opcode;
-            this.result = result;
-            this.x = x;
-            this.y = y;
-        }
-
-        @Override
-        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-            if (isRegister(x)) {
-                switch (opcode) {
-                    case IMUL:
-                        masm.imull(asIntReg(result), asIntReg(x), crb.asIntConst(y));
-                        break;
-                    case LMUL:
-                        masm.imulq(asLongReg(result), asLongReg(x), crb.asIntConst(y));
-                        break;
-                    default:
-                        throw GraalInternalError.shouldNotReachHere();
-                }
-            } else {
-                assert isStackSlot(x);
-                switch (opcode) {
-                    case IMUL:
-                        masm.imull(asIntReg(result), (AMD64Address) crb.asIntAddr(x), crb.asIntConst(y));
-                        break;
-                    case LMUL:
-                        masm.imulq(asLongReg(result), (AMD64Address) crb.asLongAddr(x), crb.asIntConst(y));
-                        break;
-                    default:
-                        throw GraalInternalError.shouldNotReachHere();
-                }
-            }
-        }
-
-        @Override
-        public void verify() {
-            super.verify();
-            verifyKind(opcode, result, x, y);
-        }
-    }
-
-    public static final class MulHighOp extends AMD64LIRInstruction {
-        public static final LIRInstructionClass<MulHighOp> TYPE = LIRInstructionClass.create(MulHighOp.class);
-
-        @Opcode private final AMD64Arithmetic opcode;
-        @Def({REG}) public AllocatableValue lowResult;
-        @Def({REG}) public AllocatableValue highResult;
-        @Use({REG}) public AllocatableValue x;
-        @Use({REG, STACK}) public AllocatableValue y;
-
-        public MulHighOp(AMD64Arithmetic opcode, LIRKind kind, AllocatableValue y) {
-            super(TYPE);
-            this.opcode = opcode;
-            this.x = AMD64.rax.asValue(kind);
-            this.y = y;
-            this.lowResult = AMD64.rax.asValue(kind);
-            this.highResult = AMD64.rdx.asValue(kind);
-        }
-
-        @Override
-        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-            if (isRegister(y)) {
-                switch (opcode) {
-                    case IMUL:
-                        masm.imull(asRegister(y));
-                        break;
-                    case IUMUL:
-                        masm.mull(asRegister(y));
-                        break;
-                    case LMUL:
-                        masm.imulq(asRegister(y));
-                        break;
-                    case LUMUL:
-                        masm.mulq(asRegister(y));
-                        break;
-                    default:
-                        throw GraalInternalError.shouldNotReachHere();
-                }
-            } else {
-                switch (opcode) {
-                    case IMUL:
-                        masm.imull((AMD64Address) crb.asAddress(y));
-                        break;
-                    case IUMUL:
-                        masm.mull((AMD64Address) crb.asAddress(y));
-                        break;
-                    case LMUL:
-                        masm.imulq((AMD64Address) crb.asAddress(y));
-                        break;
-                    case LUMUL:
-                        masm.mulq((AMD64Address) crb.asAddress(y));
-                        break;
-                    default:
-                        throw GraalInternalError.shouldNotReachHere();
-                }
-            }
-        }
-    }
-
-    public static final class DivRemOp extends AMD64LIRInstruction {
-        public static final LIRInstructionClass<DivRemOp> TYPE = LIRInstructionClass.create(DivRemOp.class);
-
-        @Opcode private final AMD64Arithmetic opcode;
-        @Def public AllocatableValue divResult;
-        @Def public AllocatableValue remResult;
-        @Use protected AllocatableValue x;
-        @Alive protected AllocatableValue y;
-        @State protected LIRFrameState state;
-
-        public DivRemOp(AMD64Arithmetic opcode, AllocatableValue x, AllocatableValue y, LIRFrameState state) {
-            super(TYPE);
-            this.opcode = opcode;
-            this.divResult = AMD64.rax.asValue(LIRKind.derive(x, y));
-            this.remResult = AMD64.rdx.asValue(LIRKind.derive(x, y));
-            this.x = x;
-            this.y = y;
-            this.state = state;
-        }
-
-        @Override
-        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-            emit(crb, masm, opcode, null, y, state);
-        }
-
-        @Override
-        public void verify() {
-            super.verify();
-            // left input in rax, right input in any register but rax and rdx, result quotient in
-            // rax, result remainder in rdx
-            assert asRegister(x).equals(AMD64.rax);
-            assert differentRegisters(y, AMD64.rax.asValue(), AMD64.rdx.asValue());
-            verifyKind(opcode, divResult, x, y);
-            verifyKind(opcode, remResult, x, y);
-        }
-    }
+    FREM,
+    DREM;
 
     public static class FPDivRemOp extends AMD64LIRInstruction {
         public static final LIRInstructionClass<FPDivRemOp> TYPE = LIRInstructionClass.create(FPDivRemOp.class);
@@ -536,647 +94,8 @@
         @Override
         public void verify() {
             super.verify();
-            verifyKind(opcode, result, x, y);
-        }
-    }
-
-    @SuppressWarnings("unused")
-    protected static void emit(CompilationResultBuilder crb, AMD64MacroAssembler masm, AMD64Arithmetic opcode, AllocatableValue result) {
-        switch (opcode) {
-            case INEG:
-                masm.negl(asIntReg(result));
-                break;
-            case LNEG:
-                masm.negq(asLongReg(result));
-                break;
-            case INOT:
-                masm.notl(asIntReg(result));
-                break;
-            case LNOT:
-                masm.notq(asLongReg(result));
-                break;
-            default:
-                throw GraalInternalError.shouldNotReachHere();
+            assert (opcode.name().startsWith("F") && result.getKind() == Kind.Float && x.getKind() == Kind.Float && y.getKind() == Kind.Float) ||
+                            (opcode.name().startsWith("D") && result.getKind() == Kind.Double && x.getKind() == Kind.Double && y.getKind() == Kind.Double);
         }
     }
-
-    public static void emit(CompilationResultBuilder crb, AMD64MacroAssembler masm, AMD64Arithmetic opcode, Value dst, Value src, LIRFrameState info) {
-        int exceptionOffset = -1;
-        if (isRegister(src)) {
-            switch (opcode) {
-                case IADD:
-                    masm.addl(asIntReg(dst), asIntReg(src));
-                    break;
-                case ISUB:
-                    masm.subl(asIntReg(dst), asIntReg(src));
-                    break;
-                case IAND:
-                    masm.andl(asIntReg(dst), asIntReg(src));
-                    break;
-                case IMUL:
-                    masm.imull(asIntReg(dst), asIntReg(src));
-                    break;
-                case IOR:
-                    masm.orl(asIntReg(dst), asIntReg(src));
-                    break;
-                case IXOR:
-                    masm.xorl(asIntReg(dst), asIntReg(src));
-                    break;
-                case ISHL:
-                    assert asIntReg(src).equals(AMD64.rcx);
-                    masm.shll(asIntReg(dst));
-                    break;
-                case ISHR:
-                    assert asIntReg(src).equals(AMD64.rcx);
-                    masm.sarl(asIntReg(dst));
-                    break;
-                case IUSHR:
-                    assert asIntReg(src).equals(AMD64.rcx);
-                    masm.shrl(asIntReg(dst));
-                    break;
-                case IROL:
-                    assert asIntReg(src).equals(AMD64.rcx);
-                    masm.roll(asIntReg(dst));
-                    break;
-                case IROR:
-                    assert asIntReg(src).equals(AMD64.rcx);
-                    masm.rorl(asIntReg(dst));
-                    break;
-
-                case LADD:
-                    masm.addq(asLongReg(dst), asLongReg(src));
-                    break;
-                case LSUB:
-                    masm.subq(asLongReg(dst), asLongReg(src));
-                    break;
-                case LMUL:
-                    masm.imulq(asLongReg(dst), asLongReg(src));
-                    break;
-                case LAND:
-                    masm.andq(asLongReg(dst), asLongReg(src));
-                    break;
-                case LOR:
-                    masm.orq(asLongReg(dst), asLongReg(src));
-                    break;
-                case LXOR:
-                    masm.xorq(asLongReg(dst), asLongReg(src));
-                    break;
-                case LSHL:
-                    assert asIntReg(src).equals(AMD64.rcx);
-                    masm.shlq(asLongReg(dst));
-                    break;
-                case LSHR:
-                    assert asIntReg(src).equals(AMD64.rcx);
-                    masm.sarq(asLongReg(dst));
-                    break;
-                case LUSHR:
-                    assert asIntReg(src).equals(AMD64.rcx);
-                    masm.shrq(asLongReg(dst));
-                    break;
-                case LROL:
-                    assert asIntReg(src).equals(AMD64.rcx);
-                    masm.rolq(asLongReg(dst));
-                    break;
-                case LROR:
-                    assert asIntReg(src).equals(AMD64.rcx);
-                    masm.rorq(asLongReg(dst));
-                    break;
-
-                case FADD:
-                    masm.addss(asFloatReg(dst), asFloatReg(src));
-                    break;
-                case FSUB:
-                    masm.subss(asFloatReg(dst), asFloatReg(src));
-                    break;
-                case FMUL:
-                    masm.mulss(asFloatReg(dst), asFloatReg(src));
-                    break;
-                case FDIV:
-                    masm.divss(asFloatReg(dst), asFloatReg(src));
-                    break;
-                case FAND:
-                    masm.andps(asFloatReg(dst), asFloatReg(src));
-                    break;
-                case FOR:
-                    masm.orps(asFloatReg(dst), asFloatReg(src));
-                    break;
-                case FXOR:
-                    masm.xorps(asFloatReg(dst), asFloatReg(src));
-                    break;
-
-                case DADD:
-                    masm.addsd(asDoubleReg(dst), asDoubleReg(src));
-                    break;
-                case DSUB:
-                    masm.subsd(asDoubleReg(dst), asDoubleReg(src));
-                    break;
-                case DMUL:
-                    masm.mulsd(asDoubleReg(dst), asDoubleReg(src));
-                    break;
-                case DDIV:
-                    masm.divsd(asDoubleReg(dst), asDoubleReg(src));
-                    break;
-                case DAND:
-                    masm.andpd(asDoubleReg(dst), asDoubleReg(src));
-                    break;
-                case DOR:
-                    masm.orpd(asDoubleReg(dst), asDoubleReg(src));
-                    break;
-                case DXOR:
-                    masm.xorpd(asDoubleReg(dst), asDoubleReg(src));
-                    break;
-
-                case SQRT:
-                    masm.sqrtsd(asDoubleReg(dst), asDoubleReg(src));
-                    break;
-
-                case B2I:
-                    masm.movsbl(asIntReg(dst), asIntReg(src));
-                    break;
-                case S2I:
-                    masm.movswl(asIntReg(dst), asIntReg(src));
-                    break;
-                case B2L:
-                    masm.movsbq(asLongReg(dst), asIntReg(src));
-                    break;
-                case S2L:
-                    masm.movswq(asLongReg(dst), asIntReg(src));
-                    break;
-                case I2L:
-                    masm.movslq(asLongReg(dst), asIntReg(src));
-                    break;
-                case L2I:
-                    masm.movl(asIntReg(dst), asLongReg(src));
-                    break;
-                case F2D:
-                    masm.cvtss2sd(asDoubleReg(dst), asFloatReg(src));
-                    break;
-                case D2F:
-                    masm.cvtsd2ss(asFloatReg(dst), asDoubleReg(src));
-                    break;
-                case I2F:
-                    masm.cvtsi2ssl(asFloatReg(dst), asIntReg(src));
-                    break;
-                case I2D:
-                    masm.cvtsi2sdl(asDoubleReg(dst), asIntReg(src));
-                    break;
-                case L2F:
-                    masm.cvtsi2ssq(asFloatReg(dst), asLongReg(src));
-                    break;
-                case L2D:
-                    masm.cvtsi2sdq(asDoubleReg(dst), asLongReg(src));
-                    break;
-                case F2I:
-                    masm.cvttss2sil(asIntReg(dst), asFloatReg(src));
-                    break;
-                case D2I:
-                    masm.cvttsd2sil(asIntReg(dst), asDoubleReg(src));
-                    break;
-                case F2L:
-                    masm.cvttss2siq(asLongReg(dst), asFloatReg(src));
-                    break;
-                case D2L:
-                    masm.cvttsd2siq(asLongReg(dst), asDoubleReg(src));
-                    break;
-                case MOV_I2F:
-                    masm.movdl(asFloatReg(dst), asIntReg(src));
-                    break;
-                case MOV_L2D:
-                    masm.movdq(asDoubleReg(dst), asLongReg(src));
-                    break;
-                case MOV_F2I:
-                    masm.movdl(asIntReg(dst), asFloatReg(src));
-                    break;
-                case MOV_D2L:
-                    masm.movdq(asLongReg(dst), asDoubleReg(src));
-                    break;
-
-                case IDIVREM:
-                case IDIV:
-                case IREM:
-                    masm.cdql();
-                    exceptionOffset = masm.position();
-                    masm.idivl(asRegister(src));
-                    break;
-
-                case LDIVREM:
-                case LDIV:
-                case LREM:
-                    masm.cdqq();
-                    exceptionOffset = masm.position();
-                    masm.idivq(asRegister(src));
-                    break;
-
-                case IUDIV:
-                case IUREM:
-                    // Must zero the high 64-bit word (in RDX) of the dividend
-                    masm.xorq(AMD64.rdx, AMD64.rdx);
-                    exceptionOffset = masm.position();
-                    masm.divl(asRegister(src));
-                    break;
-
-                case LUDIV:
-                case LUREM:
-                    // Must zero the high 64-bit word (in RDX) of the dividend
-                    masm.xorq(AMD64.rdx, AMD64.rdx);
-                    exceptionOffset = masm.position();
-                    masm.divq(asRegister(src));
-                    break;
-                default:
-                    throw GraalInternalError.shouldNotReachHere();
-            }
-        } else if (isConstant(src)) {
-            switch (opcode) {
-                case IADD:
-                    masm.incrementl(asIntReg(dst), crb.asIntConst(src));
-                    break;
-                case ISUB:
-                    masm.decrementl(asIntReg(dst), crb.asIntConst(src));
-                    break;
-                case IAND:
-                    masm.andl(asIntReg(dst), crb.asIntConst(src));
-                    break;
-                case IOR:
-                    masm.orl(asIntReg(dst), crb.asIntConst(src));
-                    break;
-                case IXOR:
-                    masm.xorl(asIntReg(dst), crb.asIntConst(src));
-                    break;
-                case ISHL:
-                    masm.shll(asIntReg(dst), crb.asIntConst(src) & 31);
-                    break;
-                case ISHR:
-                    masm.sarl(asIntReg(dst), crb.asIntConst(src) & 31);
-                    break;
-                case IUSHR:
-                    masm.shrl(asIntReg(dst), crb.asIntConst(src) & 31);
-                    break;
-                case IROL:
-                    masm.roll(asIntReg(dst), crb.asIntConst(src) & 31);
-                    break;
-                case IROR:
-                    masm.rorl(asIntReg(dst), crb.asIntConst(src) & 31);
-                    break;
-
-                case LADD:
-                    masm.addq(asLongReg(dst), crb.asIntConst(src));
-                    break;
-                case LSUB:
-                    masm.subq(asLongReg(dst), crb.asIntConst(src));
-                    break;
-                case LAND:
-                    masm.andq(asLongReg(dst), crb.asIntConst(src));
-                    break;
-                case LOR:
-                    masm.orq(asLongReg(dst), crb.asIntConst(src));
-                    break;
-                case LXOR:
-                    masm.xorq(asLongReg(dst), crb.asIntConst(src));
-                    break;
-                case LSHL:
-                    masm.shlq(asLongReg(dst), crb.asIntConst(src) & 63);
-                    break;
-                case LSHR:
-                    masm.sarq(asLongReg(dst), crb.asIntConst(src) & 63);
-                    break;
-                case LUSHR:
-                    masm.shrq(asLongReg(dst), crb.asIntConst(src) & 63);
-                    break;
-                case LROL:
-                    masm.rolq(asLongReg(dst), crb.asIntConst(src) & 31);
-                    break;
-                case LROR:
-                    masm.rorq(asLongReg(dst), crb.asIntConst(src) & 31);
-                    break;
-
-                case FADD:
-                    masm.addss(asFloatReg(dst), (AMD64Address) crb.asFloatConstRef(src));
-                    break;
-                case FSUB:
-                    masm.subss(asFloatReg(dst), (AMD64Address) crb.asFloatConstRef(src));
-                    break;
-                case FMUL:
-                    masm.mulss(asFloatReg(dst), (AMD64Address) crb.asFloatConstRef(src));
-                    break;
-                case FAND:
-                    masm.andps(asFloatReg(dst), (AMD64Address) crb.asFloatConstRef(src, 16));
-                    break;
-                case FOR:
-                    masm.orps(asFloatReg(dst), (AMD64Address) crb.asFloatConstRef(src, 16));
-                    break;
-                case FXOR:
-                    masm.xorps(asFloatReg(dst), (AMD64Address) crb.asFloatConstRef(src, 16));
-                    break;
-                case FDIV:
-                    masm.divss(asFloatReg(dst), (AMD64Address) crb.asFloatConstRef(src));
-                    break;
-
-                case DADD:
-                    masm.addsd(asDoubleReg(dst), (AMD64Address) crb.asDoubleConstRef(src));
-                    break;
-                case DSUB:
-                    masm.subsd(asDoubleReg(dst), (AMD64Address) crb.asDoubleConstRef(src));
-                    break;
-                case DMUL:
-                    masm.mulsd(asDoubleReg(dst), (AMD64Address) crb.asDoubleConstRef(src));
-                    break;
-                case DDIV:
-                    masm.divsd(asDoubleReg(dst), (AMD64Address) crb.asDoubleConstRef(src));
-                    break;
-                case DAND:
-                    masm.andpd(asDoubleReg(dst), (AMD64Address) crb.asDoubleConstRef(src, 16));
-                    break;
-                case DOR:
-                    masm.orpd(asDoubleReg(dst), (AMD64Address) crb.asDoubleConstRef(src, 16));
-                    break;
-                case DXOR:
-                    masm.xorpd(asDoubleReg(dst), (AMD64Address) crb.asDoubleConstRef(src, 16));
-                    break;
-                default:
-                    throw GraalInternalError.shouldNotReachHere();
-            }
-        } else if (isStackSlot(src)) {
-
-            switch (opcode) {
-                case IADD:
-                    masm.addl(asIntReg(dst), (AMD64Address) crb.asIntAddr(src));
-                    break;
-                case ISUB:
-                    masm.subl(asIntReg(dst), (AMD64Address) crb.asIntAddr(src));
-                    break;
-                case IAND:
-                    masm.andl(asIntReg(dst), (AMD64Address) crb.asIntAddr(src));
-                    break;
-                case IMUL:
-                    masm.imull(asIntReg(dst), (AMD64Address) crb.asIntAddr(src));
-                    break;
-                case IOR:
-                    masm.orl(asIntReg(dst), (AMD64Address) crb.asIntAddr(src));
-                    break;
-                case IXOR:
-                    masm.xorl(asIntReg(dst), (AMD64Address) crb.asIntAddr(src));
-                    break;
-
-                case LADD:
-                    masm.addq(asLongReg(dst), (AMD64Address) crb.asLongAddr(src));
-                    break;
-                case LSUB:
-                    masm.subq(asLongReg(dst), (AMD64Address) crb.asLongAddr(src));
-                    break;
-                case LMUL:
-                    masm.imulq(asLongReg(dst), (AMD64Address) crb.asLongAddr(src));
-                    break;
-                case LAND:
-                    masm.andq(asLongReg(dst), (AMD64Address) crb.asLongAddr(src));
-                    break;
-                case LOR:
-                    masm.orq(asLongReg(dst), (AMD64Address) crb.asLongAddr(src));
-                    break;
-                case LXOR:
-                    masm.xorq(asLongReg(dst), (AMD64Address) crb.asLongAddr(src));
-                    break;
-
-                case FADD:
-                    masm.addss(asFloatReg(dst), (AMD64Address) crb.asFloatAddr(src));
-                    break;
-                case FSUB:
-                    masm.subss(asFloatReg(dst), (AMD64Address) crb.asFloatAddr(src));
-                    break;
-                case FMUL:
-                    masm.mulss(asFloatReg(dst), (AMD64Address) crb.asFloatAddr(src));
-                    break;
-                case FDIV:
-                    masm.divss(asFloatReg(dst), (AMD64Address) crb.asFloatAddr(src));
-                    break;
-
-                case DADD:
-                    masm.addsd(asDoubleReg(dst), (AMD64Address) crb.asDoubleAddr(src));
-                    break;
-                case DSUB:
-                    masm.subsd(asDoubleReg(dst), (AMD64Address) crb.asDoubleAddr(src));
-                    break;
-                case DMUL:
-                    masm.mulsd(asDoubleReg(dst), (AMD64Address) crb.asDoubleAddr(src));
-                    break;
-                case DDIV:
-                    masm.divsd(asDoubleReg(dst), (AMD64Address) crb.asDoubleAddr(src));
-                    break;
-
-                case SQRT:
-                    masm.sqrtsd(asDoubleReg(dst), (AMD64Address) crb.asDoubleAddr(src));
-                    break;
-
-                case B2I:
-                    masm.movsbl(asIntReg(dst), (AMD64Address) crb.asByteAddr(src));
-                    break;
-                case S2I:
-                    masm.movswl(asIntReg(dst), (AMD64Address) crb.asShortAddr(src));
-                    break;
-                case B2L:
-                    masm.movsbq(asLongReg(dst), (AMD64Address) crb.asByteAddr(src));
-                    break;
-                case S2L:
-                    masm.movswq(asLongReg(dst), (AMD64Address) crb.asShortAddr(src));
-                    break;
-                case I2L:
-                    masm.movslq(asLongReg(dst), (AMD64Address) crb.asIntAddr(src));
-                    break;
-                case F2D:
-                    masm.cvtss2sd(asDoubleReg(dst), (AMD64Address) crb.asFloatAddr(src));
-                    break;
-                case D2F:
-                    masm.cvtsd2ss(asFloatReg(dst), (AMD64Address) crb.asDoubleAddr(src));
-                    break;
-                case I2F:
-                    masm.cvtsi2ssl(asFloatReg(dst), (AMD64Address) crb.asIntAddr(src));
-                    break;
-                case I2D:
-                    masm.cvtsi2sdl(asDoubleReg(dst), (AMD64Address) crb.asIntAddr(src));
-                    break;
-                case L2F:
-                    masm.cvtsi2ssq(asFloatReg(dst), (AMD64Address) crb.asLongAddr(src));
-                    break;
-                case L2D:
-                    masm.cvtsi2sdq(asDoubleReg(dst), (AMD64Address) crb.asLongAddr(src));
-                    break;
-                case F2I:
-                    masm.cvttss2sil(asIntReg(dst), (AMD64Address) crb.asFloatAddr(src));
-                    break;
-                case D2I:
-                    masm.cvttsd2sil(asIntReg(dst), (AMD64Address) crb.asDoubleAddr(src));
-                    break;
-                case F2L:
-                    masm.cvttss2siq(asLongReg(dst), (AMD64Address) crb.asFloatAddr(src));
-                    break;
-                case D2L:
-                    masm.cvttsd2siq(asLongReg(dst), (AMD64Address) crb.asDoubleAddr(src));
-                    break;
-                case MOV_I2F:
-                    masm.movss(asFloatReg(dst), (AMD64Address) crb.asIntAddr(src));
-                    break;
-                case MOV_L2D:
-                    masm.movsd(asDoubleReg(dst), (AMD64Address) crb.asLongAddr(src));
-                    break;
-                case MOV_F2I:
-                    masm.movl(asIntReg(dst), (AMD64Address) crb.asFloatAddr(src));
-                    break;
-                case MOV_D2L:
-                    masm.movq(asLongReg(dst), (AMD64Address) crb.asDoubleAddr(src));
-                    break;
-
-                default:
-                    throw GraalInternalError.shouldNotReachHere();
-            }
-        } else {
-            switch (opcode) {
-                case IADD:
-                    masm.addl(asIntReg(dst), ((AMD64AddressValue) src).toAddress());
-                    break;
-                case ISUB:
-                    masm.subl(asIntReg(dst), ((AMD64AddressValue) src).toAddress());
-                    break;
-                case IAND:
-                    masm.andl(asIntReg(dst), ((AMD64AddressValue) src).toAddress());
-                    break;
-                case IMUL:
-                    masm.imull(asIntReg(dst), ((AMD64AddressValue) src).toAddress());
-                    break;
-                case IOR:
-                    masm.orl(asIntReg(dst), ((AMD64AddressValue) src).toAddress());
-                    break;
-                case IXOR:
-                    masm.xorl(asIntReg(dst), ((AMD64AddressValue) src).toAddress());
-                    break;
-
-                case LADD:
-                    masm.addq(asLongReg(dst), ((AMD64AddressValue) src).toAddress());
-                    break;
-                case LSUB:
-                    masm.subq(asLongReg(dst), ((AMD64AddressValue) src).toAddress());
-                    break;
-                case LMUL:
-                    masm.imulq(asLongReg(dst), ((AMD64AddressValue) src).toAddress());
-                    break;
-                case LAND:
-                    masm.andq(asLongReg(dst), ((AMD64AddressValue) src).toAddress());
-                    break;
-                case LOR:
-                    masm.orq(asLongReg(dst), ((AMD64AddressValue) src).toAddress());
-                    break;
-                case LXOR:
-                    masm.xorq(asLongReg(dst), ((AMD64AddressValue) src).toAddress());
-                    break;
-
-                case FADD:
-                    masm.addss(asFloatReg(dst), ((AMD64AddressValue) src).toAddress());
-                    break;
-                case FSUB:
-                    masm.subss(asFloatReg(dst), ((AMD64AddressValue) src).toAddress());
-                    break;
-                case FMUL:
-                    masm.mulss(asFloatReg(dst), ((AMD64AddressValue) src).toAddress());
-                    break;
-                case FDIV:
-                    masm.divss(asFloatReg(dst), ((AMD64AddressValue) src).toAddress());
-                    break;
-
-                case DADD:
-                    masm.addsd(asDoubleReg(dst), ((AMD64AddressValue) src).toAddress());
-                    break;
-                case DSUB:
-                    masm.subsd(asDoubleReg(dst), ((AMD64AddressValue) src).toAddress());
-                    break;
-                case DMUL:
-                    masm.mulsd(asDoubleReg(dst), ((AMD64AddressValue) src).toAddress());
-                    break;
-                case DDIV:
-                    masm.divsd(asDoubleReg(dst), ((AMD64AddressValue) src).toAddress());
-                    break;
-
-                case SQRT:
-                    masm.sqrtsd(asDoubleReg(dst), ((AMD64AddressValue) src).toAddress());
-                    break;
-
-                case B2I:
-                    masm.movsbl(asIntReg(dst), ((AMD64AddressValue) src).toAddress());
-                    break;
-                case S2I:
-                    masm.movswl(asIntReg(dst), ((AMD64AddressValue) src).toAddress());
-                    break;
-                case B2L:
-                    masm.movsbq(asLongReg(dst), ((AMD64AddressValue) src).toAddress());
-                    break;
-                case S2L:
-                    masm.movswq(asLongReg(dst), ((AMD64AddressValue) src).toAddress());
-                    break;
-                case I2L:
-                    masm.movslq(asLongReg(dst), ((AMD64AddressValue) src).toAddress());
-                    break;
-                case F2D:
-                    masm.cvtss2sd(asDoubleReg(dst), ((AMD64AddressValue) src).toAddress());
-                    break;
-                case D2F:
-                    masm.cvtsd2ss(asFloatReg(dst), ((AMD64AddressValue) src).toAddress());
-                    break;
-                case I2F:
-                    masm.cvtsi2ssl(asFloatReg(dst), ((AMD64AddressValue) src).toAddress());
-                    break;
-                case I2D:
-                    masm.cvtsi2sdl(asDoubleReg(dst), ((AMD64AddressValue) src).toAddress());
-                    break;
-                case L2F:
-                    masm.cvtsi2ssq(asFloatReg(dst), ((AMD64AddressValue) src).toAddress());
-                    break;
-                case L2D:
-                    masm.cvtsi2sdq(asDoubleReg(dst), ((AMD64AddressValue) src).toAddress());
-                    break;
-                case F2I:
-                    masm.cvttss2sil(asIntReg(dst), ((AMD64AddressValue) src).toAddress());
-                    break;
-                case D2I:
-                    masm.cvttsd2sil(asIntReg(dst), ((AMD64AddressValue) src).toAddress());
-                    break;
-                case F2L:
-                    masm.cvttss2siq(asLongReg(dst), ((AMD64AddressValue) src).toAddress());
-                    break;
-                case D2L:
-                    masm.cvttsd2siq(asLongReg(dst), ((AMD64AddressValue) src).toAddress());
-                    break;
-                case MOV_I2F:
-                    masm.movss(asFloatReg(dst), ((AMD64AddressValue) src).toAddress());
-                    break;
-                case MOV_L2D:
-                    masm.movsd(asDoubleReg(dst), ((AMD64AddressValue) src).toAddress());
-                    break;
-                case MOV_F2I:
-                    masm.movl(asIntReg(dst), ((AMD64AddressValue) src).toAddress());
-                    break;
-                case MOV_D2L:
-                    masm.movq(asLongReg(dst), ((AMD64AddressValue) src).toAddress());
-                    break;
-                case MOV_B2UI:
-                    masm.movzbl(asIntReg(dst), ((AMD64AddressValue) src).toAddress());
-                    break;
-                case MOV_B2UL:
-                    masm.movzbl(asLongReg(dst), ((AMD64AddressValue) src).toAddress());
-                    break;
-
-                default:
-                    throw GraalInternalError.shouldNotReachHere();
-            }
-        }
-
-        if (info != null) {
-            assert exceptionOffset != -1;
-            crb.recordImplicitException(exceptionOffset, info);
-        }
-    }
-
-    private static void verifyKind(AMD64Arithmetic opcode, Value result, Value x, Value y) {
-        assert (opcode.name().startsWith("I") && result.getKind().getStackKind() == Kind.Int && x.getKind().getStackKind() == Kind.Int && y.getKind().getStackKind() == Kind.Int) ||
-                        (opcode.name().startsWith("L") && result.getKind() == Kind.Long && x.getKind() == Kind.Long && y.getKind() == Kind.Long) ||
-                        (opcode.name().startsWith("F") && result.getKind() == Kind.Float && x.getKind() == Kind.Float && y.getKind() == Kind.Float) ||
-                        (opcode.name().startsWith("D") && result.getKind() == Kind.Double && x.getKind() == Kind.Double && y.getKind() == Kind.Double) ||
-                        (opcode.name().matches(".U?SH.") && result.getKind() == x.getKind() && y.getKind() == Kind.Int && (isConstant(y) || asRegister(y).equals(AMD64.rcx)));
-    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BinaryCommutativeOp.java	Tue Mar 17 12:05:51 2015 +0100
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.amd64;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp;
+import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.asm.*;
+
+public class AMD64BinaryCommutativeOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64BinaryCommutativeOp> TYPE = LIRInstructionClass.create(AMD64BinaryCommutativeOp.class);
+
+    @Opcode private final AMD64RMOp opcode;
+    private final OperandSize size;
+
+    @Def({REG, HINT}) protected AllocatableValue result;
+    @Use({REG, STACK}) protected AllocatableValue x;
+    @Use({REG, STACK}) protected AllocatableValue y;
+
+    public AMD64BinaryCommutativeOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AllocatableValue y) {
+        super(TYPE);
+        this.opcode = opcode;
+        this.size = size;
+
+        this.result = result;
+        this.x = x;
+        this.y = y;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        AllocatableValue input;
+        if (sameRegister(result, y)) {
+            input = x;
+        } else {
+            AMD64Move.move(crb, masm, result, x);
+            input = y;
+        }
+
+        if (isRegister(input)) {
+            opcode.emit(masm, size, asRegister(result), asRegister(input));
+        } else {
+            assert isStackSlot(input);
+            opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(input));
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BinaryConstOp.java	Tue Mar 17 12:05:51 2015 +0100
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.amd64;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.*;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MIOp;
+import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.asm.*;
+
+public class AMD64BinaryConstOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64BinaryConstOp> TYPE = LIRInstructionClass.create(AMD64BinaryConstOp.class);
+
+    @Opcode private final AMD64MIOp opcode;
+    private final OperandSize size;
+
+    @Def({REG, HINT}) protected AllocatableValue result;
+    @Use({REG, STACK}) protected AllocatableValue x;
+    protected JavaConstant y;
+
+    public AMD64BinaryConstOp(AMD64BinaryArithmetic opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y) {
+        this(opcode.getMIOpcode(size, NumUtil.isByte(y.asLong())), size, result, x, y);
+    }
+
+    public AMD64BinaryConstOp(AMD64MIOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y) {
+        super(TYPE);
+        this.opcode = opcode;
+        this.size = size;
+
+        this.result = result;
+        this.x = x;
+        this.y = y;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        AMD64Move.move(crb, masm, result, x);
+        assert NumUtil.is32bit(y.asLong());
+        opcode.emit(masm, size, asRegister(result), (int) y.asLong());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BinaryMemoryOp.java	Tue Mar 17 12:05:51 2015 +0100
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.amd64;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp;
+import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.ImplicitNullCheck;
+import com.oracle.graal.lir.asm.*;
+
+public class AMD64BinaryMemoryOp extends AMD64LIRInstruction implements ImplicitNullCheck {
+    public static final LIRInstructionClass<AMD64BinaryMemoryOp> TYPE = LIRInstructionClass.create(AMD64BinaryMemoryOp.class);
+
+    @Opcode private final AMD64RMOp opcode;
+    private final OperandSize size;
+
+    @Def({REG, HINT}) protected AllocatableValue result;
+    @Use({REG, STACK}) protected AllocatableValue x;
+    @Alive({COMPOSITE}) protected AMD64AddressValue y;
+
+    @State protected LIRFrameState state;
+
+    public AMD64BinaryMemoryOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AMD64AddressValue y, LIRFrameState state) {
+        super(TYPE);
+        this.opcode = opcode;
+        this.size = size;
+
+        this.result = result;
+        this.x = x;
+        this.y = y;
+
+        this.state = state;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        AMD64Move.move(crb, masm, result, x);
+        if (state != null) {
+            crb.recordImplicitException(masm.position(), state);
+        }
+        opcode.emit(masm, size, asRegister(result), y.toAddress());
+    }
+
+    @Override
+    public void verify() {
+        super.verify();
+        assert differentRegisters(result, y) || sameRegister(x, y);
+    }
+
+    @Override
+    public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) {
+        if (state == null && y.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) {
+            state = nullCheckState;
+            return true;
+        }
+        return false;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BinaryOp.java	Tue Mar 17 12:05:51 2015 +0100
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.amd64;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp;
+import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.asm.*;
+
+public class AMD64BinaryOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64BinaryOp> TYPE = LIRInstructionClass.create(AMD64BinaryOp.class);
+
+    @Opcode private final AMD64RMOp opcode;
+    private final OperandSize size;
+
+    @Def({REG, HINT}) protected AllocatableValue result;
+    @Use({REG, STACK}) protected AllocatableValue x;
+    @Alive({REG, STACK}) protected AllocatableValue y;
+
+    public AMD64BinaryOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AllocatableValue y) {
+        super(TYPE);
+        this.opcode = opcode;
+        this.size = size;
+
+        this.result = result;
+        this.x = x;
+        this.y = y;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        AMD64Move.move(crb, masm, result, x);
+        if (isRegister(y)) {
+            opcode.emit(masm, size, asRegister(result), asRegister(y));
+        } else {
+            assert isStackSlot(y);
+            opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(y));
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BinaryPatchOp.java	Tue Mar 17 12:05:51 2015 +0100
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.amd64;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp;
+import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.asm.*;
+
+public class AMD64BinaryPatchOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64BinaryPatchOp> TYPE = LIRInstructionClass.create(AMD64BinaryPatchOp.class);
+
+    @Opcode private final AMD64RMOp opcode;
+    private final OperandSize size;
+
+    @Def({REG, HINT}) protected AllocatableValue result;
+    @Use({REG, STACK}) protected AllocatableValue x;
+    protected JavaConstant y;
+
+    private final int alignment;
+
+    public AMD64BinaryPatchOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y) {
+        this(opcode, size, result, x, y, y.getKind().getByteCount());
+    }
+
+    public AMD64BinaryPatchOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y, int alignment) {
+        super(TYPE);
+        this.opcode = opcode;
+        this.size = size;
+
+        this.result = result;
+        this.x = x;
+        this.y = y;
+
+        this.alignment = alignment;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        AMD64Move.move(crb, masm, result, x);
+        opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.recordDataReferenceInCode(y, alignment));
+    }
+}
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BitManipulationOp.java	Tue Mar 17 12:05:11 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,125 +0,0 @@
-/*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.lir.amd64;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.asm.amd64.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.asm.*;
-
-public final class AMD64BitManipulationOp extends AMD64LIRInstruction {
-    public static final LIRInstructionClass<AMD64BitManipulationOp> TYPE = LIRInstructionClass.create(AMD64BitManipulationOp.class);
-
-    public enum IntrinsicOpcode {
-        IPOPCNT,
-        LPOPCNT,
-        IBSR,
-        LBSR,
-        BSF,
-        ILZCNT,
-        LLZCNT,
-        ITZCNT,
-        LTZCNT
-    }
-
-    @Opcode private final IntrinsicOpcode opcode;
-    @Def protected AllocatableValue result;
-    @Use({OperandFlag.REG, OperandFlag.STACK}) protected AllocatableValue input;
-
-    public AMD64BitManipulationOp(IntrinsicOpcode opcode, AllocatableValue result, AllocatableValue input) {
-        super(TYPE);
-        this.opcode = opcode;
-        this.result = result;
-        this.input = input;
-    }
-
-    @Override
-    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-        Register dst = ValueUtil.asIntReg(result);
-        if (ValueUtil.isRegister(input)) {
-            Register src = ValueUtil.asRegister(input);
-            switch (opcode) {
-                case IPOPCNT:
-                    masm.popcntl(dst, src);
-                    break;
-                case LPOPCNT:
-                    masm.popcntq(dst, src);
-                    break;
-                case BSF:
-                    masm.bsfq(dst, src);
-                    break;
-                case IBSR:
-                    masm.bsrl(dst, src);
-                    break;
-                case LBSR:
-                    masm.bsrq(dst, src);
-                    break;
-                case ILZCNT:
-                    masm.lzcntl(dst, src);
-                    break;
-                case LLZCNT:
-                    masm.lzcntq(dst, src);
-                    break;
-                case ITZCNT:
-                    masm.tzcntl(dst, src);
-                    break;
-                case LTZCNT:
-                    masm.tzcntq(dst, src);
-                    break;
-            }
-        } else {
-            AMD64Address src = (AMD64Address) crb.asAddress(input);
-            switch (opcode) {
-                case IPOPCNT:
-                    masm.popcntl(dst, src);
-                    break;
-                case LPOPCNT:
-                    masm.popcntq(dst, src);
-                    break;
-                case BSF:
-                    masm.bsfq(dst, src);
-                    break;
-                case IBSR:
-                    masm.bsrl(dst, src);
-                    break;
-                case LBSR:
-                    masm.bsrq(dst, src);
-                    break;
-                case ILZCNT:
-                    masm.lzcntl(dst, src);
-                    break;
-                case LLZCNT:
-                    masm.lzcntq(dst, src);
-                    break;
-                case ITZCNT:
-                    masm.tzcntl(dst, src);
-                    break;
-                case LTZCNT:
-                    masm.tzcntq(dst, src);
-                    break;
-            }
-        }
-    }
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ClearRegisterOp.java	Tue Mar 17 12:05:51 2015 +0100
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.amd64;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp;
+import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.asm.*;
+
+public class AMD64ClearRegisterOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64ClearRegisterOp> TYPE = LIRInstructionClass.create(AMD64ClearRegisterOp.class);
+
+    @Opcode private final AMD64RMOp op;
+    private final OperandSize size;
+
+    @Def({REG}) protected AllocatableValue result;
+
+    public AMD64ClearRegisterOp(OperandSize size, AllocatableValue result) {
+        super(TYPE);
+        this.op = XOR.getRMOpcode(size);
+        this.size = size;
+        this.result = result;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        op.emit(masm, size, asRegister(result), asRegister(result));
+    }
+}
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Compare.java	Tue Mar 17 12:05:11 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,263 +0,0 @@
-/*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.lir.amd64;
-
-import static com.oracle.graal.api.code.ValueUtil.*;
-import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.asm.*;
-import com.oracle.graal.asm.amd64.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.amd64.AMD64Move.MemOp;
-import com.oracle.graal.lir.asm.*;
-
-public enum AMD64Compare {
-    BCMP,
-    SCMP,
-    ICMP,
-    LCMP,
-    ACMP,
-    FCMP,
-    DCMP;
-
-    public static final class CompareOp extends AMD64LIRInstruction {
-        public static final LIRInstructionClass<CompareOp> TYPE = LIRInstructionClass.create(CompareOp.class);
-        @Opcode private final AMD64Compare opcode;
-        @Use({REG}) protected Value x;
-        @Use({REG, STACK, CONST}) protected Value y;
-
-        public CompareOp(AMD64Compare opcode, Value x, Value y) {
-            super(TYPE);
-            this.opcode = opcode;
-            this.x = x;
-            this.y = y;
-        }
-
-        @Override
-        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-            emit(crb, masm, opcode, x, y);
-        }
-
-        @Override
-        public void verify() {
-            super.verify();
-            assert (name().startsWith("B") && x.getKind().getStackKind() == Kind.Int && y.getKind().getStackKind() == Kind.Int) ||
-                            (name().startsWith("S") && x.getKind().getStackKind() == Kind.Int && y.getKind().getStackKind() == Kind.Int) ||
-                            (name().startsWith("I") && x.getKind() == Kind.Int && y.getKind() == Kind.Int) || (name().startsWith("L") && x.getKind() == Kind.Long && y.getKind() == Kind.Long) ||
-                            (name().startsWith("A") && x.getKind() == Kind.Object && y.getKind() == Kind.Object) ||
-                            (name().startsWith("F") && x.getKind() == Kind.Float && y.getKind() == Kind.Float) || (name().startsWith("D") && x.getKind() == Kind.Double && y.getKind() == Kind.Double) : String.format(
-                            "%s(%s, %s)", opcode, x, y);
-        }
-    }
-
-    public static final class CompareMemoryOp extends MemOp {
-        public static final LIRInstructionClass<CompareMemoryOp> TYPE = LIRInstructionClass.create(CompareMemoryOp.class);
-        @Opcode private final AMD64Compare opcode;
-        @Use({REG, CONST}) protected Value y;
-
-        /**
-         * Compare memory, constant or register, memory.
-         */
-        public CompareMemoryOp(AMD64Compare opcode, Kind kind, AMD64AddressValue address, Value y, LIRFrameState state) {
-            super(TYPE, kind, address, state);
-            this.opcode = opcode;
-            this.y = y;
-        }
-
-        @Override
-        protected void emitMemAccess(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-            if (isRegister(y)) {
-                switch (opcode) {
-                    case BCMP:
-                        masm.cmpb(asIntReg(y), address.toAddress());
-                        break;
-                    case SCMP:
-                        masm.cmpw(asIntReg(y), address.toAddress());
-                        break;
-                    case ICMP:
-                        masm.cmpl(asIntReg(y), address.toAddress());
-                        break;
-                    case LCMP:
-                        masm.cmpq(asLongReg(y), address.toAddress());
-                        break;
-                    case ACMP:
-                        masm.cmpptr(asObjectReg(y), address.toAddress());
-                        break;
-                    case FCMP:
-                        masm.ucomiss(asFloatReg(y), address.toAddress());
-                        break;
-                    case DCMP:
-                        masm.ucomisd(asDoubleReg(y), address.toAddress());
-                        break;
-                    default:
-                        throw GraalInternalError.shouldNotReachHere();
-                }
-            } else if (isConstant(y)) {
-                switch (opcode) {
-                    case BCMP:
-                        masm.cmpb(address.toAddress(), crb.asIntConst(y));
-                        break;
-                    case SCMP:
-                        masm.cmpw(address.toAddress(), crb.asIntConst(y));
-                        break;
-                    case ICMP:
-                        masm.cmpl(address.toAddress(), crb.asIntConst(y));
-                        break;
-                    case LCMP:
-                        if (NumUtil.isInt(crb.asLongConst(y))) {
-                            masm.cmpq(address.toAddress(), (int) crb.asLongConst(y));
-                        } else {
-                            throw GraalInternalError.shouldNotReachHere();
-                        }
-                        break;
-                    case ACMP:
-                        if (asConstant(y).isNull()) {
-                            masm.cmpq(address.toAddress(), 0);
-                        } else {
-                            throw GraalInternalError.shouldNotReachHere();
-                        }
-                        break;
-                    default:
-                        throw GraalInternalError.shouldNotReachHere();
-                }
-
-            } else {
-                throw GraalInternalError.shouldNotReachHere();
-            }
-        }
-
-        @Override
-        public void verify() {
-            super.verify();
-            assert y instanceof Variable || y instanceof JavaConstant;
-            assert kind != Kind.Long || !(y instanceof JavaConstant) || NumUtil.isInt(((JavaConstant) y).asLong());
-        }
-    }
-
-    public static void emit(CompilationResultBuilder crb, AMD64MacroAssembler masm, AMD64Compare opcode, Value x, Value y) {
-        if (isRegister(x) && isRegister(y)) {
-            switch (opcode) {
-                case BCMP:
-                    masm.cmpb(asIntReg(x), asIntReg(y));
-                    break;
-                case SCMP:
-                    masm.cmpw(asIntReg(x), asIntReg(y));
-                    break;
-                case ICMP:
-                    masm.cmpl(asIntReg(x), asIntReg(y));
-                    break;
-                case LCMP:
-                    masm.cmpq(asLongReg(x), asLongReg(y));
-                    break;
-                case ACMP:
-                    masm.cmpptr(asObjectReg(x), asObjectReg(y));
-                    break;
-                case FCMP:
-                    masm.ucomiss(asFloatReg(x), asFloatReg(y));
-                    break;
-                case DCMP:
-                    masm.ucomisd(asDoubleReg(x), asDoubleReg(y));
-                    break;
-                default:
-                    throw GraalInternalError.shouldNotReachHere();
-            }
-        } else if (isRegister(x) && isConstant(y)) {
-            boolean isZero = ((JavaConstant) y).isDefaultForKind();
-            switch (opcode) {
-                case BCMP:
-                    if (isZero) {
-                        masm.testl(asIntReg(x), asIntReg(x));
-                    } else {
-                        masm.cmpb(asIntReg(x), crb.asIntConst(y));
-                    }
-                    break;
-                case SCMP:
-                    if (isZero) {
-                        masm.testl(asIntReg(x), asIntReg(x));
-                    } else {
-                        masm.cmpw(asIntReg(x), crb.asIntConst(y));
-                    }
-                    break;
-                case ICMP:
-                    if (isZero) {
-                        masm.testl(asIntReg(x), asIntReg(x));
-                    } else {
-                        masm.cmpl(asIntReg(x), crb.asIntConst(y));
-                    }
-                    break;
-                case LCMP:
-                    if (isZero) {
-                        masm.testq(asLongReg(x), asLongReg(x));
-                    } else {
-                        masm.cmpq(asLongReg(x), crb.asIntConst(y));
-                    }
-                    break;
-                case ACMP:
-                    if (isZero) {
-                        masm.testq(asObjectReg(x), asObjectReg(x));
-                        break;
-                    } else {
-                        throw GraalInternalError.shouldNotReachHere("Only null object constants are allowed in comparisons");
-                    }
-                case FCMP:
-                    masm.ucomiss(asFloatReg(x), (AMD64Address) crb.asFloatConstRef(y));
-                    break;
-                case DCMP:
-                    masm.ucomisd(asDoubleReg(x), (AMD64Address) crb.asDoubleConstRef(y));
-                    break;
-                default:
-                    throw GraalInternalError.shouldNotReachHere();
-            }
-        } else if (isRegister(x) && isStackSlot(y)) {
-            switch (opcode) {
-                case BCMP:
-                    masm.cmpb(asIntReg(x), (AMD64Address) crb.asByteAddr(y));
-                    break;
-                case SCMP:
-                    masm.cmpw(asIntReg(x), (AMD64Address) crb.asShortAddr(y));
-                    break;
-                case ICMP:
-                    masm.cmpl(asIntReg(x), (AMD64Address) crb.asIntAddr(y));
-                    break;
-                case LCMP:
-                    masm.cmpq(asLongReg(x), (AMD64Address) crb.asLongAddr(y));
-                    break;
-                case ACMP:
-                    masm.cmpptr(asObjectReg(x), (AMD64Address) crb.asObjectAddr(y));
-                    break;
-                case FCMP:
-                    masm.ucomiss(asFloatReg(x), (AMD64Address) crb.asFloatAddr(y));
-                    break;
-                case DCMP:
-                    masm.ucomisd(asDoubleReg(x), (AMD64Address) crb.asDoubleAddr(y));
-                    break;
-                default:
-                    throw GraalInternalError.shouldNotReachHere();
-            }
-        } else {
-            throw GraalInternalError.shouldNotReachHere();
-        }
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64CompareConstOp.java	Tue Mar 17 12:05:51 2015 +0100
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.amd64;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.*;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MIOp;
+import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.asm.*;
+
+public class AMD64CompareConstOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64CompareConstOp> TYPE = LIRInstructionClass.create(AMD64CompareConstOp.class);
+
+    @Opcode private final AMD64MIOp opcode;
+    private final OperandSize size;
+
+    @Use({REG, STACK}) protected AllocatableValue x;
+    protected JavaConstant y;
+
+    public AMD64CompareConstOp(AMD64MIOp opcode, OperandSize size, AllocatableValue x, JavaConstant y) {
+        super(TYPE);
+        this.opcode = opcode;
+        this.size = size;
+
+        this.x = x;
+        this.y = y;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        assert NumUtil.is32bit(y.asLong());
+        if (isRegister(x)) {
+            opcode.emit(masm, size, asRegister(x), (int) y.asLong());
+        } else {
+            assert isStackSlot(x);
+            opcode.emit(masm, size, (AMD64Address) crb.asAddress(x), (int) y.asLong());
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64CompareMemoryConstOp.java	Tue Mar 17 12:05:51 2015 +0100
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.amd64;
+
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.*;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MIOp;
+import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.ImplicitNullCheck;
+import com.oracle.graal.lir.asm.*;
+
+public class AMD64CompareMemoryConstOp extends AMD64LIRInstruction implements ImplicitNullCheck {
+    public static final LIRInstructionClass<AMD64CompareMemoryConstOp> TYPE = LIRInstructionClass.create(AMD64CompareMemoryConstOp.class);
+
+    @Opcode private final AMD64MIOp opcode;
+    private final OperandSize size;
+
+    @Use({COMPOSITE}) protected AMD64AddressValue x;
+    protected JavaConstant y;
+
+    @State protected LIRFrameState state;
+
+    public AMD64CompareMemoryConstOp(AMD64MIOp opcode, OperandSize size, AMD64AddressValue x, JavaConstant y, LIRFrameState state) {
+        super(TYPE);
+        this.opcode = opcode;
+        this.size = size;
+
+        this.x = x;
+        this.y = y;
+
+        this.state = state;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        if (state != null) {
+            crb.recordImplicitException(masm.position(), state);
+        }
+        assert NumUtil.is32bit(y.asLong());
+        opcode.emit(masm, size, x.toAddress(), (int) y.asLong());
+    }
+
+    @Override
+    public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) {
+        if (state == null && x.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) {
+            state = nullCheckState;
+            return true;
+        }
+        return false;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64CompareMemoryOp.java	Tue Mar 17 12:05:51 2015 +0100
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.amd64;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp;
+import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.ImplicitNullCheck;
+import com.oracle.graal.lir.asm.*;
+
+public class AMD64CompareMemoryOp extends AMD64LIRInstruction implements ImplicitNullCheck {
+    public static final LIRInstructionClass<AMD64CompareMemoryOp> TYPE = LIRInstructionClass.create(AMD64CompareMemoryOp.class);
+
+    @Opcode private final AMD64RMOp opcode;
+    private final OperandSize size;
+
+    @Use({REG}) protected AllocatableValue x;
+    @Use({COMPOSITE}) protected AMD64AddressValue y;
+
+    @State protected LIRFrameState state;
+
+    public AMD64CompareMemoryOp(AMD64RMOp opcode, OperandSize size, AllocatableValue x, AMD64AddressValue y, LIRFrameState state) {
+        super(TYPE);
+        this.opcode = opcode;
+        this.size = size;
+
+        this.x = x;
+        this.y = y;
+
+        this.state = state;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        if (state != null) {
+            crb.recordImplicitException(masm.position(), state);
+        }
+        opcode.emit(masm, size, asRegister(x), y.toAddress());
+    }
+
+    @Override
+    public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) {
+        if (state == null && y.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) {
+            state = nullCheckState;
+            return true;
+        }
+        return false;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64CompareOp.java	Tue Mar 17 12:05:51 2015 +0100
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.amd64;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp;
+import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.asm.*;
+
+public class AMD64CompareOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64CompareOp> TYPE = LIRInstructionClass.create(AMD64CompareOp.class);
+
+    @Opcode private final AMD64RMOp opcode;
+    private final OperandSize size;
+
+    @Use({REG}) protected AllocatableValue x;
+    @Use({REG, STACK}) protected AllocatableValue y;
+
+    public AMD64CompareOp(AMD64RMOp opcode, OperandSize size, AllocatableValue x, AllocatableValue y) {
+        super(TYPE);
+        this.opcode = opcode;
+        this.size = size;
+
+        this.x = x;
+        this.y = y;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        if (isRegister(y)) {
+            opcode.emit(masm, size, asRegister(x), asRegister(y));
+        } else {
+            assert isStackSlot(y);
+            opcode.emit(masm, size, asRegister(x), (AMD64Address) crb.asAddress(y));
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64MulConstOp.java	Tue Mar 17 12:05:51 2015 +0100
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.amd64;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.*;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMIOp;
+import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.asm.*;
+
+public class AMD64MulConstOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64MulConstOp> TYPE = LIRInstructionClass.create(AMD64MulConstOp.class);
+
+    @Opcode private final AMD64RMIOp opcode;
+    private final OperandSize size;
+
+    @Def({REG}) protected AllocatableValue result;
+    @Use({REG, STACK}) protected AllocatableValue x;
+    protected JavaConstant y;
+
+    public AMD64MulConstOp(AMD64RMIOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y) {
+        super(TYPE);
+        this.opcode = opcode;
+        this.size = size;
+
+        this.result = result;
+        this.x = x;
+        this.y = y;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        assert NumUtil.isInt(y.asLong());
+        int imm = (int) y.asLong();
+        if (isRegister(x)) {
+            opcode.emit(masm, size, asRegister(result), asRegister(x), imm);
+        } else {
+            assert isStackSlot(x);
+            opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(x), imm);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64MulDivOp.java	Tue Mar 17 12:05:51 2015 +0100
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.amd64;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MOp.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.amd64.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MOp;
+import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.asm.*;
+
+public class AMD64MulDivOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64MulDivOp> TYPE = LIRInstructionClass.create(AMD64MulDivOp.class);
+
+    @Opcode private final AMD64MOp opcode;
+    private final OperandSize size;
+
+    @Def({REG}) protected AllocatableValue highResult;
+    @Def({REG}) protected AllocatableValue lowResult;
+
+    @Use({REG, ILLEGAL}) protected AllocatableValue highX;
+    @Use({REG}) protected AllocatableValue lowX;
+
+    @Use({REG, STACK}) protected AllocatableValue y;
+
+    @State protected LIRFrameState state;
+
+    public AMD64MulDivOp(AMD64MOp opcode, OperandSize size, LIRKind resultKind, AllocatableValue x, AllocatableValue y) {
+        this(opcode, size, resultKind, Value.ILLEGAL, x, y, null);
+    }
+
+    public AMD64MulDivOp(AMD64MOp opcode, OperandSize size, LIRKind resultKind, AllocatableValue highX, AllocatableValue lowX, AllocatableValue y, LIRFrameState state) {
+        super(TYPE);
+        this.opcode = opcode;
+        this.size = size;
+
+        this.highResult = AMD64.rdx.asValue(resultKind);
+        this.lowResult = AMD64.rax.asValue(resultKind);
+
+        this.highX = highX;
+        this.lowX = lowX;
+
+        this.y = y;
+
+        this.state = state;
+    }
+
+    public AllocatableValue getHighResult() {
+        return highResult;
+    }
+
+    public AllocatableValue getLowResult() {
+        return lowResult;
+    }
+
+    public AllocatableValue getQuotient() {
+        return lowResult;
+    }
+
+    public AllocatableValue getRemainder() {
+        return highResult;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        if (state != null) {
+            crb.recordImplicitException(masm.position(), state);
+        }
+        if (isRegister(y)) {
+            opcode.emit(masm, size, asRegister(y));
+        } else {
+            assert isStackSlot(y);
+            opcode.emit(masm, size, (AMD64Address) crb.asAddress(y));
+        }
+    }
+
+    @Override
+    public void verify() {
+        assert asRegister(highResult).equals(AMD64.rdx);
+        assert asRegister(lowResult).equals(AMD64.rax);
+
+        assert asRegister(lowX).equals(AMD64.rax);
+        if (opcode == DIV || opcode == IDIV) {
+            assert asRegister(highX).equals(AMD64.rdx);
+        } else if (opcode == MUL || opcode == IMUL) {
+            assert isIllegal(highX);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64RegStackConstOp.java	Tue Mar 17 12:05:51 2015 +0100
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.amd64;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.*;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMIOp;
+import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.asm.*;
+
+public class AMD64RegStackConstOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64RegStackConstOp> TYPE = LIRInstructionClass.create(AMD64RegStackConstOp.class);
+
+    @Opcode private final AMD64RMIOp opcode;
+    private final OperandSize size;
+
+    @Def({REG}) protected AllocatableValue result;
+    @Use({REG, STACK}) protected AllocatableValue x;
+    protected JavaConstant y;
+
+    public AMD64RegStackConstOp(AMD64RMIOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y) {
+        super(TYPE);
+        this.opcode = opcode;
+        this.size = size;
+
+        this.result = result;
+        this.x = x;
+        this.y = y;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        assert NumUtil.is32bit(y.asLong());
+        if (isRegister(x)) {
+            opcode.emit(masm, size, asRegister(result), asRegister(x), (int) y.asLong());
+        } else {
+            assert isStackSlot(x);
+            opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(x), (int) y.asLong());
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ShiftOp.java	Tue Mar 17 12:05:51 2015 +0100
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.amd64;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.amd64.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MOp;
+import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.asm.*;
+
+public class AMD64ShiftOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64ShiftOp> TYPE = LIRInstructionClass.create(AMD64ShiftOp.class);
+
+    @Opcode private final AMD64MOp opcode;
+    private final OperandSize size;
+
+    @Def({REG, HINT}) protected AllocatableValue result;
+    @Use({REG, STACK}) protected AllocatableValue x;
+    @Alive({REG}) protected AllocatableValue y;
+
+    public AMD64ShiftOp(AMD64MOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AllocatableValue y) {
+        super(TYPE);
+        this.opcode = opcode;
+        this.size = size;
+
+        this.result = result;
+        this.x = x;
+        this.y = y;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        AMD64Move.move(crb, masm, result, x);
+        opcode.emit(masm, size, asRegister(result));
+    }
+
+    @Override
+    public void verify() {
+        assert asRegister(y).equals(AMD64.rcx);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64SignExtendOp.java	Tue Mar 17 12:05:51 2015 +0100
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.amd64;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.amd64.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.asm.*;
+
+@Opcode("CDQ")
+public class AMD64SignExtendOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64SignExtendOp> TYPE = LIRInstructionClass.create(AMD64SignExtendOp.class);
+
+    private final OperandSize size;
+
+    @Def({REG}) protected AllocatableValue highResult;
+    @Def({REG}) protected AllocatableValue lowResult;
+
+    @Use({REG}) protected AllocatableValue input;
+
+    public AMD64SignExtendOp(OperandSize size, LIRKind resultKind, AllocatableValue input) {
+        super(TYPE);
+        this.size = size;
+
+        this.highResult = AMD64.rdx.asValue(resultKind);
+        this.lowResult = AMD64.rax.asValue(resultKind);
+        this.input = input;
+    }
+
+    public AllocatableValue getHighResult() {
+        return highResult;
+    }
+
+    public AllocatableValue getLowResult() {
+        return lowResult;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        if (size == DWORD) {
+            masm.cdql();
+        } else {
+            assert size == QWORD;
+            masm.cdqq();
+        }
+    }
+
+    @Override
+    public void verify() {
+        assert asRegister(highResult).equals(AMD64.rdx);
+        assert asRegister(lowResult).equals(AMD64.rax);
+        assert asRegister(input).equals(AMD64.rax);
+    }
+}
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64TestMemoryOp.java	Tue Mar 17 12:05:11 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,80 +0,0 @@
-/*
- * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.lir.amd64;
-
-import static com.oracle.graal.api.code.ValueUtil.*;
-import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.asm.amd64.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.amd64.AMD64Move.MemOp;
-import com.oracle.graal.lir.asm.*;
-
-public final class AMD64TestMemoryOp extends MemOp {
-    public static final LIRInstructionClass<AMD64TestMemoryOp> TYPE = LIRInstructionClass.create(AMD64TestMemoryOp.class);
-
-    @Use({REG, CONST}) protected Value y;
-
-    public AMD64TestMemoryOp(Kind kind, AMD64AddressValue x, Value y, LIRFrameState state) {
-        super(TYPE, kind, x, state);
-        this.y = y;
-        this.state = state;
-    }
-
-    @Override
-    public void emitMemAccess(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-        if (isRegister(y)) {
-            switch (kind) {
-                case Int:
-                    masm.testl(asIntReg(y), address.toAddress());
-                    break;
-                case Long:
-                    masm.testq(asLongReg(y), address.toAddress());
-                    break;
-                default:
-                    throw GraalInternalError.shouldNotReachHere();
-            }
-        } else if (isConstant(y)) {
-            switch (kind) {
-                case Int:
-                    masm.testl(address.toAddress(), crb.asIntConst(y));
-                    break;
-                case Long:
-                    masm.testq(address.toAddress(), crb.asIntConst(y));
-                    break;
-                default:
-                    throw GraalInternalError.shouldNotReachHere();
-            }
-        } else {
-            throw GraalInternalError.shouldNotReachHere();
-        }
-    }
-
-    @Override
-    public void verify() {
-        super.verify();
-        assert (kind == Kind.Int || kind == Kind.Long) && kind == y.getKind() : address + " " + y;
-    }
-}
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64TestOp.java	Tue Mar 17 12:05:11 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +0,0 @@
-/*
- * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.lir.amd64;
-
-import static com.oracle.graal.api.code.ValueUtil.*;
-import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.asm.amd64.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.asm.*;
-
-public final class AMD64TestOp extends AMD64LIRInstruction {
-    public static final LIRInstructionClass<AMD64TestOp> TYPE = LIRInstructionClass.create(AMD64TestOp.class);
-
-    @Use({REG}) protected Value x;
-    @Use({REG, STACK, CONST}) protected Value y;
-
-    public AMD64TestOp(Value x, Value y) {
-        super(TYPE);
-        this.x = x;
-        this.y = y;
-    }
-
-    @Override
-    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-        emit(crb, masm, x, y);
-    }
-
-    @Override
-    public void verify() {
-        super.verify();
-        assert (x.getKind() == Kind.Int && y.getKind().getStackKind() == Kind.Int) || (x.getKind() == Kind.Long && y.getKind() == Kind.Long) : x + " " + y;
-    }
-
-    public static void emit(CompilationResultBuilder crb, AMD64MacroAssembler masm, Value x, Value y) {
-        if (isRegister(y)) {
-            switch (x.getKind()) {
-                case Int:
-                    masm.testl(asIntReg(x), asIntReg(y));
-                    break;
-                case Long:
-                    masm.testq(asLongReg(x), asLongReg(y));
-                    break;
-                default:
-                    throw GraalInternalError.shouldNotReachHere();
-            }
-        } else if (isConstant(y)) {
-            switch (x.getKind()) {
-                case Int:
-                    masm.testl(asIntReg(x), crb.asIntConst(y));
-                    break;
-                case Long:
-                    masm.testq(asLongReg(x), crb.asIntConst(y));
-                    break;
-                default:
-                    throw GraalInternalError.shouldNotReachHere();
-            }
-        } else {
-            switch (x.getKind()) {
-                case Int:
-                    masm.testl(asIntReg(x), (AMD64Address) crb.asIntAddr(y));
-                    break;
-                case Long:
-                    masm.testq(asLongReg(x), (AMD64Address) crb.asLongAddr(y));
-                    break;
-                default:
-                    throw GraalInternalError.shouldNotReachHere();
-            }
-        }
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64UnaryMOp.java	Tue Mar 17 12:05:51 2015 +0100
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.amd64;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MOp;
+import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.asm.*;
+
+public class AMD64UnaryMOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64UnaryMOp> TYPE = LIRInstructionClass.create(AMD64UnaryMOp.class);
+
+    @Opcode private final AMD64MOp opcode;
+    private final OperandSize size;
+
+    @Def({REG, HINT}) protected AllocatableValue result;
+    @Use({REG, STACK}) protected AllocatableValue value;
+
+    public AMD64UnaryMOp(AMD64MOp opcode, OperandSize size, AllocatableValue result, AllocatableValue value) {
+        super(TYPE);
+        this.opcode = opcode;
+        this.size = size;
+
+        this.result = result;
+        this.value = value;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        AMD64Move.move(crb, masm, result, value);
+        opcode.emit(masm, size, asRegister(result));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64UnaryMROp.java	Tue Mar 17 12:05:51 2015 +0100
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.amd64;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MROp;
+import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.asm.*;
+
+public class AMD64UnaryMROp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64UnaryMROp> TYPE = LIRInstructionClass.create(AMD64UnaryMROp.class);
+
+    @Opcode private final AMD64MROp opcode;
+    private final OperandSize size;
+
+    @Def({REG, STACK}) protected AllocatableValue result;
+    @Use({REG}) protected AllocatableValue value;
+
+    public AMD64UnaryMROp(AMD64MROp opcode, OperandSize size, AllocatableValue result, AllocatableValue value) {
+        super(TYPE);
+        this.opcode = opcode;
+        this.size = size;
+
+        this.result = result;
+        this.value = value;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        if (isRegister(result)) {
+            opcode.emit(masm, size, asRegister(result), asRegister(value));
+        } else {
+            assert isStackSlot(result);
+            opcode.emit(masm, size, (AMD64Address) crb.asAddress(result), asRegister(value));
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64UnaryMemoryOp.java	Tue Mar 17 12:05:51 2015 +0100
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.amd64;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp;
+import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.ImplicitNullCheck;
+import com.oracle.graal.lir.asm.*;
+
+public class AMD64UnaryMemoryOp extends AMD64LIRInstruction implements ImplicitNullCheck {
+    public static final LIRInstructionClass<AMD64UnaryMemoryOp> TYPE = LIRInstructionClass.create(AMD64UnaryMemoryOp.class);
+
+    @Opcode private final AMD64RMOp opcode;
+    private final OperandSize size;
+
+    @Def({REG}) protected AllocatableValue result;
+    @Use({COMPOSITE}) protected AMD64AddressValue input;
+
+    @State protected LIRFrameState state;
+
+    public AMD64UnaryMemoryOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AMD64AddressValue input, LIRFrameState state) {
+        super(TYPE);
+        this.opcode = opcode;
+        this.size = size;
+
+        this.result = result;
+        this.input = input;
+
+        this.state = state;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        if (state != null) {
+            crb.recordImplicitException(masm.position(), state);
+        }
+        opcode.emit(masm, size, asRegister(result), input.toAddress());
+    }
+
+    public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) {
+        if (state == null && input.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) {
+            state = nullCheckState;
+            return true;
+        }
+        return false;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64UnaryRMOp.java	Tue Mar 17 12:05:51 2015 +0100
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.amd64;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp;
+import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.asm.*;
+
+public class AMD64UnaryRMOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64UnaryRMOp> TYPE = LIRInstructionClass.create(AMD64UnaryRMOp.class);
+
+    @Opcode private final AMD64RMOp opcode;
+    private final OperandSize size;
+
+    @Def({REG}) protected AllocatableValue result;
+    @Use({REG, STACK}) protected AllocatableValue value;
+
+    public AMD64UnaryRMOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue value) {
+        super(TYPE);
+        this.opcode = opcode;
+        this.size = size;
+
+        this.result = result;
+        this.value = value;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        if (isRegister(value)) {
+            opcode.emit(masm, size, asRegister(result), asRegister(value));
+        } else {
+            assert isStackSlot(value);
+            opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(value));
+        }
+    }
+}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilder.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilder.java	Tue Mar 17 12:05:51 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, 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
@@ -162,7 +162,7 @@
         compilationResult.recordInfopoint(pos, debugInfo, reason);
     }
 
-    public void recordInlineDataInCode(JavaConstant data) {
+    public void recordInlineDataInCode(Constant data) {
         assert data != null;
         int pos = asm.position();
         Debug.log("Inline data in code: pos = %d, data = %s", pos, data);
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerator.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerator.java	Tue Mar 17 12:05:51 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2015, 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
@@ -177,13 +177,14 @@
         return res.getFrameMapBuilder().getRegisterConfig().getReturnRegister((Kind) kind.getPlatformKind()).asValue(kind);
     }
 
-    public void append(LIRInstruction op) {
+    public <I extends LIRInstruction> I append(I op) {
         if (Options.PrintIRWithLIR.getValue() && !TTY.isSuppressed()) {
             TTY.println(op.toStringWithIdPrefix());
             TTY.println();
         }
         assert LIRVerifier.verify(op);
         res.getLIR().getLIRforBlock(currentBlock).add(op);
+        return op;
     }
 
     public boolean hasBlockEnd(AbstractBlockBase<?> block) {
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGeneratorTool.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGeneratorTool.java	Tue Mar 17 12:05:51 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, 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
@@ -159,7 +159,7 @@
      */
     AllocatableValue resultOperandFor(LIRKind kind);
 
-    void append(LIRInstruction op);
+    <I extends LIRInstruction> I append(I op);
 
     void emitJump(LabelRef label);
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java	Tue Mar 17 12:05:51 2015 +0100
@@ -28,7 +28,6 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.nodeinfo.*;
@@ -42,7 +41,6 @@
 public final class ConstantNode extends FloatingNode implements LIRLowerable {
 
     public static final NodeClass<ConstantNode> TYPE = NodeClass.create(ConstantNode.class);
-    private static final DebugMetric ConstantNodes = Debug.metric("ConstantNodes");
 
     protected final Constant value;
 
@@ -60,7 +58,6 @@
         super(TYPE, stamp);
         assert stamp != null && isCompatible(value, stamp);
         this.value = value;
-        ConstantNodes.increment();
     }
 
     private static boolean isCompatible(Constant value, Stamp stamp) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java	Tue Mar 17 12:05:51 2015 +0100
@@ -107,7 +107,7 @@
 
     @Override
     public LocationIdentity getLocationIdentity() {
-        return LocationIdentity.ANY_LOCATION;
+        return LocationIdentity.any();
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Tue Mar 17 12:05:51 2015 +0100
@@ -154,7 +154,7 @@
 
     @Override
     public LocationIdentity getLocationIdentity() {
-        return LocationIdentity.ANY_LOCATION;
+        return LocationIdentity.any();
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryMapNode.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryMapNode.java	Tue Mar 17 12:05:51 2015 +0100
@@ -76,7 +76,7 @@
         } else {
             int index = locationIdentities.indexOf(locationIdentity);
             if (index == -1) {
-                index = locationIdentities.indexOf(ANY_LOCATION);
+                index = locationIdentities.indexOf(any());
             }
             assert index != -1;
             return (MemoryNode) nodes.get(index);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StartNode.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StartNode.java	Tue Mar 17 12:05:51 2015 +0100
@@ -44,6 +44,6 @@
 
     @Override
     public LocationIdentity getLocationIdentity() {
-        return LocationIdentity.ANY_LOCATION;
+        return LocationIdentity.any();
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BinaryArithmeticNode.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BinaryArithmeticNode.java	Tue Mar 17 12:05:51 2015 +0100
@@ -246,7 +246,7 @@
 
     protected static boolean livesLonger(ValueNode after, ValueNode value, NodeMappableLIRBuilder builder) {
         for (Node usage : value.usages()) {
-            if (usage != after && usage instanceof ValueNode && builder.hasOperand(((ValueNode) usage))) {
+            if (usage != after && usage instanceof ValueNode && builder.hasOperand(usage)) {
                 return true;
             }
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java	Tue Mar 17 12:05:51 2015 +0100
@@ -24,9 +24,11 @@
 
 import java.util.*;
 
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 
 public final class Block extends AbstractBlockBase<Block> {
 
@@ -39,6 +41,8 @@
 
     protected Block postdominator;
     protected Block distancedDominatorCache;
+    private LocationSet killLocations;
+    private LocationSet killLocationsBetweenThisAndDominator;
 
     protected Block(AbstractBeginNode node) {
         this.beginNode = node;
@@ -189,4 +193,85 @@
         }
         return result;
     }
+
+    public boolean canKill(LocationIdentity location) {
+        if (location.isImmutable()) {
+            return false;
+        }
+        return getKillLocations().contains(location);
+    }
+
+    public LocationSet getKillLocations() {
+        if (killLocations == null) {
+            killLocations = calcKillLocations();
+        }
+        return killLocations;
+    }
+
+    private LocationSet calcKillLocations() {
+        LocationSet result = new LocationSet();
+        for (FixedNode node : this.getNodes()) {
+            if (node instanceof MemoryCheckpoint.Single) {
+                LocationIdentity identity = ((MemoryCheckpoint.Single) node).getLocationIdentity();
+                result.add(identity);
+            } else if (node instanceof MemoryCheckpoint.Multi) {
+                for (LocationIdentity identity : ((MemoryCheckpoint.Multi) node).getLocationIdentities()) {
+                    result.add(identity);
+                }
+            }
+            if (result.isAny()) {
+                break;
+            }
+        }
+        return result;
+    }
+
+    public boolean canKillBetweenThisAndDominator(LocationIdentity location) {
+        if (location.isImmutable()) {
+            return false;
+        }
+        return this.getKillLocationsBetweenThisAndDominator().contains(location);
+    }
+
+    private LocationSet getKillLocationsBetweenThisAndDominator() {
+        if (this.killLocationsBetweenThisAndDominator == null) {
+            LocationSet dominatorResult = new LocationSet();
+            Block stopBlock = getDominator();
+            for (Block b : this.getPredecessors()) {
+                if (b != stopBlock && (!this.isLoopHeader() || b.getLoopDepth() < this.getLoopDepth())) {
+                    dominatorResult.addAll(b.getKillLocations());
+                    if (dominatorResult.isAny()) {
+                        break;
+                    }
+                    b.calcKillLocationsBetweenThisAndTarget(dominatorResult, stopBlock);
+                    if (dominatorResult.isAny()) {
+                        break;
+                    }
+                }
+            }
+            this.killLocationsBetweenThisAndDominator = dominatorResult;
+        }
+        return this.killLocationsBetweenThisAndDominator;
+    }
+
+    private void calcKillLocationsBetweenThisAndTarget(LocationSet result, Block stopBlock) {
+        assert AbstractControlFlowGraph.dominates(stopBlock, this);
+        if (stopBlock == this || result.isAny()) {
+            // We reached the stop block => nothing to do.
+            return;
+        } else {
+            if (stopBlock == this.getDominator()) {
+                result.addAll(this.getKillLocationsBetweenThisAndDominator());
+            } else {
+                // Divide and conquer: Aggregate kill locations from this to the dominator and then
+                // from the dominator onwards.
+                calcKillLocationsBetweenThisAndTarget(result, this.getDominator());
+                result.addAll(this.getDominator().getKillLocations());
+                if (result.isAny()) {
+                    return;
+                }
+                this.getDominator().calcKillLocationsBetweenThisAndTarget(result, stopBlock);
+            }
+        }
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java	Tue Mar 17 12:05:51 2015 +0100
@@ -40,7 +40,7 @@
 
     public final StructuredGraph graph;
 
-    private final NodeMap<Block> nodeToBlock;
+    private NodeMap<Block> nodeToBlock;
     private List<Block> reversePostOrder;
     private List<Loop<Block>> loops;
 
@@ -365,4 +365,8 @@
         }
         return iterA;
     }
+
+    public void setNodeToBlock(NodeMap<Block> nodeMap) {
+        this.nodeToBlock = nodeMap;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/HIRLoop.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/HIRLoop.java	Tue Mar 17 12:05:51 2015 +0100
@@ -22,10 +22,13 @@
  */
 package com.oracle.graal.nodes.cfg;
 
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.nodes.*;
 
-public class HIRLoop extends Loop<Block> {
+public final class HIRLoop extends Loop<Block> {
+
+    private LocationSet killLocations;
 
     protected HIRLoop(Loop<Block> parent, int index, Block header) {
         super(parent, index, header);
@@ -35,4 +38,29 @@
     public long numBackedges() {
         return ((LoopBeginNode) getHeader().getBeginNode()).loopEnds().count();
     }
+
+    private LocationSet getKillLocations() {
+        if (killLocations == null) {
+            killLocations = new LocationSet();
+            for (Block b : this.getBlocks()) {
+                if (b.getLoop() == this) {
+                    killLocations.addAll(b.getKillLocations());
+                    if (killLocations.isAny()) {
+                        break;
+                    }
+                }
+            }
+        }
+        for (Loop<Block> child : this.getChildren()) {
+            if (killLocations.isAny()) {
+                break;
+            }
+            killLocations.addAll(((HIRLoop) child).getKillLocations());
+        }
+        return killLocations;
+    }
+
+    public boolean canKill(LocationIdentity location) {
+        return getKillLocations().contains(location);
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/LocationSet.java	Tue Mar 17 12:05:51 2015 +0100
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2015, 2015, 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.cfg;
+
+import java.util.*;
+
+import com.oracle.graal.api.meta.*;
+
+public class LocationSet {
+    private LocationIdentity firstLocation;
+    private List<LocationIdentity> list;
+
+    public LocationSet() {
+        list = null;
+    }
+
+    public LocationSet(LocationSet other) {
+        this.firstLocation = other.firstLocation;
+        if (other.list != null && other.list.size() > 0) {
+            list = new ArrayList<>(other.list);
+        }
+    }
+
+    private void initList() {
+        if (list == null) {
+            list = new ArrayList<>(4);
+        }
+    }
+
+    public boolean isEmpty() {
+        return firstLocation == null;
+    }
+
+    public boolean isAny() {
+        return firstLocation != null && firstLocation.isAny();
+    }
+
+    public void add(LocationIdentity location) {
+        if (this.isAny()) {
+            return;
+        } else if (location.isAny()) {
+            firstLocation = location;
+            list = null;
+        } else if (location.isImmutable()) {
+            return;
+        } else {
+            assert location.isMutable() && location.isSingle();
+            if (firstLocation == null) {
+                firstLocation = location;
+            } else if (location.equals(firstLocation)) {
+                return;
+            } else {
+                initList();
+                for (int i = 0; i < list.size(); ++i) {
+                    LocationIdentity value = list.get(i);
+                    if (location.equals(value)) {
+                        return;
+                    }
+                }
+                list.add(location);
+            }
+        }
+    }
+
+    public void addAll(LocationSet other) {
+        if (other.firstLocation != null) {
+            add(other.firstLocation);
+        }
+        List<LocationIdentity> otherList = other.list;
+        if (otherList != null) {
+            for (LocationIdentity l : otherList) {
+                add(l);
+            }
+        }
+    }
+
+    public boolean contains(LocationIdentity locationIdentity) {
+        assert locationIdentity.isSingle();
+        assert locationIdentity.isMutable();
+        if (LocationIdentity.any().equals(firstLocation)) {
+            return true;
+        }
+        if (locationIdentity.equals(firstLocation)) {
+            return true;
+        }
+        if (list != null) {
+            for (int i = 0; i < list.size(); ++i) {
+                LocationIdentity value = list.get(i);
+                if (locationIdentity.equals(value)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public List<LocationIdentity> getCopyAsList() {
+        ArrayList<LocationIdentity> result = new ArrayList<>();
+        if (firstLocation != null) {
+            result.add(firstLocation);
+        }
+        if (list != null) {
+            result.addAll(list);
+        }
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        if (this.isAny()) {
+            return "ANY";
+        } else if (this.isEmpty()) {
+            return "EMPTY";
+        } else {
+            List<LocationIdentity> copyAsList = getCopyAsList();
+            return Arrays.toString(copyAsList.toArray(new LocationIdentity[0]));
+        }
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BytecodeExceptionNode.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BytecodeExceptionNode.java	Tue Mar 17 12:05:51 2015 +0100
@@ -59,7 +59,7 @@
     }
 
     public LocationIdentity getLocationIdentity() {
-        return LocationIdentity.ANY_LOCATION;
+        return LocationIdentity.any();
     }
 
     public void lower(LoweringTool tool) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatableAccessNode.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatableAccessNode.java	Tue Mar 17 12:05:51 2015 +0100
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.nodes.extended;
 
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
@@ -56,6 +55,6 @@
      * an attached write barrier with pre-semantics can not also float.
      */
     public boolean canFloat() {
-        return !location().getLocationIdentity().equals(LocationIdentity.ANY_LOCATION) && getBarrierType() == BarrierType.NONE;
+        return location().getLocationIdentity().isSingle() && getBarrierType() == BarrierType.NONE;
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java	Tue Mar 17 12:05:51 2015 +0100
@@ -53,10 +53,6 @@
         this.foreignCalls = foreignCalls;
     }
 
-    public ForeignCallNode(ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, List<ValueNode> arguments) {
-        this(foreignCalls, descriptor, StampFactory.forKind(Kind.fromJavaClass(descriptor.getResultType())), arguments);
-    }
-
     public ForeignCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, Stamp stamp, List<ValueNode> arguments) {
         super(TYPE, stamp);
         this.arguments = new NodeInputList<>(this, arguments);
@@ -64,15 +60,15 @@
         this.foreignCalls = foreignCalls;
     }
 
-    protected ForeignCallNode(NodeClass<? extends ForeignCallNode> c, ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, Stamp stamp) {
-        super(c, stamp);
+    public ForeignCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, Stamp stamp) {
+        super(TYPE, stamp);
         this.arguments = new NodeInputList<>(this);
         this.descriptor = descriptor;
         this.foreignCalls = foreignCalls;
     }
 
-    public ForeignCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, Stamp stamp) {
-        super(TYPE, stamp);
+    protected ForeignCallNode(NodeClass<? extends ForeignCallNode> c, ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, Stamp stamp) {
+        super(c, stamp);
         this.arguments = new NodeInputList<>(this);
         this.descriptor = descriptor;
         this.foreignCalls = foreignCalls;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MembarNode.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MembarNode.java	Tue Mar 17 12:05:51 2015 +0100
@@ -45,7 +45,7 @@
 
     @Override
     public LocationIdentity getLocationIdentity() {
-        return LocationIdentity.ANY_LOCATION;
+        return LocationIdentity.any();
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryCheckpoint.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryCheckpoint.java	Tue Mar 17 12:05:51 2015 +0100
@@ -39,7 +39,7 @@
 
         /**
          * This method is used to determine which memory location is killed by this node. Returning
-         * the special value {@link LocationIdentity#ANY_LOCATION} will kill all memory locations.
+         * the special value {@link LocationIdentity#any()} will kill all memory locations.
          *
          * @return the identity of the location killed by this node.
          */
@@ -51,7 +51,7 @@
 
         /**
          * This method is used to determine which set of memory locations is killed by this node.
-         * Returning the special value {@link LocationIdentity#ANY_LOCATION} will kill all memory
+         * Returning the special value {@link LocationIdentity#any()} will kill all memory
          * locations.
          *
          * @return the identities of all locations killed by this node.
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java	Tue Mar 17 12:05:51 2015 +0100
@@ -28,17 +28,22 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo
-public final class UnboxNode extends UnaryNode implements Virtualizable, Lowerable {
+public final class UnboxNode extends FixedWithNextNode implements Virtualizable, Lowerable, Canonicalizable.Unary<ValueNode> {
 
     public static final NodeClass<UnboxNode> TYPE = NodeClass.create(UnboxNode.class);
+    @Input protected ValueNode value;
     protected final Kind boxingKind;
 
+    public ValueNode getValue() {
+        return value;
+    }
+
     protected UnboxNode(ValueNode value, Kind boxingKind) {
-        super(TYPE, StampFactory.forKind(boxingKind.getStackKind()), value);
+        super(TYPE, StampFactory.forKind(boxingKind.getStackKind()));
+        this.value = value;
         this.boxingKind = boxingKind;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeAccessNode.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeAccessNode.java	Tue Mar 17 12:05:51 2015 +0100
@@ -66,7 +66,7 @@
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
-        if (this.getLocationIdentity().equals(LocationIdentity.ANY_LOCATION) && offset().isConstant()) {
+        if (this.getLocationIdentity().isAny() && offset().isConstant()) {
             long constantOffset = offset().asJavaConstant().asLong();
 
             // Try to canonicalize to a field access.
@@ -82,7 +82,7 @@
                 }
             }
         }
-        if (this.getLocationIdentity().equals(LocationIdentity.ANY_LOCATION)) {
+        if (this.getLocationIdentity().isAny()) {
             ResolvedJavaType receiverType = StampTool.typeOrNull(object());
             // Try to build a better location identity.
             if (receiverType != null && receiverType.isArray()) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java	Tue Mar 17 12:05:51 2015 +0100
@@ -44,7 +44,7 @@
 
     @Override
     public LocationIdentity getLocationIdentity() {
-        return LocationIdentity.ANY_LOCATION;
+        return LocationIdentity.any();
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java	Tue Mar 17 12:05:51 2015 +0100
@@ -42,6 +42,15 @@
     @Input ValueNode object;
     @Input ValueNode mirror;
 
+    public static LogicNode create(ConstantReflectionProvider constantReflection, ValueNode mirror, ValueNode object) {
+        LogicNode synonym = findSynonym(constantReflection, object, mirror);
+        if (synonym != null) {
+            return synonym;
+        }
+        return new InstanceOfDynamicNode(mirror, object);
+
+    }
+
     public InstanceOfDynamicNode(ValueNode mirror, ValueNode object) {
         super(TYPE);
         this.mirror = mirror;
@@ -56,9 +65,9 @@
         tool.getLowerer().lower(this, tool);
     }
 
-    public LogicNode canonical(CanonicalizerTool tool, ValueNode forObject, ValueNode forMirror) {
+    private static LogicNode findSynonym(ConstantReflectionProvider constantReflection, ValueNode forObject, ValueNode forMirror) {
         if (forMirror.isConstant()) {
-            ResolvedJavaType t = tool.getConstantReflection().asJavaType(forMirror.asConstant());
+            ResolvedJavaType t = constantReflection.asJavaType(forMirror.asConstant());
             if (t != null) {
                 if (t.isPrimitive()) {
                     return LogicConstantNode.contradiction();
@@ -67,7 +76,15 @@
                 }
             }
         }
-        return this;
+        return null;
+    }
+
+    public LogicNode canonical(CanonicalizerTool tool, ValueNode forObject, ValueNode forMirror) {
+        LogicNode res = findSynonym(tool.getConstantReflection(), forObject, forMirror);
+        if (res == null) {
+            res = this;
+        }
+        return res;
     }
 
     public ValueNode object() {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java	Tue Mar 17 12:05:51 2015 +0100
@@ -43,7 +43,7 @@
 
     @Override
     public LocationIdentity getLocationIdentity() {
-        return LocationIdentity.ANY_LOCATION;
+        return LocationIdentity.any();
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java	Tue Mar 17 12:05:51 2015 +0100
@@ -58,7 +58,7 @@
 
     @Override
     public LocationIdentity getLocationIdentity() {
-        return LocationIdentity.ANY_LOCATION;
+        return LocationIdentity.any();
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeLIRBuilderTool.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeLIRBuilderTool.java	Tue Mar 17 12:05:51 2015 +0100
@@ -28,6 +28,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
@@ -71,5 +72,5 @@
 
     Value[] visitInvokeArguments(CallingConvention cc, Collection<ValueNode> arguments);
 
-    void doBlock(Block block, StructuredGraph graph, BlockMap<List<ValueNode>> blockMap);
+    void doBlock(Block block, StructuredGraph graph, BlockMap<List<Node>> blockMap);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeMappableLIRBuilder.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeMappableLIRBuilder.java	Tue Mar 17 12:05:51 2015 +0100
@@ -24,13 +24,14 @@
 package com.oracle.graal.nodes.spi;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 
 public interface NodeMappableLIRBuilder {
 
-    Value operand(ValueNode object);
+    Value operand(Node object);
 
-    boolean hasOperand(ValueNode object);
+    boolean hasOperand(Node object);
 
     Value setResult(ValueNode x, Value operand);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java	Tue Mar 17 12:05:51 2015 +0100
@@ -33,6 +33,8 @@
  * Interface for managing replacements.
  */
 public interface Replacements {
+    // Disabled until bug in support for this is fixed.
+    boolean SELF_RECURSIVE_INTRINSICS_ENABLED = false;
 
     /**
      * Gets the snippet graph derived from a given method.
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Tue Mar 17 12:05:51 2015 +0100
@@ -24,7 +24,6 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.debug.*;
-import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Graph.Mark;
 import com.oracle.graal.graph.Graph.NodeEventListener;
@@ -254,30 +253,24 @@
             }
             if (nodeClass.isCanonicalizable()) {
                 METRIC_CANONICALIZATION_CONSIDERED_NODES.increment();
-                try (Scope s = Debug.scope("CanonicalizeNode", node)) {
-                    Node canonical;
-                    try (AutoCloseable verify = getCanonicalizeableContractAssertion(node)) {
-                        canonical = ((Canonicalizable) node).canonical(tool);
-                        if (canonical == node && nodeClass.isCommutative()) {
-                            canonical = ((BinaryCommutative<?>) node).maybeCommuteInputs();
-                        }
-                    }
-                    if (performReplacement(node, canonical)) {
-                        return true;
+                Node canonical;
+                try (AutoCloseable verify = getCanonicalizeableContractAssertion(node)) {
+                    canonical = ((Canonicalizable) node).canonical(tool);
+                    if (canonical == node && nodeClass.isCommutative()) {
+                        canonical = ((BinaryCommutative<?>) node).maybeCommuteInputs();
                     }
                 } catch (Throwable e) {
                     throw Debug.handle(e);
                 }
+                if (performReplacement(node, canonical)) {
+                    return true;
+                }
             }
 
             if (nodeClass.isSimplifiable() && simplify) {
                 Debug.log(3, "Canonicalizer: simplifying %s", node);
                 METRIC_SIMPLIFICATION_CONSIDERED_NODES.increment();
-                try (Scope s = Debug.scope("SimplifyNode", node)) {
-                    node.simplify(tool);
-                } catch (Throwable e) {
-                    throw Debug.handle(e);
-                }
+                node.simplify(tool);
                 return node.isDeleted();
             }
             return false;
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java	Tue Mar 17 12:05:51 2015 +0100
@@ -29,10 +29,12 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.graph.Graph.NodeEventScope;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.*;
@@ -56,7 +58,7 @@
 
         public MemoryMapImpl(StartNode start) {
             lastMemorySnapshot = CollectionsFactory.newMap();
-            lastMemorySnapshot.put(ANY_LOCATION, start);
+            lastMemorySnapshot.put(any(), start);
         }
 
         public MemoryMapImpl() {
@@ -71,7 +73,7 @@
             } else {
                 lastLocationAccess = lastMemorySnapshot.get(locationIdentity);
                 if (lastLocationAccess == null) {
-                    lastLocationAccess = lastMemorySnapshot.get(ANY_LOCATION);
+                    lastLocationAccess = lastMemorySnapshot.get(any());
                     assert lastLocationAccess != null;
                 }
                 return lastLocationAccess;
@@ -125,10 +127,56 @@
         return set;
     }
 
+    protected void processNode(FixedNode node, Set<LocationIdentity> currentState) {
+        if (node instanceof MemoryCheckpoint.Single) {
+            currentState.add(((MemoryCheckpoint.Single) node).getLocationIdentity());
+        } else if (node instanceof MemoryCheckpoint.Multi) {
+            for (LocationIdentity identity : ((MemoryCheckpoint.Multi) node).getLocationIdentities()) {
+                currentState.add(identity);
+            }
+        }
+    }
+
+    protected void processBlock(Block b, Set<LocationIdentity> currentState) {
+        for (FixedNode n : b.getNodes()) {
+            processNode(n, currentState);
+        }
+    }
+
+    private Set<LocationIdentity> processLoop(HIRLoop loop, Map<LoopBeginNode, Set<LocationIdentity>> modifiedInLoops) {
+        LoopBeginNode loopBegin = (LoopBeginNode) loop.getHeader().getBeginNode();
+        Set<LocationIdentity> result = modifiedInLoops.get(loopBegin);
+        if (result != null) {
+            return result;
+        }
+
+        result = CollectionsFactory.newSet();
+        for (Loop<Block> inner : loop.getChildren()) {
+            result.addAll(processLoop((HIRLoop) inner, modifiedInLoops));
+        }
+
+        for (Block b : loop.getBlocks()) {
+            if (b.getLoop() == loop) {
+                processBlock(b, result);
+            }
+        }
+
+        modifiedInLoops.put(loopBegin, result);
+        return result;
+    }
+
     @Override
     protected void run(StructuredGraph graph) {
-        Map<LoopBeginNode, Set<LocationIdentity>> modifiedInLoops = Node.newIdentityMap();
-        ReentrantNodeIterator.apply(new CollectMemoryCheckpointsClosure(modifiedInLoops), graph.start(), CollectionsFactory.newSet());
+        Map<LoopBeginNode, Set<LocationIdentity>> modifiedInLoops = null;
+        if (graph.hasLoops()) {
+            modifiedInLoops = new HashMap<>();
+            ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, false, false);
+            for (Loop<?> l : cfg.getLoops()) {
+                HIRLoop loop = (HIRLoop) l;
+                processLoop(loop, modifiedInLoops);
+            }
+        }
+
         HashSetNodeEventListener listener = new HashSetNodeEventListener(EnumSet.of(NODE_ADDED, ZERO_USAGES));
         try (NodeEventScope nes = graph.trackNodeEvents(listener)) {
             ReentrantNodeIterator.apply(new FloatingReadClosure(modifiedInLoops, createFloatingReads, createMemoryMapNodes), graph.start(), new MemoryMapImpl(graph.start()));
@@ -193,58 +241,6 @@
         return true;
     }
 
-    public static class CollectMemoryCheckpointsClosure extends NodeIteratorClosure<Set<LocationIdentity>> {
-
-        private final Map<LoopBeginNode, Set<LocationIdentity>> modifiedInLoops;
-
-        public CollectMemoryCheckpointsClosure(Map<LoopBeginNode, Set<LocationIdentity>> modifiedInLoops) {
-            this.modifiedInLoops = modifiedInLoops;
-        }
-
-        @Override
-        protected Set<LocationIdentity> processNode(FixedNode node, Set<LocationIdentity> currentState) {
-            if (node instanceof MemoryCheckpoint.Single) {
-                currentState.add(((MemoryCheckpoint.Single) node).getLocationIdentity());
-            } else if (node instanceof MemoryCheckpoint.Multi) {
-                for (LocationIdentity identity : ((MemoryCheckpoint.Multi) node).getLocationIdentities()) {
-                    currentState.add(identity);
-                }
-            }
-            return currentState;
-        }
-
-        @Override
-        protected Set<LocationIdentity> merge(AbstractMergeNode merge, List<Set<LocationIdentity>> states) {
-            Set<LocationIdentity> result = CollectionsFactory.newSet();
-            for (Set<LocationIdentity> other : states) {
-                result.addAll(other);
-            }
-            return result;
-        }
-
-        @Override
-        protected Set<LocationIdentity> afterSplit(AbstractBeginNode node, Set<LocationIdentity> oldState) {
-            return CollectionsFactory.newSet(oldState);
-        }
-
-        @Override
-        protected Map<LoopExitNode, Set<LocationIdentity>> processLoop(LoopBeginNode loop, Set<LocationIdentity> initialState) {
-            LoopInfo<Set<LocationIdentity>> loopInfo = ReentrantNodeIterator.processLoop(this, loop, CollectionsFactory.newSet());
-            Set<LocationIdentity> modifiedLocations = CollectionsFactory.newSet();
-            for (Set<LocationIdentity> end : loopInfo.endStates.values()) {
-                modifiedLocations.addAll(end);
-            }
-            for (Set<LocationIdentity> exit : loopInfo.exitStates.values()) {
-                exit.addAll(modifiedLocations);
-                exit.addAll(initialState);
-            }
-            assert checkNoImmutableLocations(modifiedLocations);
-            modifiedInLoops.put(loop, modifiedLocations);
-            return loopInfo.exitStates;
-        }
-
-    }
-
     public static class FloatingReadClosure extends NodeIteratorClosure<MemoryMapImpl> {
 
         private final Map<LoopBeginNode, Set<LocationIdentity>> modifiedInLoops;
@@ -280,7 +276,7 @@
 
         private static void processAccess(MemoryAccess access, MemoryMapImpl state) {
             LocationIdentity locationIdentity = access.getLocationIdentity();
-            if (!locationIdentity.equals(LocationIdentity.ANY_LOCATION)) {
+            if (!locationIdentity.equals(LocationIdentity.any())) {
                 MemoryNode lastLocationAccess = state.getLastLocationAccess(locationIdentity);
                 access.setLastLocationAccess(lastLocationAccess);
             }
@@ -297,7 +293,7 @@
         }
 
         private static void processIdentity(LocationIdentity identity, MemoryCheckpoint checkpoint, MemoryMapImpl state) {
-            if (identity.equals(ANY_LOCATION)) {
+            if (identity.isAny()) {
                 state.lastMemorySnapshot.clear();
             }
             state.lastMemorySnapshot.put(identity, checkpoint);
@@ -345,18 +341,15 @@
         @Override
         protected Map<LoopExitNode, MemoryMapImpl> processLoop(LoopBeginNode loop, MemoryMapImpl initialState) {
             Set<LocationIdentity> modifiedLocations = modifiedInLoops.get(loop);
-            if (modifiedLocations.contains(ANY_LOCATION)) {
+            Map<LocationIdentity, MemoryPhiNode> phis = CollectionsFactory.newMap();
+            if (modifiedLocations.contains(LocationIdentity.any())) {
                 // create phis for all locations if ANY is modified in the loop
                 modifiedLocations = CollectionsFactory.newSet(modifiedLocations);
                 modifiedLocations.addAll(initialState.lastMemorySnapshot.keySet());
             }
 
-            Map<LocationIdentity, MemoryPhiNode> phis = CollectionsFactory.newMap();
-
             for (LocationIdentity location : modifiedLocations) {
-                MemoryPhiNode phi = loop.graph().addWithoutUnique(new MemoryPhiNode(loop, location));
-                phi.addInput(ValueNodeUtil.asNode(initialState.getLastLocationAccess(location)));
-                phis.put(location, phi);
+                createMemoryPhi(loop, initialState, phis, location);
             }
             for (Map.Entry<LocationIdentity, MemoryPhiNode> entry : phis.entrySet()) {
                 initialState.lastMemorySnapshot.put(entry.getKey(), entry.getValue());
@@ -374,5 +367,11 @@
             }
             return loopInfo.exitStates;
         }
+
+        private static void createMemoryPhi(LoopBeginNode loop, MemoryMapImpl initialState, Map<LocationIdentity, MemoryPhiNode> phis, LocationIdentity location) {
+            MemoryPhiNode phi = loop.graph().addWithoutUnique(new MemoryPhiNode(loop, location));
+            phi.addInput(ValueNodeUtil.asNode(initialState.getLastLocationAccess(location)));
+            phis.put(location, phi);
+        }
     }
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java	Tue Mar 17 12:05:51 2015 +0100
@@ -289,7 +289,7 @@
             final LoweringToolImpl loweringTool = new LoweringToolImpl(context, startAnchor, activeGuards, b.getBeginNode());
 
             // Lower the instructions of this block.
-            List<ValueNode> nodes = schedule.nodesFor(b);
+            List<Node> nodes = schedule.nodesFor(b);
             for (Node node : nodes) {
 
                 if (node.isDeleted()) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ProfileCompiledMethodsPhase.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ProfileCompiledMethodsPhase.java	Tue Mar 17 12:05:51 2015 +0100
@@ -46,7 +46,7 @@
  * a method and at each loop header.
  *
  * A schedule is created so that floating nodes can also be taken into account. The weight of a node
- * is determined heuristically in the {@link ProfileCompiledMethodsPhase#getNodeWeight(ValueNode)}
+ * is determined heuristically in the {@link ProfileCompiledMethodsPhase#getNodeWeight(Node)}
  * method.
  *
  * Additionally, there's a second counter that's only increased for code sections without invokes.
@@ -117,14 +117,14 @@
         double count = 0;
         for (Block block : blocks) {
             double blockProbability = probabilities.applyAsDouble(block.getBeginNode());
-            for (ValueNode node : schedule.getBlockToNodesMap().get(block)) {
+            for (Node node : schedule.getBlockToNodesMap().get(block)) {
                 count += blockProbability * getNodeWeight(node);
             }
         }
         return count;
     }
 
-    private static double getNodeWeight(ValueNode node) {
+    private static double getNodeWeight(Node node) {
         if (node instanceof AbstractMergeNode) {
             return ((AbstractMergeNode) node).phiPredecessorCount();
         } else if (node instanceof AbstractBeginNode || node instanceof AbstractEndNode || node instanceof MonitorIdNode || node instanceof ConstantNode || node instanceof ParameterNode ||
@@ -150,6 +150,8 @@
             return node.successors().count();
         } else if (node instanceof AbstractNewObjectNode) {
             return 10;
+        } else if (node instanceof VirtualState) {
+            return 0;
         }
         return 2;
     }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java	Tue Mar 17 12:05:51 2015 +0100
@@ -211,10 +211,7 @@
         if (callTarget.targetMethod() == null) {
             return "target method is null";
         }
-        if (invoke.stateAfter() == null) {
-            // TODO (chaeubl): why should an invoke not have a state after?
-            return "the invoke has no after state";
-        }
+        assert invoke.stateAfter() != null;
         if (!invoke.useForInlining()) {
             return "the invoke is marked to be not used for inlining";
         }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ScheduledNodeIterator.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ScheduledNodeIterator.java	Tue Mar 17 12:05:51 2015 +0100
@@ -40,7 +40,7 @@
 
     private FixedWithNextNode lastFixed;
     private FixedWithNextNode reconnect;
-    private ListIterator<ValueNode> iterator;
+    private ListIterator<Node> iterator;
 
     public void processNodes(Block block, SchedulePhase shedule) {
         lastFixed = block.getBeginNode();
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Tue Mar 17 12:05:51 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, 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,26 +22,21 @@
  */
 package com.oracle.graal.phases.schedule;
 
-import static com.oracle.graal.api.meta.LocationIdentity.*;
 import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static com.oracle.graal.compiler.common.cfg.AbstractControlFlowGraph.*;
 
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.graph.*;
-import com.oracle.graal.phases.graph.ReentrantBlockIterator.BlockIteratorClosure;
-import com.oracle.graal.phases.graph.ReentrantBlockIterator.LoopInfo;
+
+import edu.umd.cs.findbugs.annotations.*;
 
 public final class SchedulePhase extends Phase {
 
@@ -75,234 +70,14 @@
         LATEST_OUT_OF_LOOPS
     }
 
-    private class LocationSet {
-        private LocationIdentity firstLocation;
-        private List<LocationIdentity> list;
-
-        public LocationSet() {
-            list = null;
-        }
-
-        public LocationSet(LocationSet other) {
-            this.firstLocation = other.firstLocation;
-            if (other.list != null && other.list.size() > 0) {
-                list = new ArrayList<>(other.list);
-            }
-        }
-
-        private void initList() {
-            if (list == null) {
-                list = new ArrayList<>(4);
-            }
-        }
-
-        public void add(LocationIdentity location) {
-            if (LocationIdentity.ANY_LOCATION.equals(location)) {
-                firstLocation = location;
-                list = null;
-            } else {
-                if (firstLocation == null) {
-                    firstLocation = location;
-                } else if (LocationIdentity.ANY_LOCATION.equals(firstLocation)) {
-                    return;
-                } else if (location.equals(firstLocation)) {
-                    return;
-                } else {
-                    initList();
-                    for (int i = 0; i < list.size(); ++i) {
-                        LocationIdentity value = list.get(i);
-                        if (location.equals(value)) {
-                            return;
-                        }
-                    }
-                    list.add(location);
-                }
-            }
-        }
-
-        public void addAll(LocationSet other) {
-            if (other.firstLocation != null) {
-                add(other.firstLocation);
-            }
-            List<LocationIdentity> otherList = other.list;
-            if (otherList != null) {
-                for (LocationIdentity l : otherList) {
-                    add(l);
-                }
-            }
-        }
-
-        public boolean contains(LocationIdentity locationIdentity) {
-            assert locationIdentity != null;
-            assert !locationIdentity.equals(LocationIdentity.ANY_LOCATION);
-            assert !locationIdentity.equals(LocationIdentity.FINAL_LOCATION);
-            if (LocationIdentity.ANY_LOCATION.equals(firstLocation)) {
-                return true;
-            }
-            if (locationIdentity.equals(firstLocation)) {
-                return true;
-            }
-            if (list != null) {
-                for (int i = 0; i < list.size(); ++i) {
-                    LocationIdentity value = list.get(i);
-                    if (locationIdentity.equals(value)) {
-                        return true;
-                    }
-                }
-            }
-            return false;
-        }
-
-        public List<LocationIdentity> getCopyAsList() {
-            ArrayList<LocationIdentity> result = new ArrayList<>();
-            if (firstLocation != null) {
-                result.add(firstLocation);
-            }
-            if (list != null) {
-                result.addAll(list);
-            }
-            return result;
-        }
-    }
-
-    private class NewMemoryScheduleClosure extends BlockIteratorClosure<LocationSet> {
-        private Node excludeNode;
-        private Block upperBoundBlock;
-
-        public NewMemoryScheduleClosure(Node excludeNode, Block upperBoundBlock) {
-            this.excludeNode = excludeNode;
-            this.upperBoundBlock = upperBoundBlock;
-        }
-
-        public NewMemoryScheduleClosure() {
-            this(null, null);
-        }
-
-        @Override
-        protected LocationSet getInitialState() {
-            return cloneState(blockToKillSet.get(getCFG().getStartBlock()));
-        }
-
-        @Override
-        protected LocationSet processBlock(Block block, LocationSet currentState) {
-            assert block != null;
-            currentState.addAll(computeKillSet(block, block == upperBoundBlock ? excludeNode : null));
-            return currentState;
-        }
-
-        @Override
-        protected LocationSet merge(Block merge, List<LocationSet> states) {
-            assert merge.getBeginNode() instanceof AbstractMergeNode;
-
-            LocationSet initKillSet = new LocationSet();
-            for (LocationSet state : states) {
-                initKillSet.addAll(state);
-            }
-
-            return initKillSet;
-        }
-
-        @Override
-        protected LocationSet cloneState(LocationSet state) {
-            return new LocationSet(state);
-        }
-
-        @Override
-        protected List<LocationSet> processLoop(Loop<Block> loop, LocationSet state) {
-            LoopInfo<LocationSet> info = ReentrantBlockIterator.processLoop(this, loop, cloneState(state));
-
-            assert loop.getHeader().getBeginNode() instanceof LoopBeginNode;
-            LocationSet headerState = merge(loop.getHeader(), info.endStates);
-
-            // second iteration, for propagating information to loop exits
-            info = ReentrantBlockIterator.processLoop(this, loop, cloneState(headerState));
-
-            return info.exitStates;
-        }
-    }
-
-    /**
-     * gather all kill locations by iterating trough the nodes assigned to a block.
-     *
-     * assumptions: {@link MemoryCheckpoint MemoryCheckPoints} are {@link FixedNode FixedNodes}.
-     *
-     * @param block block to analyze
-     * @param excludeNode if null, compute normal set of kill locations. if != null, don't add kills
-     *            until we reach excludeNode.
-     * @return all killed locations
-     */
-    private LocationSet computeKillSet(Block block, Node excludeNode) {
-        // cache is only valid if we don't potentially exclude kills from the set
-        if (excludeNode == null) {
-            LocationSet cachedSet = blockToKillSet.get(block);
-            if (cachedSet != null) {
-                return cachedSet;
-            }
-        }
-
-        // add locations to excludedLocations until we reach the excluded node
-        boolean foundExcludeNode = excludeNode == null;
-
-        LocationSet set = new LocationSet();
-        LocationSet excludedLocations = new LocationSet();
-        if (block.getBeginNode() instanceof AbstractMergeNode) {
-            AbstractMergeNode mergeNode = (AbstractMergeNode) block.getBeginNode();
-            for (MemoryPhiNode phi : mergeNode.usages().filter(MemoryPhiNode.class)) {
-                if (foundExcludeNode) {
-                    set.add(phi.getLocationIdentity());
-                } else {
-                    excludedLocations.add(phi.getLocationIdentity());
-                    foundExcludeNode = phi == excludeNode;
-                }
-            }
-        }
-
-        AbstractBeginNode startNode = cfg.getStartBlock().getBeginNode();
-        assert startNode instanceof StartNode;
-
-        LocationSet accm = foundExcludeNode ? set : excludedLocations;
-        for (Node node : block.getNodes()) {
-            if (!foundExcludeNode && node == excludeNode) {
-                foundExcludeNode = true;
-            }
-            if (node != startNode) {
-                if (node instanceof MemoryCheckpoint.Single) {
-                    LocationIdentity identity = ((MemoryCheckpoint.Single) node).getLocationIdentity();
-                    accm.add(identity);
-                } else if (node instanceof MemoryCheckpoint.Multi) {
-                    for (LocationIdentity identity : ((MemoryCheckpoint.Multi) node).getLocationIdentities()) {
-                        accm.add(identity);
-                    }
-                }
-                assert MemoryCheckpoint.TypeAssertion.correctType(node);
-            }
-
-            if (foundExcludeNode) {
-                accm = set;
-            }
-        }
-
-        // merge it for the cache entry
-        excludedLocations.addAll(set);
-        blockToKillSet.put(block, excludedLocations);
-
-        return set;
-    }
-
-    private LocationSet computeKillSet(Block block) {
-        return computeKillSet(block, null);
-    }
-
     private ControlFlowGraph cfg;
-    private NodeMap<Block> earliestCache;
 
     /**
      * Map from blocks to the nodes in each block.
      */
-    private BlockMap<List<ValueNode>> blockToNodesMap;
+    private BlockMap<List<Node>> blockToNodesMap;
     private BlockMap<LocationSet> blockToKillSet;
     private final SchedulingStrategy selectedStrategy;
-    private boolean scheduleConstants;
     private NodeMap<Block> nodeToBlockMap;
 
     public SchedulePhase() {
@@ -313,41 +88,373 @@
         this.selectedStrategy = strategy;
     }
 
-    public void setScheduleConstants(boolean value) {
-        scheduleConstants = value;
-    }
-
     @Override
     protected void run(StructuredGraph graph) {
         // assert GraphOrder.assertNonCyclicGraph(graph);
         cfg = ControlFlowGraph.compute(graph, true, true, true, false);
-        earliestCache = graph.createNodeMap();
-        blockToNodesMap = new BlockMap<>(cfg);
+
+        if (selectedStrategy == SchedulingStrategy.EARLIEST) {
+            this.nodeToBlockMap = graph.createNodeMap();
+            this.blockToNodesMap = new BlockMap<>(cfg);
+            NodeBitMap visited = graph.createNodeBitMap();
+            scheduleEarliestIterative(cfg, blockToNodesMap, nodeToBlockMap, visited, graph);
+            return;
+        } else {
+            boolean isOutOfLoops = selectedStrategy == SchedulingStrategy.LATEST_OUT_OF_LOOPS;
+            if (selectedStrategy == SchedulingStrategy.LATEST || isOutOfLoops) {
+                NodeMap<Block> currentNodeMap = graph.createNodeMap();
+                BlockMap<List<Node>> earliestBlockToNodesMap = new BlockMap<>(cfg);
+                NodeBitMap visited = graph.createNodeBitMap();
+                scheduleEarliestIterative(cfg, earliestBlockToNodesMap, currentNodeMap, visited, graph);
+                BlockMap<List<Node>> latestBlockToNodesMap = new BlockMap<>(cfg);
+
+                for (Block b : cfg.getBlocks()) {
+                    latestBlockToNodesMap.put(b, new ArrayList<Node>());
+                }
+
+                BlockMap<ArrayList<FloatingReadNode>> watchListMap = calcLatestBlocks(isOutOfLoops, currentNodeMap, earliestBlockToNodesMap, visited, latestBlockToNodesMap);
+                sortNodesLatestWithinBlock(cfg, earliestBlockToNodesMap, latestBlockToNodesMap, currentNodeMap, watchListMap, visited);
+
+                this.blockToNodesMap = latestBlockToNodesMap;
+                this.nodeToBlockMap = currentNodeMap;
+
+                assert verifySchedule(cfg, latestBlockToNodesMap, currentNodeMap);
+                cfg.setNodeToBlock(currentNodeMap);
+            }
+        }
+    }
+
+    @SuppressFBWarnings(value = "RCN_REDUNDANT_NULLCHECK_WOULD_HAVE_BEEN_A_NPE", justification = "false positive found by findbugs")
+    private BlockMap<ArrayList<FloatingReadNode>> calcLatestBlocks(boolean isOutOfLoops, NodeMap<Block> currentNodeMap, BlockMap<List<Node>> earliestBlockToNodesMap, NodeBitMap visited,
+                    BlockMap<List<Node>> latestBlockToNodesMap) {
+        BlockMap<ArrayList<FloatingReadNode>> watchListMap = null;
+        for (Block b : cfg.postOrder()) {
+            List<Node> blockToNodes = earliestBlockToNodesMap.get(b);
+            LocationSet killed = null;
+            int previousIndex = blockToNodes.size();
+            for (int i = blockToNodes.size() - 1; i >= 0; --i) {
+                Node currentNode = blockToNodes.get(i);
+                assert currentNodeMap.get(currentNode) == b;
+                assert !(currentNode instanceof PhiNode) && !(currentNode instanceof ProxyNode);
+                assert visited.isMarked(currentNode);
+                if (currentNode instanceof FixedNode) {
+                    // For these nodes, the earliest is at the same time the latest block.
+                } else {
+                    Block currentBlock = b;
+                    assert currentBlock != null;
+                    Block latestBlock = calcLatestBlock(b, isOutOfLoops, currentNode, currentNodeMap);
+                    assert AbstractControlFlowGraph.dominates(currentBlock, latestBlock) || currentNode instanceof VirtualState : currentNode + " " + currentBlock + " " + latestBlock;
+                    if (latestBlock != currentBlock) {
+                        if (currentNode instanceof FloatingReadNode) {
 
-        if (selectedStrategy != SchedulingStrategy.EARLIEST && graph.isAfterFloatingReadPhase()) {
-            blockToKillSet = new BlockMap<>(cfg);
+                            FloatingReadNode floatingReadNode = (FloatingReadNode) currentNode;
+                            LocationIdentity location = floatingReadNode.getLocationIdentity();
+                            if (location.isMutable()) {
+                                if (currentBlock.canKill(location)) {
+                                    if (killed == null) {
+                                        killed = new LocationSet();
+                                    }
+                                    fillKillSet(killed, blockToNodes.subList(i + 1, previousIndex));
+                                    previousIndex = i;
+                                    if (killed.contains(location)) {
+                                        latestBlock = currentBlock;
+                                    }
+                                }
+
+                                if (latestBlock != currentBlock) {
+                                    // We are not constraint within currentBlock. Check if
+                                    // we are contraint while walking down the dominator
+                                    // line.
+                                    Block newLatestBlock = adjustLatestForRead(currentBlock, latestBlock, location);
+                                    assert dominates(newLatestBlock, latestBlock);
+                                    assert dominates(currentBlock, newLatestBlock);
+                                    latestBlock = newLatestBlock;
+
+                                    if (newLatestBlock != currentBlock && latestBlock.canKill(location)) {
+                                        if (watchListMap == null) {
+                                            watchListMap = new BlockMap<>(cfg);
+                                        }
+                                        if (watchListMap.get(latestBlock) == null) {
+                                            watchListMap.put(latestBlock, new ArrayList<>());
+                                        }
+                                        watchListMap.get(latestBlock).add(floatingReadNode);
+                                    }
+                                }
+                            }
+                        }
+                        currentNodeMap.set(currentNode, latestBlock);
+                        currentBlock = latestBlock;
+                    }
+                    latestBlockToNodesMap.get(currentBlock).add(currentNode);
+                }
+            }
+        }
+        return watchListMap;
+    }
+
+    private static boolean verifySchedule(ControlFlowGraph cfg, BlockMap<List<Node>> blockToNodesMap, NodeMap<Block> nodeMap) {
+        for (Block b : cfg.getBlocks()) {
+            List<Node> nodes = blockToNodesMap.get(b);
+            for (Node n : nodes) {
+                assert n.isAlive();
+                assert nodeMap.get(n) == b;
+            }
+        }
+        return true;
+    }
+
+    private static Block adjustLatestForRead(Block earliestBlock, Block latestBlock, LocationIdentity location) {
+        assert strictlyDominates(earliestBlock, latestBlock);
+        Block current = latestBlock.getDominator();
+
+        // Collect dominator chain that needs checking.
+        List<Block> dominatorChain = new ArrayList<>();
+        dominatorChain.add(latestBlock);
+        while (current != earliestBlock) {
+            // Current is an intermediate dominator between earliestBlock and latestBlock.
+            assert strictlyDominates(earliestBlock, current) && strictlyDominates(current, latestBlock);
+            if (current.canKill(location)) {
+                dominatorChain.clear();
+            }
+            dominatorChain.add(current);
+            current = current.getDominator();
         }
 
-        if (selectedStrategy == SchedulingStrategy.EARLIEST) {
-            scheduleEarliestIterative(blockToNodesMap, graph);
+        // The first element of dominatorChain now contains the latest possible block.
+        assert dominatorChain.size() >= 1;
+        assert dominatorChain.get(dominatorChain.size() - 1).getDominator() == earliestBlock;
+
+        Block lastBlock = earliestBlock;
+        for (int i = dominatorChain.size() - 1; i >= 0; --i) {
+            Block currentBlock = dominatorChain.get(i);
+            if (lastBlock.getLoop() != currentBlock.getLoop()) {
+                // We are crossing a loop boundary. Both loops must not kill the location for the
+                // crossing to be safe.
+                if (lastBlock.getLoop() != null && ((HIRLoop) lastBlock.getLoop()).canKill(location)) {
+                    break;
+                }
+                if (currentBlock.getLoop() != null && ((HIRLoop) currentBlock.getLoop()).canKill(location)) {
+                    break;
+                }
+            }
+
+            if (currentBlock.canKillBetweenThisAndDominator(location)) {
+                break;
+            }
+            lastBlock = currentBlock;
+        }
+
+        return lastBlock;
+    }
+
+    private static void fillKillSet(LocationSet killed, List<Node> subList) {
+        if (!killed.isAny()) {
+            for (Node n : subList) {
+                // Check if this node kills a node in the watch list.
+                if (n instanceof MemoryCheckpoint.Single) {
+                    LocationIdentity identity = ((MemoryCheckpoint.Single) n).getLocationIdentity();
+                    killed.add(identity);
+                    if (killed.isAny()) {
+                        return;
+                    }
+                } else if (n instanceof MemoryCheckpoint.Multi) {
+                    for (LocationIdentity identity : ((MemoryCheckpoint.Multi) n).getLocationIdentities()) {
+                        killed.add(identity);
+                        if (killed.isAny()) {
+                            return;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    private static void sortNodesLatestWithinBlock(ControlFlowGraph cfg, BlockMap<List<Node>> earliestBlockToNodesMap, BlockMap<List<Node>> latestBlockToNodesMap, NodeMap<Block> currentNodeMap,
+                    BlockMap<ArrayList<FloatingReadNode>> watchListMap, NodeBitMap visited) {
+        for (Block b : cfg.getBlocks()) {
+            sortNodesLatestWithinBlock(b, earliestBlockToNodesMap, latestBlockToNodesMap, currentNodeMap, watchListMap, visited);
+        }
+    }
+
+    private static void sortNodesLatestWithinBlock(Block b, BlockMap<List<Node>> earliestBlockToNodesMap, BlockMap<List<Node>> latestBlockToNodesMap, NodeMap<Block> nodeMap,
+                    BlockMap<ArrayList<FloatingReadNode>> watchListMap, NodeBitMap unprocessed) {
+        List<Node> earliestSorting = earliestBlockToNodesMap.get(b);
+        ArrayList<Node> result = new ArrayList<>(earliestSorting.size());
+        ArrayList<FloatingReadNode> watchList = null;
+        if (watchListMap != null) {
+            watchList = watchListMap.get(b);
+            assert watchList == null || !b.getKillLocations().isEmpty();
+        }
+        AbstractBeginNode beginNode = b.getBeginNode();
+        if (beginNode instanceof LoopExitNode) {
+            LoopExitNode loopExitNode = (LoopExitNode) beginNode;
+            for (ProxyNode proxy : loopExitNode.proxies()) {
+                unprocessed.clear(proxy);
+                ValueNode value = proxy.value();
+                if (nodeMap.get(value) == b) {
+                    sortIntoList(value, b, result, nodeMap, unprocessed, null);
+                }
+            }
+        }
+        FixedNode endNode = b.getEndNode();
+        for (Node n : earliestSorting) {
+            if (n != endNode) {
+                if (n instanceof FixedNode) {
+                    assert nodeMap.get(n) == b;
+                    checkWatchList(b, nodeMap, unprocessed, result, watchList, n);
+                    sortIntoList(n, b, result, nodeMap, unprocessed, null);
+                } else if (nodeMap.get(n) == b && n instanceof FloatingReadNode) {
+                    FloatingReadNode floatingReadNode = (FloatingReadNode) n;
+                    LocationIdentity location = floatingReadNode.getLocationIdentity();
+                    if (b.canKill(location)) {
+                        // This read can be killed in this block, add to watch list.
+                        if (watchList == null) {
+                            watchList = new ArrayList<>();
+                        }
+                        watchList.add(floatingReadNode);
+                    }
+                }
+            }
+        }
+
+        for (Node n : latestBlockToNodesMap.get(b)) {
+            assert nodeMap.get(n) == b;
+            assert !(n instanceof FixedNode);
+            if (unprocessed.isMarked(n)) {
+                sortIntoList(n, b, result, nodeMap, unprocessed, endNode);
+            }
+        }
+
+        if (unprocessed.isMarked(endNode)) {
+            sortIntoList(endNode, b, result, nodeMap, unprocessed, null);
+        }
+
+        latestBlockToNodesMap.put(b, result);
+    }
+
+    private static void checkWatchList(Block b, NodeMap<Block> nodeMap, NodeBitMap unprocessed, ArrayList<Node> result, ArrayList<FloatingReadNode> watchList, Node n) {
+        if (watchList != null && !watchList.isEmpty()) {
+            // Check if this node kills a node in the watch list.
+            if (n instanceof MemoryCheckpoint.Single) {
+                LocationIdentity identity = ((MemoryCheckpoint.Single) n).getLocationIdentity();
+                checkWatchList(watchList, identity, b, result, nodeMap, unprocessed);
+            } else if (n instanceof MemoryCheckpoint.Multi) {
+                for (LocationIdentity identity : ((MemoryCheckpoint.Multi) n).getLocationIdentities()) {
+                    checkWatchList(watchList, identity, b, result, nodeMap, unprocessed);
+                }
+            }
+        }
+    }
+
+    private static void checkWatchList(ArrayList<FloatingReadNode> watchList, LocationIdentity identity, Block b, ArrayList<Node> result, NodeMap<Block> nodeMap, NodeBitMap unprocessed) {
+        assert identity.isMutable();
+        if (identity.isAny()) {
+            for (FloatingReadNode r : watchList) {
+                if (unprocessed.isMarked(r)) {
+                    sortIntoList(r, b, result, nodeMap, unprocessed, null);
+                }
+            }
+            watchList.clear();
+        } else {
+            int index = 0;
+            while (index < watchList.size()) {
+                FloatingReadNode r = watchList.get(index);
+                LocationIdentity locationIdentity = r.getLocationIdentity();
+                assert locationIdentity.isMutable();
+                if (unprocessed.isMarked(r)) {
+                    if (identity.overlaps(locationIdentity)) {
+                        sortIntoList(r, b, result, nodeMap, unprocessed, null);
+                    } else {
+                        ++index;
+                        continue;
+                    }
+                }
+                int lastIndex = watchList.size() - 1;
+                watchList.set(index, watchList.get(lastIndex));
+                watchList.remove(lastIndex);
+            }
+        }
+    }
+
+    private static void sortIntoList(Node n, Block b, ArrayList<Node> result, NodeMap<Block> nodeMap, NodeBitMap unprocessed, Node excludeNode) {
+        assert unprocessed.isMarked(n) : n;
+        unprocessed.clear(n);
+
+        assert nodeMap.get(n) == b;
+
+        if (n instanceof PhiNode) {
             return;
         }
 
-        assignBlockToNodes(graph, selectedStrategy);
-        printSchedule("after assign nodes to blocks");
+        for (Node input : n.inputs()) {
+            if (nodeMap.get(input) == b && unprocessed.isMarked(input) && input != excludeNode) {
+                sortIntoList(input, b, result, nodeMap, unprocessed, excludeNode);
+            }
+        }
 
-        sortNodesWithinBlocks(graph, selectedStrategy);
-        printSchedule("after sorting nodes within blocks");
+        if (n instanceof ProxyNode) {
+            // Skip proxy nodes.
+        } else {
+            result.add(n);
+        }
+
     }
 
-    private void scheduleEarliestIterative(BlockMap<List<ValueNode>> blockToNodes, StructuredGraph graph) {
-        NodeMap<Block> nodeToBlock = graph.createNodeMap();
-        NodeBitMap visited = graph.createNodeBitMap();
+    private static Block calcLatestBlock(Block earliestBlock, boolean scheduleOutOfLoops, Node currentNode, NodeMap<Block> currentNodeMap) {
+        Block block = null;
+        assert currentNode.hasUsages();
+        for (Node usage : currentNode.usages()) {
+            block = calcBlockForUsage(currentNode, usage, block, currentNodeMap);
+            if (scheduleOutOfLoops) {
+                while (block.getLoopDepth() > earliestBlock.getLoopDepth()) {
+                    block = block.getDominator();
+                }
+            }
+            if (block == earliestBlock) {
+                // No need to search further. The earliest block *must* be a valid schedule block.
+                break;
+            }
+        }
+        assert block != null : currentNode;
+        return block;
+    }
+
+    private static Block calcBlockForUsage(Node node, Node usage, Block startCurrentBlock, NodeMap<Block> currentNodeMap) {
+        assert !(node instanceof PhiNode);
+        Block currentBlock = startCurrentBlock;
+        if (usage instanceof PhiNode) {
+            // An input to a PhiNode is used at the end of the predecessor block that corresponds to
+            // the PhiNode input. One PhiNode can use an input multiple times.
+            PhiNode phi = (PhiNode) usage;
+            AbstractMergeNode merge = phi.merge();
+            Block mergeBlock = currentNodeMap.get(merge);
+            for (int i = 0; i < phi.valueCount(); ++i) {
+                if (phi.valueAt(i) == node) {
+                    currentBlock = AbstractControlFlowGraph.commonDominatorTyped(currentBlock, mergeBlock.getPredecessors().get(i));
+                }
+            }
+        } else if (usage instanceof AbstractBeginNode) {
+            AbstractBeginNode abstractBeginNode = (AbstractBeginNode) usage;
+            if (abstractBeginNode instanceof StartNode) {
+                currentBlock = currentNodeMap.get(abstractBeginNode);
+            } else {
+                currentBlock = AbstractControlFlowGraph.commonDominatorTyped(currentBlock, currentNodeMap.get(abstractBeginNode).getDominator());
+            }
+        } else {
+            // All other types of usages: Put the input into the same block as the usage.
+            currentBlock = AbstractControlFlowGraph.commonDominatorTyped(currentBlock, currentNodeMap.get(usage));
+        }
+        return currentBlock;
+    }
+
+    private static void scheduleEarliestIterative(ControlFlowGraph cfg, BlockMap<List<Node>> blockToNodes, NodeMap<Block> nodeToBlock, NodeBitMap visited, StructuredGraph graph) {
+
+        BitSet floatingReads = new BitSet(cfg.getBlocks().size());
 
         // Add begin nodes as the first entry and set the block for phi nodes.
         for (Block b : cfg.getBlocks()) {
             AbstractBeginNode beginNode = b.getBeginNode();
-            ArrayList<ValueNode> nodes = new ArrayList<>();
+            ArrayList<Node> nodes = new ArrayList<>();
             nodeToBlock.set(beginNode, b);
             nodes.add(beginNode);
             blockToNodes.put(b, nodes);
@@ -365,7 +472,7 @@
             }
         }
 
-        Stack<Node> stack = new Stack<>();
+        NodeStack stack = new NodeStack();
 
         // Start analysis with control flow ends.
         for (Block b : cfg.postOrder()) {
@@ -374,10 +481,9 @@
             nodeToBlock.set(endNode, b);
         }
 
-        processStack(blockToNodes, nodeToBlock, visited, stack);
+        processStack(cfg, blockToNodes, nodeToBlock, visited, floatingReads, stack);
 
         // Visit back input edges of loop phis.
-
         boolean changed;
         boolean unmarkedPhi;
         do {
@@ -391,7 +497,7 @@
                             if (node != null && !visited.isMarked(node)) {
                                 changed = true;
                                 stack.push(node);
-                                processStack(blockToNodes, nodeToBlock, visited, stack);
+                                processStack(cfg, blockToNodes, nodeToBlock, visited, floatingReads, stack);
                             }
                         }
                     } else {
@@ -424,16 +530,83 @@
             }
         }
 
-        this.blockToNodesMap = blockToNodes;
-        this.nodeToBlockMap = nodeToBlock;
+        if (!floatingReads.isEmpty()) {
+            for (Block b : cfg.getBlocks()) {
+                if (floatingReads.get(b.getId())) {
+                    resortEarliestWithinBlock(b, blockToNodes, nodeToBlock, visited);
+                }
+            }
+        }
     }
 
-    private static void addNode(BlockMap<List<ValueNode>> blockToNodes, Block b, ValueNode endNode) {
+    private static void resortEarliestWithinBlock(Block b, BlockMap<List<Node>> blockToNodes, NodeMap<Block> nodeToBlock, NodeBitMap unprocessed) {
+        ArrayList<FloatingReadNode> watchList = new ArrayList<>();
+        List<Node> oldList = blockToNodes.get(b);
+        AbstractBeginNode beginNode = b.getBeginNode();
+        for (Node n : oldList) {
+            if (n instanceof FloatingReadNode) {
+                FloatingReadNode floatingReadNode = (FloatingReadNode) n;
+                LocationIdentity locationIdentity = floatingReadNode.getLocationIdentity();
+                MemoryNode lastLocationAccess = floatingReadNode.getLastLocationAccess();
+                if (locationIdentity.isMutable() && lastLocationAccess != null) {
+                    ValueNode lastAccessLocation = lastLocationAccess.asNode();
+                    if (nodeToBlock.get(lastAccessLocation) == b && lastAccessLocation != beginNode) {
+                        // This node's last access location is within this block. Add to watch list
+                        // when processing the last access location.
+                    } else {
+                        watchList.add(floatingReadNode);
+                    }
+                }
+            }
+        }
+
+        ArrayList<Node> newList = new ArrayList<>(oldList.size());
+        assert oldList.get(0) == beginNode;
+        unprocessed.clear(beginNode);
+        newList.add(beginNode);
+        for (int i = 1; i < oldList.size(); ++i) {
+            Node n = oldList.get(i);
+            if (unprocessed.isMarked(n)) {
+                if (n instanceof MemoryCheckpoint) {
+                    assert n instanceof FixedNode;
+                    if (watchList.size() > 0) {
+                        // Check whether we need to commit reads from the watch list.
+                        checkWatchList(b, nodeToBlock, unprocessed, newList, watchList, n);
+                    }
+
+                    // Add potential dependent reads to the watch list.
+                    for (Node usage : n.usages()) {
+                        if (usage instanceof FloatingReadNode) {
+                            FloatingReadNode floatingReadNode = (FloatingReadNode) usage;
+                            if (nodeToBlock.get(floatingReadNode) == b && floatingReadNode.getLastLocationAccess() == n) {
+                                watchList.add(floatingReadNode);
+                            }
+                        }
+                    }
+                }
+                assert unprocessed.isMarked(n);
+                unprocessed.clear(n);
+                newList.add(n);
+            } else {
+                // This node was pulled up.
+                assert !(n instanceof FixedNode) : n;
+            }
+        }
+
+        for (Node n : newList) {
+            unprocessed.mark(n);
+        }
+
+        assert newList.size() == oldList.size();
+        blockToNodes.put(b, newList);
+    }
+
+    private static void addNode(BlockMap<List<Node>> blockToNodes, Block b, Node endNode) {
         assert !blockToNodes.get(b).contains(endNode) : endNode;
         blockToNodes.get(b).add(endNode);
     }
 
-    private void processStack(BlockMap<List<ValueNode>> blockToNodes, NodeMap<Block> nodeToBlock, NodeBitMap visited, Stack<Node> stack) {
+    private static void processStack(ControlFlowGraph cfg, BlockMap<List<Node>> blockToNodes, NodeMap<Block> nodeToBlock, NodeBitMap visited, BitSet floatingReads, NodeStack stack) {
         Block startBlock = cfg.getStartBlock();
         while (!stack.isEmpty()) {
             Node current = stack.peek();
@@ -455,12 +628,16 @@
                         }
                     }
                 } else {
-                    for (Node input : current.inputs()) {
-                        if (current instanceof FrameState && input instanceof StateSplit && ((StateSplit) input).stateAfter() == current) {
-                            // Ignore the cycle.
-                        } else {
-                            stack.push(input);
+                    if (current instanceof FrameState) {
+                        for (Node input : current.inputs()) {
+                            if (input instanceof StateSplit && ((StateSplit) input).stateAfter() == current) {
+                                // Ignore the cycle.
+                            } else {
+                                stack.push(input);
+                            }
                         }
+                    } else {
+                        current.pushInputs(stack);
                     }
                 }
             } else {
@@ -468,24 +645,21 @@
                 stack.pop();
 
                 if (nodeToBlock.get(current) == null) {
-                    Node predecessor = current.predecessor();
-                    Block curBlock;
-                    if (predecessor != null) {
-                        // Predecessor determines block.
-                        curBlock = nodeToBlock.get(predecessor);
-                    } else {
+                    Block curBlock = cfg.blockFor(current);
+                    if (curBlock == null) {
+                        assert current.predecessor() == null && !(current instanceof FixedNode) : "The assignment of blocks to fixed nodes is already done when constructing the cfg.";
                         Block earliest = startBlock;
                         for (Node input : current.inputs()) {
-                            if (current instanceof FrameState && input instanceof StateSplit && ((StateSplit) input).stateAfter() == current) {
-                                // ignore
+                            Block inputEarliest;
+                            if (input instanceof ControlSplitNode) {
+                                inputEarliest = nodeToBlock.get(((ControlSplitNode) input).getPrimarySuccessor());
                             } else {
-                                Block inputEarliest;
-                                if (input instanceof ControlSplitNode) {
-                                    inputEarliest = nodeToBlock.get(((ControlSplitNode) input).getPrimarySuccessor());
-                                } else {
-                                    inputEarliest = nodeToBlock.get(input);
-                                }
-                                assert inputEarliest != null : current + " / " + input;
+                                inputEarliest = nodeToBlock.get(input);
+                            }
+                            if (inputEarliest == null) {
+                                assert current instanceof FrameState && input instanceof StateSplit && ((StateSplit) input).stateAfter() == current;
+                            } else {
+                                assert inputEarliest != null;
                                 if (earliest.getDominatorDepth() < inputEarliest.getDominatorDepth()) {
                                     earliest = inputEarliest;
                                 }
@@ -494,32 +668,20 @@
                         curBlock = earliest;
                     }
                     assert curBlock != null;
-                    if (current instanceof ValueNode) {
-                        addNode(blockToNodes, curBlock, (ValueNode) current);
+                    addNode(blockToNodes, curBlock, current);
+                    nodeToBlock.set(current, curBlock);
+                    if (current instanceof FloatingReadNode) {
+                        FloatingReadNode floatingReadNode = (FloatingReadNode) current;
+                        if (curBlock.canKill(floatingReadNode.getLocationIdentity())) {
+                            floatingReads.set(curBlock.getId());
+                        }
                     }
-                    nodeToBlock.set(current, curBlock);
                 }
             }
         }
     }
 
-    private Block blockForMemoryNode(MemoryNode memory) {
-        MemoryNode current = memory;
-        while (current instanceof MemoryProxy) {
-            current = ((MemoryProxy) current).getOriginalMemoryNode();
-        }
-        Block b = cfg.getNodeToBlock().get(current.asNode());
-        assert b != null : "all lastAccess locations should have a block assignment from CFG";
-        return b;
-    }
-
-    private void printSchedule(String desc) {
-        if (Debug.isLogEnabled()) {
-            printScheduleHelper(desc);
-        }
-    }
-
-    private void printScheduleHelper(String desc) {
+    public String printScheduleHelper(String desc) {
         Formatter buf = new Formatter();
         buf.format("=== %s / %s / %s ===%n", getCFG().getStartBlock().getBeginNode().graph(), selectedStrategy, desc);
         for (Block b : getCFG().getBlocks()) {
@@ -548,7 +710,7 @@
             }
         }
         buf.format("%n");
-        Debug.log("%s", buf);
+        return buf.toString();
     }
 
     private static void printNode(Node n) {
@@ -579,7 +741,7 @@
     /**
      * Gets the map from each block to the nodes in the block.
      */
-    public BlockMap<List<ValueNode>> getBlockToNodesMap() {
+    public BlockMap<List<Node>> getBlockToNodesMap() {
         return blockToNodesMap;
     }
 
@@ -590,660 +752,7 @@
     /**
      * Gets the nodes in a given block.
      */
-    public List<ValueNode> nodesFor(Block block) {
+    public List<Node> nodesFor(Block block) {
         return blockToNodesMap.get(block);
     }
-
-    private void assignBlockToNodes(StructuredGraph graph, SchedulingStrategy strategy) {
-        for (Block block : cfg.getBlocks()) {
-            List<ValueNode> nodes = new ArrayList<>();
-            if (blockToNodesMap.get(block) != null) {
-                throw new SchedulingError();
-            }
-            blockToNodesMap.put(block, nodes);
-            for (FixedNode node : block.getNodes()) {
-                nodes.add(node);
-            }
-        }
-
-        for (Node n : graph.getNodes()) {
-            if (n instanceof ValueNode) {
-                assignBlockToNode((ValueNode) n, strategy);
-            }
-        }
-    }
-
-    /**
-     * Assigns a block to the given node. This method expects that PhiNodes and FixedNodes are
-     * already assigned to a block.
-     */
-    private void assignBlockToNode(ValueNode node, SchedulingStrategy strategy) {
-        assert !node.isDeleted();
-
-        if (cfg.getNodeToBlock().containsKey(node)) {
-            return;
-        }
-        if (!scheduleConstants && node instanceof ConstantNode) {
-            return;
-        }
-        if (node instanceof VirtualObjectNode) {
-            return;
-        }
-        // PhiNodes, ProxyNodes and FixedNodes should already have been placed in blocks by
-        // ControlFlowGraph.identifyBlocks
-        if (node instanceof PhiNode || node instanceof ProxyNode || node instanceof FixedNode) {
-            throw new SchedulingError("%s should already have been placed in a block", node);
-        }
-
-        Block earliestBlock = earliestBlock(node);
-        Block block = null;
-        Block latest = null;
-        switch (strategy) {
-            case EARLIEST:
-                block = earliestBlock;
-                break;
-            case LATEST:
-            case LATEST_OUT_OF_LOOPS:
-                boolean scheduleRead = node instanceof FloatingReadNode && !((FloatingReadNode) node).location().getLocationIdentity().isImmutable();
-                if (scheduleRead) {
-                    FloatingReadNode read = (FloatingReadNode) node;
-                    block = optimalBlock(read, strategy);
-                    Debug.log("schedule for %s: %s", read, block);
-                    assert dominates(earliestBlock, block) : String.format("%s (%s) cannot be scheduled before earliest schedule (%s). location: %s", read, block, earliestBlock,
-                                    read.getLocationIdentity());
-                } else {
-                    block = latestBlock(node, strategy, earliestBlock);
-                }
-                if (block == null) {
-                    // handle nodes without usages
-                    block = earliestBlock;
-                } else if (strategy == SchedulingStrategy.LATEST_OUT_OF_LOOPS && !(node instanceof VirtualObjectNode)) {
-                    // schedule at the latest position possible in the outermost loop possible
-                    latest = block;
-                    block = scheduleOutOfLoops(node, block, earliestBlock);
-                }
-
-                assert assertReadSchedule(node, earliestBlock, block, latest, scheduleRead);
-                break;
-            default:
-                throw new GraalInternalError("unknown scheduling strategy");
-        }
-        if (!dominates(earliestBlock, block)) {
-            throw new SchedulingError("%s: Graph cannot be scheduled : inconsistent for %s, %d usages, (%s needs to dominate %s)", node.graph(), node, node.getUsageCount(), earliestBlock, block);
-        }
-        cfg.getNodeToBlock().set(node, block);
-        blockToNodesMap.get(block).add(node);
-    }
-
-    private boolean assertReadSchedule(ValueNode node, Block earliestBlock, Block block, Block latest, boolean scheduleRead) {
-        if (scheduleRead) {
-            FloatingReadNode read = (FloatingReadNode) node;
-            MemoryNode lastLocationAccess = read.getLastLocationAccess();
-            Block upperBound = blockForMemoryNode(lastLocationAccess);
-            assert dominates(upperBound, block) : String.format("out of loop movement voilated memory semantics for %s (location %s). moved to %s but upper bound is %s (earliest: %s, latest: %s)",
-                            read, read.getLocationIdentity(), block, upperBound, earliestBlock, latest);
-        }
-        return true;
-    }
-
-    /**
-     * this method tries to find the "optimal" schedule for a read, by pushing it down towards its
-     * latest schedule starting by the earliest schedule. By doing this, it takes care of memory
-     * dependencies using kill sets.
-     *
-     * In terms of domination relation, it looks like this:
-     *
-     * <pre>
-     *    U      upperbound block, defined by last access location of the floating read
-     *    &and;
-     *    E      earliest block
-     *    &and;
-     *    O      optimal block, first block that contains a kill of the read's location
-     *    &and;
-     *    L      latest block
-     * </pre>
-     *
-     * i.e. <code>upperbound `dom` earliest `dom` optimal `dom` latest</code>.
-     *
-     */
-    private Block optimalBlock(FloatingReadNode n, SchedulingStrategy strategy) {
-        LocationIdentity locid = n.location().getLocationIdentity();
-        assert !locid.isImmutable();
-
-        Block upperBoundBlock = blockForMemoryNode(n.getLastLocationAccess());
-        Block earliestBlock = earliestBlock(n);
-        assert dominates(upperBoundBlock, earliestBlock) : "upper bound (" + upperBoundBlock + ") should dominate earliest (" + earliestBlock + ")";
-
-        Block latestBlock = latestBlock(n, strategy, earliestBlock);
-        assert latestBlock != null && dominates(earliestBlock, latestBlock) : "earliest (" + earliestBlock + ") should dominate latest block (" + latestBlock + ")";
-
-        Debug.log("processing %s (accessing %s): latest %s, earliest %s, upper bound %s (%s)", n, locid, latestBlock, earliestBlock, upperBoundBlock, n.getLastLocationAccess());
-        if (earliestBlock == latestBlock) {
-            // read is fixed to this block, nothing to schedule
-            return latestBlock;
-        }
-
-        Deque<Block> path = computePathInDominatorTree(earliestBlock, latestBlock);
-        Debug.log("|path| is %d: %s", path.size(), path);
-
-        // follow path, start at earliest schedule
-        while (path.size() > 0) {
-            Block currentBlock = path.pop();
-            Block dominatedBlock = path.size() == 0 ? null : path.peek();
-            if (dominatedBlock != null && !currentBlock.getSuccessors().contains(dominatedBlock)) {
-                // the dominated block is not a successor -> we have a split
-                assert dominatedBlock.getBeginNode() instanceof AbstractMergeNode;
-
-                NewMemoryScheduleClosure closure = null;
-                if (currentBlock == upperBoundBlock) {
-                    assert earliestBlock == upperBoundBlock;
-                    // don't treat lastLocationAccess node as a kill for this read.
-                    closure = new NewMemoryScheduleClosure(ValueNodeUtil.asNode(n.getLastLocationAccess()), upperBoundBlock);
-                } else {
-                    closure = new NewMemoryScheduleClosure();
-                }
-                Map<FixedNode, LocationSet> states;
-                states = ReentrantBlockIterator.apply(closure, currentBlock, new LocationSet(), block -> block == dominatedBlock);
-
-                LocationSet mergeState = states.get(dominatedBlock.getBeginNode());
-                if (mergeState.contains(locid)) {
-                    // location got killed somewhere in the branches,
-                    // thus we've to move the read above it
-                    return currentBlock;
-                }
-            } else {
-                if (currentBlock == upperBoundBlock) {
-                    assert earliestBlock == upperBoundBlock;
-                    LocationSet ks = computeKillSet(upperBoundBlock, ValueNodeUtil.asNode(n.getLastLocationAccess()));
-                    if (ks.contains(locid)) {
-                        return upperBoundBlock;
-                    }
-                } else if (dominatedBlock == null || computeKillSet(currentBlock).contains(locid)) {
-                    return currentBlock;
-                }
-            }
-        }
-        throw new SchedulingError("should have found a block for " + n);
-    }
-
-    /**
-     * compute path in dominator tree from earliest schedule to latest schedule.
-     *
-     * @return the order of the stack is such as the first element is the earliest schedule.
-     */
-    private static Deque<Block> computePathInDominatorTree(Block earliestBlock, Block latestBlock) {
-        Deque<Block> path = new LinkedList<>();
-        Block currentBlock = latestBlock;
-        while (currentBlock != null && dominates(earliestBlock, currentBlock)) {
-            path.push(currentBlock);
-            currentBlock = currentBlock.getDominator();
-        }
-        assert path.peek() == earliestBlock;
-        return path;
-    }
-
-    /**
-     * Calculates the last block that the given node could be scheduled in, i.e., the common
-     * dominator of all usages. To do so all usages are also assigned to blocks.
-     *
-     * @param strategy
-     * @param earliestBlock
-     */
-    private Block latestBlock(ValueNode node, SchedulingStrategy strategy, Block earliestBlock) {
-        Block block = null;
-        for (Node usage : node.usages()) {
-            block = blocksForUsage(node, usage, block, earliestBlock, strategy);
-            if (block == earliestBlock) {
-                break;
-            }
-        }
-
-        assert assertLatestBlockResult(node, block);
-        return block;
-    }
-
-    private boolean assertLatestBlockResult(ValueNode node, Block block) throws SchedulingError {
-        if (block != null && !dominates(earliestBlock(node), block)) {
-            throw new SchedulingError("failed to find correct latest schedule for %s. cdbc: %s, earliest: %s", node, block, earliestBlock(node));
-        }
-        return true;
-    }
-
-    /**
-     * Determines the earliest block in which the given node can be scheduled.
-     */
-    private Block earliestBlock(Node node) {
-        Block earliest = cfg.getNodeToBlock().get(node);
-        if (earliest != null) {
-            return earliest;
-        }
-        earliest = earliestCache.get(node);
-        if (earliest != null) {
-            return earliest;
-        }
-        return earliestBlockHelper(node, earliest);
-    }
-
-    private Block earliestBlockHelper(Node node, Block earliestStart) throws SchedulingError {
-        /*
-         * All inputs must be in a dominating block, otherwise the graph cannot be scheduled. This
-         * implies that the inputs' blocks have a total ordering via their dominance relation. So in
-         * order to find the earliest block placement for this node we need to find the input block
-         * that is dominated by all other input blocks.
-         */
-        Block earliest = earliestStart;
-
-        if (node.predecessor() != null) {
-            throw new SchedulingError();
-        }
-        for (Node input : node.inputs()) {
-            if (input != null) {
-                assert input instanceof ValueNode;
-                Block inputEarliest;
-                if (input instanceof InvokeWithExceptionNode) {
-                    inputEarliest = cfg.getNodeToBlock().get(((InvokeWithExceptionNode) input).next());
-                } else {
-                    inputEarliest = earliestBlock(input);
-                }
-                if (earliest == null || earliest.getDominatorDepth() < inputEarliest.getDominatorDepth()) {
-                    earliest = inputEarliest;
-                }
-            }
-        }
-        if (earliest == null) {
-            earliest = cfg.getStartBlock();
-        }
-        earliestCache.set(node, earliest);
-        return earliest;
-    }
-
-    /**
-     * Schedules a node out of loop based on its earliest schedule. Note that this movement is only
-     * valid if it's done for <b>every</b> other node in the schedule, otherwise this movement is
-     * not valid.
-     *
-     * @param n Node to schedule
-     * @param latestBlock latest possible schedule for {@code n}
-     * @param earliest earliest possible schedule for {@code n}
-     * @return block schedule for {@code n} which is not inside a loop (if possible)
-     */
-    private static Block scheduleOutOfLoops(Node n, Block latestBlock, Block earliest) {
-        if (latestBlock == null) {
-            throw new SchedulingError("no latest : %s", n);
-        }
-        Block cur = latestBlock;
-        Block result = latestBlock;
-        Loop<?> earliestLoop = earliest.getLoop();
-        while (true) {
-            Loop<?> curLoop = cur.getLoop();
-            if (curLoop == earliestLoop) {
-                return result;
-            } else {
-                Block dom = cur.getDominator();
-                if (dom.getLoopDepth() < result.getLoopDepth()) {
-                    result = dom;
-                }
-                cur = dom;
-            }
-        }
-    }
-
-    /**
-     * Passes all blocks that a specific usage of a node is in to a given closure. This is more
-     * complex than just taking the usage's block because of of PhiNodes and FrameStates.
-     *
-     * @param node the node that needs to be scheduled
-     * @param usage the usage whose blocks need to be considered
-     * @param earliestBlock
-     */
-    private Block blocksForUsage(ValueNode node, Node usage, Block startCurrentBlock, Block earliestBlock, SchedulingStrategy strategy) {
-        assert !(node instanceof PhiNode);
-        Block currentBlock = startCurrentBlock;
-        if (usage instanceof PhiNode) {
-            // An input to a PhiNode is used at the end of the predecessor block that corresponds to
-            // the PhiNode input.
-            // One PhiNode can use an input multiple times, the closure will be called for each
-            // usage.
-            PhiNode phi = (PhiNode) usage;
-            AbstractMergeNode merge = phi.merge();
-            Block mergeBlock = cfg.getNodeToBlock().get(merge);
-            for (int i = 0; i < phi.valueCount(); ++i) {
-                if (phi.valueAt(i) == node) {
-                    currentBlock = AbstractControlFlowGraph.commonDominatorTyped(currentBlock, mergeBlock.getPredecessors().get(i));
-                    if (currentBlock == earliestBlock) {
-                        break;
-                    }
-                }
-            }
-        } else if (usage instanceof VirtualState) {
-            // The following logic does not work if node is a PhiNode, but this method is never
-            // called for PhiNodes.
-            for (Node unscheduledUsage : usage.usages()) {
-                if (unscheduledUsage instanceof VirtualState) {
-                    // If a FrameState is an outer FrameState this method behaves as if the inner
-                    // FrameState was the actual usage, by recursing.
-                    currentBlock = blocksForUsage(node, unscheduledUsage, currentBlock, earliestBlock, strategy);
-                } else if (unscheduledUsage instanceof AbstractBeginNode) {
-                    // Only FrameStates can be connected to BeginNodes.
-                    if (!(usage instanceof FrameState)) {
-                        throw new SchedulingError(usage.toString());
-                    }
-                    if (unscheduledUsage instanceof StartNode) {
-                        currentBlock = AbstractControlFlowGraph.commonDominatorTyped(currentBlock, cfg.getNodeToBlock().get(unscheduledUsage));
-                    } else {
-                        // If a FrameState belongs to a BeginNode then it's inputs will be placed at
-                        // the common dominator of all EndNodes.
-                        for (Node pred : unscheduledUsage.cfgPredecessors()) {
-                            currentBlock = AbstractControlFlowGraph.commonDominatorTyped(currentBlock, cfg.getNodeToBlock().get(pred));
-                        }
-                    }
-                } else {
-                    // For the time being, FrameStates can only be connected to NodeWithState.
-                    if (!(usage instanceof FrameState)) {
-                        throw new SchedulingError(usage.toString());
-                    }
-                    if (!(unscheduledUsage instanceof NodeWithState)) {
-                        throw new SchedulingError(unscheduledUsage.toString());
-                    }
-                    // Otherwise: Put the input into the same block as the usage.
-                    assignBlockToNode((ValueNode) unscheduledUsage, strategy);
-                    currentBlock = AbstractControlFlowGraph.commonDominatorTyped(currentBlock, cfg.getNodeToBlock().get(unscheduledUsage));
-                }
-                if (currentBlock == earliestBlock) {
-                    break;
-                }
-            }
-        } else {
-            // All other types of usages: Put the input into the same block as the usage.
-            assignBlockToNode((ValueNode) usage, strategy);
-            currentBlock = AbstractControlFlowGraph.commonDominatorTyped(currentBlock, cfg.getNodeToBlock().get(usage));
-        }
-        return currentBlock;
-    }
-
-    private void sortNodesWithinBlocks(StructuredGraph graph, SchedulingStrategy strategy) {
-        NodeBitMap visited = graph.createNodeBitMap();
-        NodeBitMap beforeLastLocation = graph.createNodeBitMap();
-        for (Block b : cfg.getBlocks()) {
-            sortNodesWithinBlock(b, visited, beforeLastLocation, strategy);
-            assert noDuplicatedNodesInBlock(b) : "duplicated nodes in " + b;
-        }
-    }
-
-    private boolean noDuplicatedNodesInBlock(Block b) {
-        List<ValueNode> list = blockToNodesMap.get(b);
-        Set<ValueNode> hashset = Node.newSet(list);
-        return list.size() == hashset.size();
-    }
-
-    private void sortNodesWithinBlock(Block b, NodeBitMap visited, NodeBitMap beforeLastLocation, SchedulingStrategy strategy) {
-        if (visited.isMarked(b.getBeginNode()) || cfg.blockFor(b.getBeginNode()) != b) {
-            throw new SchedulingError();
-        }
-        if (visited.isMarked(b.getEndNode()) || cfg.blockFor(b.getEndNode()) != b) {
-            throw new SchedulingError();
-        }
-
-        List<ValueNode> sortedInstructions;
-        assert strategy == SchedulingStrategy.LATEST || strategy == SchedulingStrategy.LATEST_OUT_OF_LOOPS;
-        sortedInstructions = sortNodesWithinBlockLatest(b, visited, beforeLastLocation);
-        assert filterSchedulableNodes(blockToNodesMap.get(b)).size() == removeProxies(sortedInstructions).size() : "sorted block does not contain the same amount of nodes: " +
-                        filterSchedulableNodes(blockToNodesMap.get(b)) + " vs. " + removeProxies(sortedInstructions);
-        assert sameOrderForFixedNodes(blockToNodesMap.get(b), sortedInstructions) : "fixed nodes in sorted block are not in the same order";
-        blockToNodesMap.put(b, sortedInstructions);
-    }
-
-    private static List<ValueNode> removeProxies(List<ValueNode> list) {
-        List<ValueNode> result = new ArrayList<>();
-        for (ValueNode n : list) {
-            if (!(n instanceof ProxyNode)) {
-                result.add(n);
-            }
-        }
-        return result;
-    }
-
-    private static List<ValueNode> filterSchedulableNodes(List<ValueNode> list) {
-        List<ValueNode> result = new ArrayList<>();
-        for (ValueNode n : list) {
-            if (!(n instanceof PhiNode)) {
-                result.add(n);
-            }
-        }
-        return result;
-    }
-
-    private static boolean sameOrderForFixedNodes(List<ValueNode> fixed, List<ValueNode> sorted) {
-        Iterator<ValueNode> fixedIterator = fixed.iterator();
-        Iterator<ValueNode> sortedIterator = sorted.iterator();
-
-        while (sortedIterator.hasNext()) {
-            ValueNode sortedCurrent = sortedIterator.next();
-            if (sortedCurrent instanceof FixedNode) {
-                if (!(fixedIterator.hasNext() && fixedIterator.next() == sortedCurrent)) {
-                    return false;
-                }
-            }
-        }
-
-        while (fixedIterator.hasNext()) {
-            if (fixedIterator.next() instanceof FixedNode) {
-                return false;
-            }
-        }
-
-        return true;
-    }
-
-    private static class SortState {
-        private Block block;
-        private NodeBitMap visited;
-        private NodeBitMap beforeLastLocation;
-        private List<ValueNode> sortedInstructions;
-        private List<FloatingReadNode> reads;
-
-        SortState(Block block, NodeBitMap visited, NodeBitMap beforeLastLocation, List<ValueNode> sortedInstructions) {
-            this.block = block;
-            this.visited = visited;
-            this.beforeLastLocation = beforeLastLocation;
-            this.sortedInstructions = sortedInstructions;
-            this.reads = null;
-        }
-
-        public Block currentBlock() {
-            return block;
-        }
-
-        void markVisited(Node n) {
-            visited.mark(n);
-        }
-
-        boolean isVisited(Node n) {
-            return visited.isMarked(n);
-        }
-
-        void markBeforeLastLocation(FloatingReadNode n) {
-            beforeLastLocation.mark(n);
-        }
-
-        void clearBeforeLastLocation(FloatingReadNode frn) {
-            beforeLastLocation.clear(frn);
-        }
-
-        boolean isBeforeLastLocation(FloatingReadNode n) {
-            return beforeLastLocation.isMarked(n);
-        }
-
-        void addRead(FloatingReadNode n) {
-            if (reads == null) {
-                reads = new ArrayList<>();
-            }
-            reads.add(n);
-        }
-
-        int readsSize() {
-            if (reads == null) {
-                return 0;
-            }
-            return reads.size();
-        }
-
-        void removeRead(ValueNode i) {
-            assert reads != null;
-            reads.remove(i);
-        }
-
-        List<FloatingReadNode> readsSnapshot() {
-            assert reads != null;
-            return new ArrayList<>(reads);
-        }
-
-        List<ValueNode> getSortedInstructions() {
-            return sortedInstructions;
-        }
-
-        boolean containsInstruction(ValueNode i) {
-            return sortedInstructions.contains(i);
-        }
-
-        void addInstruction(ValueNode i) {
-            sortedInstructions.add(i);
-        }
-    }
-
-    /**
-     * Sorts the nodes within a block by adding the nodes to a list in a post-order iteration over
-     * all inputs. This means that a node is added to the list after all its inputs have been
-     * processed.
-     */
-    private List<ValueNode> sortNodesWithinBlockLatest(Block b, NodeBitMap visited, NodeBitMap beforeLastLocation) {
-        SortState state = new SortState(b, visited, beforeLastLocation, new ArrayList<>(blockToNodesMap.get(b).size() + 2));
-        List<ValueNode> instructions = blockToNodesMap.get(b);
-
-        for (ValueNode i : instructions) {
-            if (i instanceof FloatingReadNode) {
-                FloatingReadNode frn = (FloatingReadNode) i;
-                if (!frn.location().getLocationIdentity().isImmutable()) {
-                    state.addRead(frn);
-                    if (nodesFor(b).contains(frn.getLastLocationAccess())) {
-                        assert !state.isBeforeLastLocation(frn);
-                        state.markBeforeLastLocation(frn);
-                    }
-                }
-            }
-        }
-
-        for (ValueNode i : instructions) {
-            addToLatestSorting(i, state);
-        }
-        assert state.readsSize() == 0 : "not all reads are scheduled";
-
-        // Make sure that last node gets really last (i.e. when a frame state successor hangs off
-        // it).
-        List<ValueNode> sortedInstructions = state.getSortedInstructions();
-        Node lastSorted = sortedInstructions.get(sortedInstructions.size() - 1);
-        if (lastSorted != b.getEndNode()) {
-            sortedInstructions.remove(b.getEndNode());
-            sortedInstructions.add(b.getEndNode());
-        }
-        return sortedInstructions;
-    }
-
-    private void processKillLocation(Node node, LocationIdentity identity, SortState state) {
-        for (FloatingReadNode frn : state.readsSnapshot()) {
-            LocationIdentity readLocation = frn.location().getLocationIdentity();
-            assert !readLocation.isImmutable();
-            if (frn.getLastLocationAccess() == node) {
-                assert identity.equals(ANY_LOCATION) || readLocation.equals(identity) || node instanceof MemoryCheckpoint.Multi : "location doesn't match: " + readLocation + ", " + identity;
-                state.clearBeforeLastLocation(frn);
-            } else if (!state.isBeforeLastLocation(frn) && (readLocation.equals(identity) || (node != getCFG().graph.start() && ANY_LOCATION.equals(identity)))) {
-                state.removeRead(frn);
-                addToLatestSorting(frn, state);
-            }
-        }
-    }
-
-    private void addUnscheduledToLatestSorting(VirtualState state, SortState sortState) {
-        if (state != null) {
-            // UnscheduledNodes should never be marked as visited.
-            if (sortState.isVisited(state)) {
-                throw new SchedulingError();
-            }
-
-            for (Node input : state.inputs()) {
-                if (input instanceof VirtualState) {
-                    addUnscheduledToLatestSorting((VirtualState) input, sortState);
-                } else {
-                    addToLatestSorting((ValueNode) input, sortState);
-                }
-            }
-        }
-    }
-
-    private void addToLatestSorting(ValueNode i, SortState state) {
-        if (i == null || state.isVisited(i) || cfg.getNodeToBlock().get(i) != state.currentBlock() || i instanceof PhiNode) {
-            return;
-        }
-
-        if (i instanceof ProxyNode) {
-            ProxyNode proxyNode = (ProxyNode) i;
-            addToLatestSorting(proxyNode.value(), state);
-            return;
-        }
-
-        if (i instanceof LoopExitNode) {
-            LoopExitNode loopExitNode = (LoopExitNode) i;
-            for (ProxyNode proxy : loopExitNode.proxies()) {
-                addToLatestSorting(proxy, state);
-            }
-        }
-
-        addToLatestSortingHelper(i, state);
-    }
-
-    private void addToLatestSortingHelper(ValueNode i, SortState state) {
-        FrameState stateAfter = null;
-        if (i instanceof StateSplit) {
-            stateAfter = ((StateSplit) i).stateAfter();
-        }
-
-        addInputsToLatestSorting(i, state, stateAfter);
-
-        if (state.readsSize() != 0) {
-            if (i instanceof MemoryCheckpoint.Single) {
-                LocationIdentity identity = ((MemoryCheckpoint.Single) i).getLocationIdentity();
-                processKillLocation(i, identity, state);
-            } else if (i instanceof MemoryCheckpoint.Multi) {
-                for (LocationIdentity identity : ((MemoryCheckpoint.Multi) i).getLocationIdentities()) {
-                    processKillLocation(i, identity, state);
-                }
-            }
-            assert MemoryCheckpoint.TypeAssertion.correctType(i);
-        }
-
-        addToLatestSorting((ValueNode) i.predecessor(), state);
-        state.markVisited(i);
-        addUnscheduledToLatestSorting(stateAfter, state);
-
-        // Now predecessors and inputs are scheduled => we can add this node.
-        if (!state.containsInstruction(i)) {
-            state.addInstruction(i);
-        }
-
-        if (state.readsSize() != 0 && i instanceof FloatingReadNode) {
-            state.removeRead(i);
-        }
-    }
-
-    private void addInputsToLatestSorting(ValueNode i, SortState state, FrameState stateAfter) {
-        for (Node input : i.inputs()) {
-            if (input instanceof FrameState) {
-                if (input != stateAfter) {
-                    addUnscheduledToLatestSorting((FrameState) input, state);
-                }
-            } else {
-                addToLatestSorting((ValueNode) input, state);
-            }
-        }
-    }
 }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/GraphOrder.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/GraphOrder.java	Tue Mar 17 12:05:51 2015 +0100
@@ -147,7 +147,7 @@
 
                 @Override
                 protected NodeBitMap processBlock(final Block block, final NodeBitMap currentState) {
-                    final List<ValueNode> list = schedule.getBlockToNodesMap().get(block);
+                    final List<Node> list = schedule.getBlockToNodesMap().get(block);
 
                     /*
                      * A stateAfter is not valid directly after its associated state split, but
@@ -155,78 +155,81 @@
                      * will be checked at the correct position.
                      */
                     FrameState pendingStateAfter = null;
-                    for (final ValueNode node : list) {
-                        FrameState stateAfter = node instanceof StateSplit ? ((StateSplit) node).stateAfter() : null;
-                        if (node instanceof FullInfopointNode) {
-                            stateAfter = ((FullInfopointNode) node).getState();
-                        }
+                    for (final Node node : list) {
+                        if (node instanceof ValueNode) {
+                            FrameState stateAfter = node instanceof StateSplit ? ((StateSplit) node).stateAfter() : null;
+                            if (node instanceof FullInfopointNode) {
+                                stateAfter = ((FullInfopointNode) node).getState();
+                            }
 
-                        if (pendingStateAfter != null && node instanceof FixedNode) {
-                            pendingStateAfter.applyToNonVirtual(new NodeClosure<Node>() {
-                                @Override
-                                public void apply(Node usage, Node nonVirtualNode) {
-                                    assert currentState.isMarked(nonVirtualNode) || nonVirtualNode instanceof VirtualObjectNode || nonVirtualNode instanceof ConstantNode : nonVirtualNode +
-                                                    " not available at virtualstate " + usage + " before " + node + " in block " + block + " \n" + list;
+                            if (pendingStateAfter != null && node instanceof FixedNode) {
+                                pendingStateAfter.applyToNonVirtual(new NodeClosure<Node>() {
+                                    @Override
+                                    public void apply(Node usage, Node nonVirtualNode) {
+                                        assert currentState.isMarked(nonVirtualNode) || nonVirtualNode instanceof VirtualObjectNode || nonVirtualNode instanceof ConstantNode : nonVirtualNode +
+                                                        " not available at virtualstate " + usage + " before " + node + " in block " + block + " \n" + list;
+                                    }
+                                });
+                                pendingStateAfter = null;
+                            }
+
+                            if (node instanceof AbstractMergeNode) {
+                                // phis aren't scheduled, so they need to be added explicitly
+                                currentState.markAll(((AbstractMergeNode) node).phis());
+                                if (node instanceof LoopBeginNode) {
+                                    // remember the state at the loop entry, it's restored at exits
+                                    loopEntryStates.put((LoopBeginNode) node, currentState.copy());
                                 }
-                            });
-                            pendingStateAfter = null;
-                        }
+                            } else if (node instanceof ProxyNode) {
+                                assert false : "proxy nodes should not be in the schedule";
+                            } else if (node instanceof LoopExitNode) {
+                                if (graph.hasValueProxies()) {
+                                    for (ProxyNode proxy : ((LoopExitNode) node).proxies()) {
+                                        for (Node input : proxy.inputs()) {
+                                            if (input != proxy.proxyPoint()) {
+                                                assert currentState.isMarked(input) : input + " not available at " + proxy + " in block " + block + "\n" + list;
+                                            }
+                                        }
+                                    }
 
-                        if (node instanceof AbstractMergeNode) {
-                            // phis aren't scheduled, so they need to be added explicitly
-                            currentState.markAll(((AbstractMergeNode) node).phis());
-                            if (node instanceof LoopBeginNode) {
-                                // remember the state at the loop entry, it's restored at exits
-                                loopEntryStates.put((LoopBeginNode) node, currentState.copy());
-                            }
-                        } else if (node instanceof ProxyNode) {
-                            assert false : "proxy nodes should not be in the schedule";
-                        } else if (node instanceof LoopExitNode) {
-                            if (graph.hasValueProxies()) {
-                                for (ProxyNode proxy : ((LoopExitNode) node).proxies()) {
-                                    for (Node input : proxy.inputs()) {
-                                        if (input != proxy.proxyPoint()) {
-                                            assert currentState.isMarked(input) : input + " not available at " + proxy + " in block " + block + "\n" + list;
+                                    // loop contents are only accessible via proxies at the exit
+                                    currentState.clearAll();
+                                    currentState.markAll(loopEntryStates.get(((LoopExitNode) node).loopBegin()));
+                                }
+                                // Loop proxies aren't scheduled, so they need to be added
+                                // explicitly
+                                currentState.markAll(((LoopExitNode) node).proxies());
+                            } else {
+                                for (Node input : node.inputs()) {
+                                    if (input != stateAfter) {
+                                        if (input instanceof FrameState) {
+                                            ((FrameState) input).applyToNonVirtual(new VirtualState.NodeClosure<Node>() {
+                                                @Override
+                                                public void apply(Node usage, Node nonVirtual) {
+                                                    assert currentState.isMarked(nonVirtual) : nonVirtual + " not available at " + node + " in block " + block + "\n" + list;
+                                                }
+                                            });
+                                        } else {
+                                            assert currentState.isMarked(input) || input instanceof VirtualObjectNode || input instanceof ConstantNode : input + " not available at " + node +
+                                                            " in block " + block + "\n" + list;
                                         }
                                     }
                                 }
-
-                                // loop contents are only accessible via proxies at the exit
-                                currentState.clearAll();
-                                currentState.markAll(loopEntryStates.get(((LoopExitNode) node).loopBegin()));
                             }
-                            // Loop proxies aren't scheduled, so they need to be added explicitly
-                            currentState.markAll(((LoopExitNode) node).proxies());
-                        } else {
-                            for (Node input : node.inputs()) {
-                                if (input != stateAfter) {
-                                    if (input instanceof FrameState) {
-                                        ((FrameState) input).applyToNonVirtual(new VirtualState.NodeClosure<Node>() {
-                                            @Override
-                                            public void apply(Node usage, Node nonVirtual) {
-                                                assert currentState.isMarked(nonVirtual) : nonVirtual + " not available at " + node + " in block " + block + "\n" + list;
-                                            }
-                                        });
-                                    } else {
-                                        assert currentState.isMarked(input) || input instanceof VirtualObjectNode || input instanceof ConstantNode : input + " not available at " + node +
-                                                        " in block " + block + "\n" + list;
-                                    }
+                            if (node instanceof AbstractEndNode) {
+                                AbstractMergeNode merge = ((AbstractEndNode) node).merge();
+                                for (PhiNode phi : merge.phis()) {
+                                    ValueNode phiValue = phi.valueAt((AbstractEndNode) node);
+                                    assert phiValue == null || currentState.isMarked(phiValue) || phiValue instanceof ConstantNode : phiValue + " not available at phi " + phi + " / end " + node +
+                                                    " in block " + block;
                                 }
                             }
+                            if (stateAfter != null) {
+                                assert pendingStateAfter == null;
+                                pendingStateAfter = stateAfter;
+                            }
+                            currentState.mark(node);
                         }
-                        if (node instanceof AbstractEndNode) {
-                            AbstractMergeNode merge = ((AbstractEndNode) node).merge();
-                            for (PhiNode phi : merge.phis()) {
-                                ValueNode phiValue = phi.valueAt((AbstractEndNode) node);
-                                assert phiValue == null || currentState.isMarked(phiValue) || phiValue instanceof ConstantNode : phiValue + " not available at phi " + phi + " / end " + node +
-                                                " in block " + block;
-                            }
-                        }
-                        if (stateAfter != null) {
-                            assert pendingStateAfter == null;
-                            pendingStateAfter = stateAfter;
-                        }
-                        currentState.mark(node);
                     }
                     if (pendingStateAfter != null) {
                         pendingStateAfter.applyToNonVirtual(new NodeClosure<Node>() {
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/verify/VerifyUsageWithEquals.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/verify/VerifyUsageWithEquals.java	Tue Mar 17 12:05:51 2015 +0100
@@ -107,7 +107,11 @@
         for (ObjectEqualsNode cn : graph.getNodes().filter(ObjectEqualsNode.class)) {
             // bail out if we compare an object of type klass with == or != (except null checks)
             ResolvedJavaMethod method = graph.method();
-            if (isIllegalUsage(method, cn.getX(), cn.getY(), context.getMetaAccess()) || isIllegalUsage(method, cn.getY(), cn.getX(), context.getMetaAccess())) {
+            ResolvedJavaType restrictedType = context.getMetaAccess().lookupJavaType(restrictedClass);
+
+            if (method.getDeclaringClass().equals(restrictedType)) {
+                // Allow violation in methods of the restricted type itself.
+            } else if (isIllegalUsage(method, cn.getX(), cn.getY(), context.getMetaAccess()) || isIllegalUsage(method, cn.getY(), cn.getX(), context.getMetaAccess())) {
                 throw new VerificationError("Verification of " + restrictedClass.getName() + " usage failed: Comparing " + cn.getX() + " and " + cn.getY() + " in " + method +
                                 " must use .equals() for object equality, not '==' or '!='");
             }
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java	Tue Mar 17 12:05:51 2015 +0100
@@ -140,7 +140,7 @@
             }
         }
         ControlFlowGraph cfg = schedule == null ? null : schedule.getCFG();
-        BlockMap<List<ValueNode>> blockToNodes = schedule == null ? null : schedule.getBlockToNodesMap();
+        BlockMap<List<Node>> blockToNodes = schedule == null ? null : schedule.getBlockToNodesMap();
         List<Block> blocks = cfg == null ? null : cfg.getBlocks();
         writeNodes(graph);
         writeBlocks(blocks, blockToNodes);
@@ -468,11 +468,18 @@
         }
     }
 
-    private void writeBlocks(List<Block> blocks, BlockMap<List<ValueNode>> blockToNodes) throws IOException {
-        if (blocks != null) {
+    private void writeBlocks(List<Block> blocks, BlockMap<List<Node>> blockToNodes) throws IOException {
+        if (blocks != null && blockToNodes != null) {
+            for (Block block : blocks) {
+                List<Node> nodes = blockToNodes.get(block);
+                if (nodes == null) {
+                    writeInt(0);
+                    return;
+                }
+            }
             writeInt(blocks.size());
             for (Block block : blocks) {
-                List<ValueNode> nodes = blockToNodes.get(block);
+                List<Node> nodes = blockToNodes.get(block);
                 writeInt(block.getId());
                 writeInt(nodes.size());
                 for (Node node : nodes) {
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java	Tue Mar 17 12:05:51 2015 +0100
@@ -604,7 +604,7 @@
         printedNodes = null;
     }
 
-    private void printScheduledBlock(Block block, List<ValueNode> nodesFor) {
+    private void printScheduledBlock(Block block, List<Node> nodesFor) {
         printBlockProlog(block);
         begin("IR");
         out.println("HIR");
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java	Tue Mar 17 12:05:51 2015 +0100
@@ -70,7 +70,7 @@
     @Test
     public void testRead3() {
         for (Kind kind : KINDS) {
-            assertRead(parseEager("read" + kind.name() + "3", AllowAssumptions.YES), kind, true, LocationIdentity.ANY_LOCATION);
+            assertRead(parseEager("read" + kind.name() + "3", AllowAssumptions.YES), kind, true, LocationIdentity.any());
         }
     }
 
@@ -91,7 +91,7 @@
     @Test
     public void testWrite3() {
         for (Kind kind : KINDS) {
-            assertWrite(parseEager("write" + kind.name() + "3", AllowAssumptions.YES), true, LocationIdentity.ANY_LOCATION);
+            assertWrite(parseEager("write" + kind.name() + "3", AllowAssumptions.YES), true, LocationIdentity.any());
         }
     }
 
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java	Tue Mar 17 12:05:51 2015 +0100
@@ -79,7 +79,7 @@
     @Test
     public void testRead3() {
         for (Kind kind : KINDS) {
-            assertRead(parseEager("read" + kind.name() + "3", AllowAssumptions.YES), kind, true, LocationIdentity.ANY_LOCATION);
+            assertRead(parseEager("read" + kind.name() + "3", AllowAssumptions.YES), kind, true, LocationIdentity.any());
         }
     }
 
@@ -100,7 +100,7 @@
     @Test
     public void testWrite3() {
         for (Kind kind : KINDS) {
-            assertWrite(parseEager("write" + kind.name() + "3", AllowAssumptions.YES), true, LocationIdentity.ANY_LOCATION);
+            assertWrite(parseEager("write" + kind.name() + "3", AllowAssumptions.YES), true, LocationIdentity.any());
         }
     }
 
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BoxingSnippets.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BoxingSnippets.java	Tue Mar 17 12:05:51 2015 +0100
@@ -235,8 +235,7 @@
 
             SnippetTemplate template = template(args);
             Debug.log("Lowering integerValueOf in %s: node=%s, template=%s, arguments=%s", unbox.graph(), unbox, template, args);
-            template.instantiate(providers.getMetaAccess(), unbox, DEFAULT_REPLACER, tool, args);
-            GraphUtil.killWithUnusedFloatingInputs(unbox);
+            template.instantiate(providers.getMetaAccess(), unbox, DEFAULT_REPLACER, args);
         }
     }
 
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultGenericInvocationPlugin.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultGenericInvocationPlugin.java	Tue Mar 17 12:05:51 2015 +0100
@@ -100,7 +100,9 @@
         if (res instanceof UnsafeCopyNode) {
             UnsafeCopyNode copy = (UnsafeCopyNode) res;
             UnsafeLoadNode value = b.append(new UnsafeLoadNode(copy.sourceObject(), copy.sourceOffset(), copy.accessKind(), copy.getLocationIdentity()));
-            b.append(new UnsafeStoreNode(copy.destinationObject(), copy.destinationOffset(), value, copy.accessKind(), copy.getLocationIdentity()));
+            UnsafeStoreNode unsafeStore = new UnsafeStoreNode(copy.destinationObject(), copy.destinationOffset(), value, copy.accessKind(), copy.getLocationIdentity());
+            b.append(unsafeStore);
+            unsafeStore.setStateAfter(b.createStateAfter());
             return true;
         } else if (res instanceof ForeignCallNode) {
             ForeignCallNode foreign = (ForeignCallNode) res;
@@ -115,6 +117,13 @@
             assert res.getKind().getStackKind() == Kind.Void;
         }
 
+        if (res instanceof StateSplit) {
+            StateSplit stateSplit = (StateSplit) res;
+            if (stateSplit.stateAfter() == null) {
+                stateSplit.setStateAfter(b.createStateAfter());
+            }
+        }
+
         return true;
     }
 
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultJavaLoweringProvider.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultJavaLoweringProvider.java	Tue Mar 17 12:05:51 2015 +0100
@@ -590,7 +590,7 @@
     protected ConstantLocationNode createFieldLocation(StructuredGraph graph, ResolvedJavaField field, boolean initialization) {
         int offset = fieldOffset(field);
         if (offset >= 0) {
-            LocationIdentity loc = initialization ? initLocationIdentity() : field;
+            LocationIdentity loc = initialization ? initLocationIdentity() : field.getLocationIdentity();
             return graph.unique(new ConstantLocationNode(loc, offset));
         } else {
             return null;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java	Tue Mar 17 12:05:51 2015 +0100
@@ -444,7 +444,7 @@
         } else if (usage instanceof UnboxNode) {
             UnboxNode unbox = (UnboxNode) usage;
             unbox.replaceAtUsages(intrinsifiedNode);
-            graph.removeFloating(unbox);
+            graph.removeFixed(unbox);
             Debug.log("%s: Removed an UnboxNode", Debug.contextSnapshot(JavaMethod.class));
         } else if (usage instanceof UnsafeStoreNode) {
             UnsafeStoreNode store = (UnsafeStoreNode) usage;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Tue Mar 17 12:05:51 2015 +0100
@@ -1027,8 +1027,8 @@
         if (replacee instanceof MemoryCheckpoint.Single) {
             // check if some node in snippet graph also kills the same location
             LocationIdentity locationIdentity = ((MemoryCheckpoint.Single) replacee).getLocationIdentity();
-            if (locationIdentity.equals(ANY_LOCATION)) {
-                assert !(memoryMap.getLastLocationAccess(ANY_LOCATION) instanceof MemoryAnchorNode) : replacee + " kills ANY_LOCATION, but snippet does not";
+            if (locationIdentity.isAny()) {
+                assert !(memoryMap.getLastLocationAccess(any()) instanceof MemoryAnchorNode) : replacee + " kills ANY_LOCATION, but snippet does not";
             }
             assert kills.contains(locationIdentity) : replacee + " kills " + locationIdentity + ", but snippet doesn't contain a kill to this location";
             return true;
@@ -1038,12 +1038,12 @@
         Debug.log("WARNING: %s is not a MemoryCheckpoint, but the snippet graph contains kills (%s). You might want %s to be a MemoryCheckpoint", replacee, kills, replacee);
 
         // remove ANY_LOCATION if it's just a kill by the start node
-        if (memoryMap.getLastLocationAccess(ANY_LOCATION) instanceof MemoryAnchorNode) {
-            kills.remove(ANY_LOCATION);
+        if (memoryMap.getLastLocationAccess(any()) instanceof MemoryAnchorNode) {
+            kills.remove(any());
         }
 
         // node can only lower to a ANY_LOCATION kill if the replacee also kills ANY_LOCATION
-        assert !kills.contains(ANY_LOCATION) : "snippet graph contains a kill to ANY_LOCATION, but replacee (" + replacee + ") doesn't kill ANY_LOCATION.  kills: " + kills;
+        assert !kills.contains(any()) : "snippet graph contains a kill to ANY_LOCATION, but replacee (" + replacee + ") doesn't kill ANY_LOCATION.  kills: " + kills;
 
         /*
          * kills to other locations than ANY_LOCATION can be still inserted if there aren't any
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java	Tue Mar 17 12:05:51 2015 +0100
@@ -108,7 +108,9 @@
             Class<?> javaClass = kind == Kind.Object ? Object.class : kind.toJavaClass();
             r.register5("compareAndSwap" + kind.name(), Receiver.class, Object.class, long.class, javaClass, javaClass, new InvocationPlugin() {
                 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode ignoredUnsafe, ValueNode object, ValueNode offset, ValueNode expected, ValueNode x) {
-                    b.push(Kind.Boolean.getStackKind(), b.append(new CompareAndSwapNode(object, offset, expected, x, kind, LocationIdentity.ANY_LOCATION)));
+                    CompareAndSwapNode compareAndSwap = new CompareAndSwapNode(object, offset, expected, x, kind, LocationIdentity.any());
+                    b.push(Kind.Boolean.getStackKind(), b.append(compareAndSwap));
+                    compareAndSwap.setStateAfter(b.createStateAfter());
                     return true;
                 }
             });
@@ -116,14 +118,18 @@
             if (getAndSetEnabled(arch)) {
                 r.register4("getAndSet" + kind.name(), Receiver.class, Object.class, long.class, javaClass, new InvocationPlugin() {
                     public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode ignoredUnsafe, ValueNode object, ValueNode offset, ValueNode value) {
-                        b.push(kind.getStackKind(), b.append(new AtomicReadAndWriteNode(object, offset, value, kind, LocationIdentity.ANY_LOCATION)));
+                        AtomicReadAndWriteNode atomicReadWrite = new AtomicReadAndWriteNode(object, offset, value, kind, LocationIdentity.any());
+                        b.push(kind.getStackKind(), b.append(atomicReadWrite));
+                        atomicReadWrite.setStateAfter(b.createStateAfter());
                         return true;
                     }
                 });
                 if (kind != Kind.Object) {
                     r.register4("getAndAdd" + kind.name(), Receiver.class, Object.class, long.class, javaClass, new InvocationPlugin() {
                         public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode ignoredUnsafe, ValueNode object, ValueNode offset, ValueNode delta) {
-                            b.push(kind.getStackKind(), b.append(new AtomicReadAndAddNode(object, offset, delta, LocationIdentity.ANY_LOCATION)));
+                            AtomicReadAndAddNode atomicReadAdd = new AtomicReadAndAddNode(object, offset, delta, LocationIdentity.any());
+                            b.push(kind.getStackKind(), b.append(atomicReadAdd));
+                            atomicReadAdd.setStateAfter(b.createStateAfter());
                             return true;
                         }
                     });
@@ -347,7 +353,9 @@
         r.register1("<init>", Receiver.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode object) {
                 if (RegisterFinalizerNode.mayHaveFinalizer(object, b.getAssumptions())) {
-                    b.append(new RegisterFinalizerNode(object));
+                    RegisterFinalizerNode registerFinalizer = new RegisterFinalizerNode(object);
+                    b.append(registerFinalizer);
+                    registerFinalizer.setStateAfter(b.createStateAfter());
                 }
                 return true;
             }
@@ -359,7 +367,7 @@
         r.register2("isInstance", Receiver.class, Object.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode type, ValueNode object) {
                 ValueNode nullCheckedType = nullCheckedValue(b, type);
-                LogicNode condition = b.append(new InstanceOfDynamicNode(nullCheckedType, object).canonical(null, nullCheckedType, object));
+                LogicNode condition = b.append(InstanceOfDynamicNode.create(b.getConstantReflection(), nullCheckedType, object));
                 b.push(Kind.Boolean.getStackKind(), b.append(new ConditionalNode(condition).canonical(null)));
                 return true;
             }
@@ -397,7 +405,7 @@
         for (Class<?> c : new Class<?>[]{Node.class, NodeList.class}) {
             r.register2("get" + c.getSimpleName() + "Unsafe", Node.class, long.class, new InvocationPlugin() {
                 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode node, ValueNode offset) {
-                    ValueNode value = b.append(new UnsafeLoadNode(node, offset, Kind.Object, LocationIdentity.ANY_LOCATION));
+                    ValueNode value = b.append(new UnsafeLoadNode(node, offset, Kind.Object, LocationIdentity.any()));
                     boolean exactType = false;
                     boolean nonNull = false;
                     b.push(Kind.Object, b.append(new PiNode(value, metaAccess.lookupJavaType(c), exactType, nonNull)));
@@ -406,7 +414,9 @@
             });
             r.register3("put" + c.getSimpleName() + "Unsafe", Node.class, long.class, c, new InvocationPlugin() {
                 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode node, ValueNode offset, ValueNode value) {
-                    b.append(new UnsafeStoreNode(node, offset, value, Kind.Object, LocationIdentity.ANY_LOCATION));
+                    UnsafeStoreNode unsafeStore = new UnsafeStoreNode(node, offset, value, Kind.Object, LocationIdentity.any());
+                    b.append(unsafeStore);
+                    unsafeStore.setStateAfter(b.createStateAfter());
                     return true;
                 }
             });
@@ -489,7 +499,7 @@
             if (isVolatile) {
                 b.append(new MembarNode(JMM_PRE_VOLATILE_READ));
             }
-            b.push(returnKind.getStackKind(), b.append(new UnsafeLoadNode(object, offset, returnKind, LocationIdentity.ANY_LOCATION)));
+            b.push(returnKind.getStackKind(), b.append(new UnsafeLoadNode(object, offset, returnKind, LocationIdentity.any())));
             if (isVolatile) {
                 b.append(new MembarNode(JMM_POST_VOLATILE_READ));
             }
@@ -516,7 +526,9 @@
             if (isVolatile) {
                 b.append(new MembarNode(JMM_PRE_VOLATILE_WRITE));
             }
-            b.append(new UnsafeStoreNode(object, offset, value, kind, LocationIdentity.ANY_LOCATION));
+            UnsafeStoreNode unsafeStore = new UnsafeStoreNode(object, offset, value, kind, LocationIdentity.any());
+            b.append(unsafeStore);
+            unsafeStore.setStateAfter(b.createStateAfter());
             if (isVolatile) {
                 b.append(new MembarNode(JMM_PRE_VOLATILE_WRITE));
             }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/WordOperationPlugin.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/WordOperationPlugin.java	Tue Mar 17 12:05:51 2015 +0100
@@ -102,7 +102,7 @@
                 Kind readKind = wordTypes.asKind(wordMethod.getSignature().getReturnType(wordMethod.getDeclaringClass()));
                 LocationNode location;
                 if (args.length == 2) {
-                    location = makeLocation(b, args[1], ANY_LOCATION);
+                    location = makeLocation(b, args[1], any());
                 } else {
                     location = makeLocation(b, args[1], args[2]);
                 }
@@ -112,7 +112,7 @@
             case READ_HEAP: {
                 assert args.length == 3;
                 Kind readKind = wordTypes.asKind(wordMethod.getSignature().getReturnType(wordMethod.getDeclaringClass()));
-                LocationNode location = makeLocation(b, args[1], ANY_LOCATION);
+                LocationNode location = makeLocation(b, args[1], any());
                 BarrierType barrierType = snippetReflection.asObject(BarrierType.class, args[2].asJavaConstant());
                 b.push(returnStackKind, readOp(b, readKind, args[0], location, barrierType, true));
                 break;
@@ -125,7 +125,7 @@
                 Kind writeKind = wordTypes.asKind(wordMethod.getSignature().getParameterType(wordMethod.isStatic() ? 2 : 1, wordMethod.getDeclaringClass()));
                 LocationNode location;
                 if (args.length == 3) {
-                    location = makeLocation(b, args[1], LocationIdentity.ANY_LOCATION);
+                    location = makeLocation(b, args[1], LocationIdentity.any());
                 } else {
                     location = makeLocation(b, args[1], args[3]);
                 }
@@ -246,7 +246,9 @@
         final BarrierType barrier = (op == Opcode.WRITE_BARRIERED ? BarrierType.PRECISE : BarrierType.NONE);
         final boolean compressible = (op == Opcode.WRITE_OBJECT || op == Opcode.WRITE_BARRIERED);
         final boolean initialize = (op == Opcode.INITIALIZE);
-        b.append(new JavaWriteNode(writeKind, base, value, location, barrier, compressible, initialize));
+        JavaWriteNode writeNode = new JavaWriteNode(writeKind, base, value, location, barrier, compressible, initialize);
+        b.append(writeNode);
+        writeNode.setStateAfter(b.createStateAfter());
     }
 
     public LocationNode makeLocation(GraphBuilderContext b, ValueNode offset, LocationIdentity locationIdentity) {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroStateSplitNode.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroStateSplitNode.java	Tue Mar 17 12:05:51 2015 +0100
@@ -62,7 +62,7 @@
     }
 
     public LocationIdentity getLocationIdentity() {
-        return LocationIdentity.ANY_LOCATION;
+        return LocationIdentity.any();
     }
 
     protected void replaceSnippetInvokes(StructuredGraph snippetGraph) {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java	Tue Mar 17 12:05:51 2015 +0100
@@ -344,18 +344,22 @@
     }
 
     public void notifyCompilationFailed(Throwable t) {
-        if (!(t instanceof BailoutException) || ((BailoutException) t).isPermanent()) {
+        if (t instanceof BailoutException && !((BailoutException) t).isPermanent()) {
+            /*
+             * Non permanent bailouts are expected cases. A non permanent bailout would be for
+             * example class redefinition during code installation. As opposed to permanent
+             * bailouts, non permanent bailouts will trigger recompilation and are not considered a
+             * failure state.
+             */
+        } else {
             compilationPolicy.recordCompilationFailure(t);
             if (TruffleCompilationExceptionsAreThrown.getValue()) {
                 throw new OptimizationFailedException(t, this);
             }
-        }
-
-        if (t instanceof BailoutException) {
-            // Bailout => move on.
-        } else if (TruffleCompilationExceptionsAreFatal.getValue()) {
-            t.printStackTrace(OUT);
-            System.exit(-1);
+            if (TruffleCompilationExceptionsAreFatal.getValue()) {
+                t.printStackTrace(OUT);
+                System.exit(-1);
+            }
         }
     }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Tue Mar 17 12:05:51 2015 +0100
@@ -204,6 +204,7 @@
             if (replacements != null && (replacements.getMethodSubstitutionMethod(original) != null || replacements.getMacroSubstitution(original) != null)) {
                 return null;
             }
+            assert !builder.parsingReplacement();
             if (original.equals(callSiteProxyMethod)) {
                 ValueNode arg1 = arguments[0];
                 if (!arg1.isConstant()) {
@@ -221,10 +222,10 @@
                 if (decision != null && decision.isInline()) {
                     inlining.push(decision);
                     builder.getAssumptions().record(new AssumptionValidAssumption((OptimizedAssumption) decision.getTarget().getNodeRewritingAssumption()));
-                    return new InlineInfo(callInlinedMethod, false);
+                    return new InlineInfo(callInlinedMethod, false, false);
                 }
             }
-            return new InlineInfo(original, false);
+            return new InlineInfo(original, false, false);
         }
 
         public void postInline(ResolvedJavaMethod inlinedTargetMethod) {
@@ -261,6 +262,7 @@
         plugins.setInlineInvokePlugin(new InlineInvokePlugin(callTarget.getInlining(), providers.getReplacements()));
         plugins.setLoopExplosionPlugin(new LoopExplosionPlugin());
         TruffleGraphBuilderPlugins.registerInvocationPlugins(providers.getMetaAccess(), newConfig.getPlugins().getInvocationPlugins());
+
         new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), this.snippetReflection, providers.getConstantReflection(), newConfig,
                         TruffleCompilerImpl.Optimizations, null).apply(graph);
         Debug.dump(graph, "After FastPE");
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Tue Mar 17 12:05:51 2015 +0100
@@ -66,8 +66,17 @@
     private final TruffleCache truffleCache;
     private final GraalTruffleCompilationListener compilationNotify;
 
-    private static final Class<?>[] SKIPPED_EXCEPTION_CLASSES = new Class[]{UnexpectedResultException.class, SlowPathException.class, ArithmeticException.class, IllegalArgumentException.class,
-                    VirtualMachineError.class, ClassCastException.class};
+    // @formatter:off
+    private static final Class<?>[] SKIPPED_EXCEPTION_CLASSES = new Class[]{
+        UnexpectedResultException.class,
+        SlowPathException.class,
+        ArithmeticException.class,
+        IllegalArgumentException.class,
+        VirtualMachineError.class,
+        StringIndexOutOfBoundsException.class,
+        ClassCastException.class
+    };
+    // @formatter:off
 
     public static final OptimisticOptimizations Optimizations = OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.UseExceptionProbability,
                     OptimisticOptimizations.Optimization.RemoveNeverExecutedCode, OptimisticOptimizations.Optimization.UseTypeCheckedInlining, OptimisticOptimizations.Optimization.UseTypeCheckHints);
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/ObjectLocationIdentity.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/ObjectLocationIdentity.java	Tue Mar 17 12:05:51 2015 +0100
@@ -29,7 +29,7 @@
 /**
  * A {@link LocationIdentity} wrapping an object.
  */
-public final class ObjectLocationIdentity implements LocationIdentity {
+public final class ObjectLocationIdentity extends LocationIdentity {
 
     private JavaConstant object;
 
@@ -53,6 +53,7 @@
     }
 
     private ObjectLocationIdentity(JavaConstant object) {
+        super(false);
         this.object = object;
     }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeLoadMacroNode.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeLoadMacroNode.java	Tue Mar 17 12:05:51 2015 +0100
@@ -60,7 +60,7 @@
             ValueNode conditionArgument = arguments.get(CONDITION_ARGUMENT_INDEX);
             LocationIdentity locationIdentity;
             if (locationArgument.isNullConstant()) {
-                locationIdentity = LocationIdentity.ANY_LOCATION;
+                locationIdentity = LocationIdentity.any();
             } else {
                 locationIdentity = ObjectLocationIdentity.create(locationArgument.asJavaConstant());
             }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeStoreMacroNode.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeStoreMacroNode.java	Tue Mar 17 12:05:51 2015 +0100
@@ -57,7 +57,7 @@
             ValueNode valueArgument = arguments.get(VALUE_ARGUMENT_INDEX);
             LocationIdentity locationIdentity;
             if (locationArgument.isNullConstant()) {
-                locationIdentity = LocationIdentity.ANY_LOCATION;
+                locationIdentity = LocationIdentity.any();
             } else {
                 locationIdentity = ObjectLocationIdentity.create(locationArgument.asJavaConstant());
             }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java	Tue Mar 17 12:05:51 2015 +0100
@@ -337,7 +337,7 @@
             if (location.isConstant()) {
                 LocationIdentity locationIdentity;
                 if (location.isNullConstant()) {
-                    locationIdentity = LocationIdentity.ANY_LOCATION;
+                    locationIdentity = LocationIdentity.any();
                 } else {
                     locationIdentity = ObjectLocationIdentity.create(location.asJavaConstant());
                 }
@@ -363,12 +363,14 @@
             if (locationArgument.isConstant()) {
                 LocationIdentity locationIdentity;
                 if (locationArgument.isNullConstant()) {
-                    locationIdentity = LocationIdentity.ANY_LOCATION;
+                    locationIdentity = LocationIdentity.any();
                 } else {
                     locationIdentity = ObjectLocationIdentity.create(locationArgument.asJavaConstant());
                 }
 
-                b.append(new UnsafeStoreNode(object, offset, value, kind, locationIdentity, null));
+                UnsafeStoreNode unsafeStore = new UnsafeStoreNode(object, offset, value, kind, locationIdentity, null);
+                b.append(unsafeStore);
+                unsafeStore.setStateAfter(b.createStateAfter());
                 return true;
             }
             // TODO: should we throw GraalInternalError.shouldNotReachHere() here?
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsPhase.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsPhase.java	Tue Mar 17 12:05:51 2015 +0100
@@ -79,7 +79,7 @@
                     schedule = null;
                     cfg = ControlFlowGraph.compute(graph, true, true, false, false);
                 } else {
-                    schedule = new SchedulePhase(SchedulePhase.SchedulingStrategy.LATEST);
+                    schedule = new SchedulePhase(SchedulePhase.SchedulingStrategy.EARLIEST);
                     schedule.apply(graph, false);
                     cfg = schedule.getCFG();
                 }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationBlockState.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationBlockState.java	Tue Mar 17 12:05:51 2015 +0100
@@ -83,7 +83,7 @@
         if (virtual instanceof VirtualInstanceNode) {
             VirtualInstanceNode instance = (VirtualInstanceNode) virtual;
             for (int i = 0; i < instance.entryCount(); i++) {
-                readCache.put(new ReadCacheEntry(instance.field(i), representation), values.get(i));
+                readCache.put(new ReadCacheEntry(instance.field(i).getLocationIdentity(), representation), values.get(i));
             }
         }
     }
@@ -133,7 +133,7 @@
         readCache.clear();
     }
 
-    public void killReadCache(ResolvedJavaField identity) {
+    public void killReadCache(LocationIdentity identity) {
         Iterator<Map.Entry<ReadCacheEntry, ValueNode>> iter = readCache.entrySet().iterator();
         while (iter.hasNext()) {
             Map.Entry<ReadCacheEntry, ValueNode> entry = iter.next();
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java	Tue Mar 17 12:05:51 2015 +0100
@@ -89,7 +89,7 @@
     private boolean processStoreField(StoreFieldNode store, PEReadEliminationBlockState state, GraphEffectList effects) {
         if (!store.isVolatile()) {
             ValueNode object = GraphUtil.unproxify(store.object());
-            ValueNode cachedValue = state.getReadCache(object, store.field(), this);
+            ValueNode cachedValue = state.getReadCache(object, store.field().getLocationIdentity(), this);
 
             ValueNode value = getScalarAlias(store.value());
             boolean result = false;
@@ -97,37 +97,37 @@
                 effects.deleteNode(store);
                 result = true;
             }
-            state.killReadCache(store.field());
-            state.addReadCache(object, store.field(), value, this);
+            state.killReadCache(store.field().getLocationIdentity());
+            state.addReadCache(object, store.field().getLocationIdentity(), value, this);
             return result;
         } else {
-            processIdentity(state, ANY_LOCATION);
+            processIdentity(state, any());
         }
         return false;
     }
 
     private boolean processLoadField(LoadFieldNode load, PEReadEliminationBlockState state, GraphEffectList effects) {
-        if (!load.isVolatile()) {
+        if (load.isVolatile()) {
+            processIdentity(state, any());
+        } else {
             ValueNode object = GraphUtil.unproxify(load.object());
-            ValueNode cachedValue = state.getReadCache(object, load.field(), this);
+            ValueNode cachedValue = state.getReadCache(object, load.field().getLocationIdentity(), this);
             if (cachedValue != null) {
                 effects.replaceAtUsages(load, cachedValue);
                 addScalarAlias(load, cachedValue);
                 return true;
             } else {
-                state.addReadCache(object, load.field(), load, this);
+                state.addReadCache(object, load.field().getLocationIdentity(), load, this);
             }
-        } else {
-            processIdentity(state, ANY_LOCATION);
         }
         return false;
     }
 
     private static void processIdentity(PEReadEliminationBlockState state, LocationIdentity identity) {
-        if (identity instanceof ResolvedJavaField) {
-            state.killReadCache((ResolvedJavaField) identity);
-        } else if (identity.equals(ANY_LOCATION)) {
+        if (identity.isAny()) {
             state.killReadCache();
+        } else {
+            state.killReadCache(identity);
         }
     }
 
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Tue Mar 17 12:05:51 2015 +0100
@@ -119,7 +119,7 @@
     @Override
     protected boolean processNode(Node node, BlockT state, GraphEffectList effects, FixedWithNextNode lastFixedNode) {
         boolean isMarked = usages.isMarked(node);
-        if (isMarked || node instanceof VirtualizableRoot) {
+        if ((isMarked && node instanceof ValueNode) || node instanceof VirtualizableRoot) {
             VirtualUtil.trace("[[%s]] ", node);
             FixedNode nextFixedNode = lastFixedNode == null ? null : lastFixedNode.next();
             return processNode((ValueNode) node, nextFixedNode, state, effects, isMarked);
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java	Tue Mar 17 12:05:51 2015 +0100
@@ -57,10 +57,10 @@
         if (node instanceof AccessFieldNode) {
             AccessFieldNode access = (AccessFieldNode) node;
             if (access.isVolatile()) {
-                processIdentity(state, ANY_LOCATION);
+                processIdentity(state, any());
             } else {
                 ValueNode object = GraphUtil.unproxify(access.object());
-                LoadCacheEntry identifier = new LoadCacheEntry(object, access.field());
+                LoadCacheEntry identifier = new LoadCacheEntry(object, access.field().getLocationIdentity());
                 ValueNode cachedValue = state.getCacheEntry(identifier);
                 if (node instanceof LoadFieldNode) {
                     if (cachedValue != null && access.stamp().isCompatible(cachedValue.stamp())) {
@@ -78,7 +78,7 @@
                         effects.deleteNode(store);
                         deleted = true;
                     }
-                    state.killReadCache(store.field());
+                    state.killReadCache(store.field().getLocationIdentity());
                     state.addCacheEntry(identifier, value);
                 }
             }
@@ -119,7 +119,7 @@
         } else if (node instanceof UnsafeAccessNode) {
             if (node instanceof UnsafeLoadNode) {
                 UnsafeLoadNode load = (UnsafeLoadNode) node;
-                if (load.offset().isConstant() && !load.getLocationIdentity().equals(LocationIdentity.ANY_LOCATION)) {
+                if (load.offset().isConstant() && !load.getLocationIdentity().equals(LocationIdentity.any())) {
                     ValueNode object = GraphUtil.unproxify(load.object());
                     UnsafeLoadCacheEntry identifier = new UnsafeLoadCacheEntry(object, load.offset(), load.getLocationIdentity());
                     ValueNode cachedValue = state.getCacheEntry(identifier);
@@ -134,7 +134,7 @@
             } else {
                 assert node instanceof UnsafeStoreNode;
                 UnsafeStoreNode write = (UnsafeStoreNode) node;
-                if (write.offset().isConstant() && !write.getLocationIdentity().equals(LocationIdentity.ANY_LOCATION)) {
+                if (write.offset().isConstant() && !write.getLocationIdentity().equals(LocationIdentity.any())) {
                     ValueNode object = GraphUtil.unproxify(write.object());
                     UnsafeLoadCacheEntry identifier = new UnsafeLoadCacheEntry(object, write.offset(), write.getLocationIdentity());
                     ValueNode cachedValue = state.getCacheEntry(identifier);
@@ -162,7 +162,7 @@
     }
 
     private static void processIdentity(ReadEliminationBlockState state, LocationIdentity identity) {
-        if (identity.equals(ANY_LOCATION)) {
+        if (identity.isAny()) {
             state.killReadCache();
             return;
         }
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/nodes/SnippetLocationNode.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/nodes/SnippetLocationNode.java	Tue Mar 17 12:05:51 2015 +0100
@@ -74,7 +74,7 @@
             return identity;
         }
         // We do not know our actual location identity yet, so be conservative.
-        return ANY_LOCATION;
+        return any();
     }
 
     @Override
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTest.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTest.java	Tue Mar 17 12:05:51 2015 +0100
@@ -380,11 +380,7 @@
 
         @Override
         public Probe getProbe() {
-            try {
-                return probeNode.getProbe();
-            } catch (IllegalStateException e) {
-                throw new IllegalStateException("Cannot call getProbe() on a wrapper that has no probe");
-            }
+            return probeNode.getProbe();
         }
 
         @Override
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/tools/TestNodes.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/tools/TestNodes.java	Tue Mar 17 12:05:51 2015 +0100
@@ -119,11 +119,7 @@
 
         @Override
         public Probe getProbe() {
-            try {
-                return probeNode.getProbe();
-            } catch (IllegalStateException e) {
-                throw new IllegalStateException("Cannot call getProbe() on a wrapper that has no probe");
-            }
+            return probeNode.getProbe();
         }
 
         @Override
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeFailure.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeFailure.java	Tue Mar 17 12:05:51 2015 +0100
@@ -58,12 +58,7 @@
         /**
          * Wrapper not assignable to the parent's child field.
          */
-        WRAPPER_TYPE("Wrapper not assignable to parent's child field"),
-
-        /**
-         * Attempt to \"probe lite\" an already probed node.
-         */
-        LITE_VIOLATION("Attempt to \"probe lite\" an already probed node");
+        WRAPPER_TYPE("Wrapper not assignable to parent's child field");
 
         final String message;
 
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeNode.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeNode.java	Tue Mar 17 12:05:51 2015 +0100
@@ -33,9 +33,20 @@
 import com.oracle.truffle.api.source.*;
 
 /**
- * Implementation interfaces and classes for attaching {@link Probe}s to {@link WrapperNode}s.
+ * Implementation class & interface for enabling the attachment of {@linkplain Probe Probes} to
+ * Truffle ASTs.
+ * <p>
+ * A {@link ProbeNode} is the head of a chain of nodes acting on behalf of {@linkplain Instrument
+ * instruments}. It is attached to an AST as a child of a guest-language-specific
+ * {@link WrapperNode} node.
+ * <p>
+ * When Truffle clones an AST, the chain, including all attached {@linkplain Instrument instruments}
+ * will be cloned along with the {@link WrapperNode} to which it is attached. An instance of
+ * {@link Probe} represents abstractly the instrumentation at a particular location in a GL AST,
+ * tracks the clones of the chain, and keeps the instrumentation attached to the clones consistent.
  */
-public abstract class ProbeNode extends Node implements TruffleEvents, InstrumentationNode {
+@NodeInfo(cost = NodeCost.NONE)
+public final class ProbeNode extends Node implements TruffleEvents, InstrumentationNode {
 
     /**
      * A node that can be inserted into a Truffle AST, and which enables {@linkplain Instrument
@@ -91,8 +102,7 @@
         Node getChild();
 
         /**
-         * Gets the {@link Probe} responsible for installing this wrapper; none if the wrapper
-         * installed via {@linkplain Node#probeLite(ASTInstrumentListener) "lite-Probing"}.
+         * Gets the {@link Probe} responsible for installing this wrapper.
          */
         Probe getProbe();
 
@@ -100,7 +110,6 @@
          * Implementation support for completing a newly created wrapper node.
          */
         void insertProbe(ProbeNode probeNode);
-
     }
 
     /**
@@ -109,202 +118,99 @@
      */
     public static Probe insertProbe(WrapperNode wrapper) {
         final SourceSection sourceSection = wrapper.getChild().getSourceSection();
-        final ProbeFullNode probeFullNode = new ProbeFullNode(); // private constructor
-        final Probe probe = new Probe(probeFullNode, sourceSection);  // package private access
-        probeFullNode.setProbe(probe);
-        wrapper.insertProbe(probeFullNode);
-        return probe;
+        final ProbeNode probeNode = new ProbeNode(); // private constructor
+        probeNode.probe = new Probe(probeNode, sourceSection);  // package private access
+        wrapper.insertProbe(probeNode);
+        return probeNode.probe;
     }
 
+    // Never changed once set.
+    @CompilationFinal Probe probe = null;
     /**
-     * Creates a new {@link ProbeLiteNode} associated with, and attached to, a Guest Language
-     * specific instance of {@link WrapperNode}.
+     * First {@link AbstractInstrumentNode} node in chain; {@code null} of no instruments in chain.
      */
-    public static void insertProbeLite(WrapperNode wrapper, ASTInstrumentListener instrumentListener) {
-        final ProbeLiteNode probeLiteNode = new ProbeLiteNode(instrumentListener);
-        wrapper.insertProbe(probeLiteNode);
-    }
+    @Child protected AbstractInstrumentNode firstInstrument;
 
     @Override
     public boolean isInstrumentable() {
         return false;
     }
 
+    @Override
+    public Node copy() {
+        Node node = super.copy();
+        probe.registerProbeNodeClone((ProbeNode) node);
+        return node;
+    }
+
     /**
      * @return the {@link Probe} permanently associated with this {@link ProbeNode}.
-     *
-     * @throws IllegalStateException if this location was "lite-Probed"
      */
-    public abstract Probe getProbe() throws IllegalStateException;
+    public Probe getProbe() {
+        return probe;
+    }
+
+    public void enter(Node node, VirtualFrame vFrame) {
+        this.probe.checkProbeUnchanged();
+        final SyntaxTagTrap trap = probe.getTrap();
+        if (trap != null) {
+            trap.tagTrappedAt(((WrapperNode) this.getParent()).getChild(), vFrame.materialize());
+        }
+        if (firstInstrument != null) {
+            firstInstrument.enter(node, vFrame);
+        }
+    }
+
+    public void returnVoid(Node node, VirtualFrame vFrame) {
+        this.probe.checkProbeUnchanged();
+        if (firstInstrument != null) {
+            firstInstrument.returnVoid(node, vFrame);
+        }
+    }
+
+    public void returnValue(Node node, VirtualFrame vFrame, Object result) {
+        this.probe.checkProbeUnchanged();
+        if (firstInstrument != null) {
+            firstInstrument.returnValue(node, vFrame, result);
+        }
+    }
+
+    public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) {
+        this.probe.checkProbeUnchanged();
+        if (firstInstrument != null) {
+            firstInstrument.returnExceptional(node, vFrame, exception);
+        }
+    }
+
+    public String instrumentationInfo() {
+        return "Standard probe";
+    }
 
     /**
      * Adds an {@link AbstractInstrumentNode} to this chain.
-     *
-     * @throws IllegalStateException if at a "lite-Probed" location.
      */
-    abstract void addInstrument(Instrument instrument);
+    @TruffleBoundary
+    void addInstrument(Instrument instrument) {
+        assert instrument.getProbe() == probe;
+        // The existing chain of nodes may be empty
+        // Attach the modified chain.
+        firstInstrument = insert(instrument.addToChain(firstInstrument));
+    }
 
     /**
      * Removes an instrument from this chain of instruments.
      *
-     * @throws IllegalStateException if at a "lite-Probed" location.
      * @throws RuntimeException if no matching instrument is found,
      */
-    abstract void removeInstrument(Instrument instrument);
-
-    /**
-     * Implementation class & interfaces for enabling the attachment of {@linkplain Probe Probes} to
-     * Truffle ASTs.
-     * <p>
-     * Head of a chain of nodes acting on behalf of {@linkplain Instrument instruments}, attached to
-     * a Guest Language (GL) AST as a child of a GL-specific {@link WrapperNode} node.
-     * <p>
-     * When Truffle clones an AST, the chain, including all attached {@linkplain Instrument
-     * instruments} will be cloned along with the {@link WrapperNode} to which it is attached. An
-     * instance of {@link Probe} represents abstractly the instrumentation at a particular location
-     * in a GL AST, tracks the clones of the chain, and keeps the instrumentation attached to the
-     * clones consistent.
-     */
-    @NodeInfo(cost = NodeCost.NONE)
-    private static final class ProbeFullNode extends ProbeNode {
-
-        /**
-         * First {@link AbstractInstrumentNode} node in chain; {@code null} of no instruments in
-         * chain.
-         */
-        @Child protected AbstractInstrumentNode firstInstrument;
-
-        // Never changed once set.
-        @CompilationFinal private Probe probe = null;
-
-        private ProbeFullNode() {
-            this.firstInstrument = null;
-        }
-
-        @Override
-        public Probe getProbe() throws IllegalStateException {
-            return probe;
-        }
-
-        @Override
-        public Node copy() {
-            Node node = super.copy();
-            probe.registerProbeNodeClone((ProbeNode) node);
-            return node;
-        }
-
-        private void setProbe(Probe probe) {
-            this.probe = probe;
-        }
-
-        @Override
-        @TruffleBoundary
-        void addInstrument(Instrument instrument) {
-            assert instrument.getProbe() == probe;
-            // The existing chain of nodes may be empty
-            // Attach the modified chain.
-            firstInstrument = insert(instrument.addToChain(firstInstrument));
-        }
-
-        @Override
-        @TruffleBoundary
-        void removeInstrument(Instrument instrument) {
-            assert instrument.getProbe() == probe;
-            final AbstractInstrumentNode modifiedChain = instrument.removeFromChain(firstInstrument);
-            if (modifiedChain == null) {
-                firstInstrument = null;
-            } else {
-                firstInstrument = insert(modifiedChain);
-            }
-        }
-
-        public void enter(Node node, VirtualFrame vFrame) {
-            this.probe.checkProbeUnchanged();
-            final SyntaxTagTrap trap = probe.getTrap();
-            if (trap != null) {
-                trap.tagTrappedAt(((WrapperNode) this.getParent()).getChild(), vFrame.materialize());
-            }
-            if (firstInstrument != null) {
-                firstInstrument.enter(node, vFrame);
-            }
-        }
-
-        public void returnVoid(Node node, VirtualFrame vFrame) {
-            this.probe.checkProbeUnchanged();
-            if (firstInstrument != null) {
-                firstInstrument.returnVoid(node, vFrame);
-            }
-        }
-
-        public void returnValue(Node node, VirtualFrame vFrame, Object result) {
-            this.probe.checkProbeUnchanged();
-            if (firstInstrument != null) {
-                firstInstrument.returnValue(node, vFrame, result);
-            }
-        }
-
-        public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) {
-            this.probe.checkProbeUnchanged();
-            if (firstInstrument != null) {
-                firstInstrument.returnExceptional(node, vFrame, exception);
-            }
-        }
-
-        public String instrumentationInfo() {
-            return "Standard probe";
+    @TruffleBoundary
+    void removeInstrument(Instrument instrument) {
+        assert instrument.getProbe() == probe;
+        final AbstractInstrumentNode modifiedChain = instrument.removeFromChain(firstInstrument);
+        if (modifiedChain == null) {
+            firstInstrument = null;
+        } else {
+            firstInstrument = insert(modifiedChain);
         }
     }
 
-    /**
-     * Implementation of a probe that only ever has a single "instrument" associated with it. No
-     * {@link Instrument} is ever created; instead this method simply delegates the various enter
-     * and return events to a {@link TruffleEvents} passed in during construction.
-     */
-    @NodeInfo(cost = NodeCost.NONE)
-    private static final class ProbeLiteNode extends ProbeNode {
-
-        private final ASTInstrumentListener instrumentListener;
-
-        private ProbeLiteNode(ASTInstrumentListener eventListener) {
-            this.instrumentListener = eventListener;
-        }
-
-        @Override
-        public Probe getProbe() throws IllegalStateException {
-            throw new IllegalStateException("\"lite-Probed\" nodes have no explicit Probe");
-        }
-
-        @Override
-        @TruffleBoundary
-        void addInstrument(Instrument instrument) {
-            throw new IllegalStateException("Instruments may not be added at a \"lite-probed\" location");
-        }
-
-        @Override
-        @TruffleBoundary
-        void removeInstrument(Instrument instrument) {
-            throw new IllegalStateException("Instruments may not be removed at a \"lite-probed\" location");
-        }
-
-        public void enter(Node node, VirtualFrame vFrame) {
-            instrumentListener.enter(getProbe(), node, vFrame);
-        }
-
-        public void returnVoid(Node node, VirtualFrame vFrame) {
-            instrumentListener.returnVoid(getProbe(), node, vFrame);
-        }
-
-        public void returnValue(Node node, VirtualFrame vFrame, Object result) {
-            instrumentListener.returnValue(getProbe(), node, vFrame, result);
-        }
-
-        public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) {
-            instrumentListener.returnExceptional(getProbe(), node, vFrame, exception);
-        }
-
-        public String instrumentationInfo() {
-            return "\"Lite\" probe";
-        }
-
-    }
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java	Tue Mar 17 12:05:51 2015 +0100
@@ -497,61 +497,6 @@
     }
 
     /**
-     * Enables "one-shot", unmodifiable {@linkplain Instrument instrumentation} of a node, where the
-     * node is presumed to be part of a well-formed Truffle AST that is not being executed.
-     * <p>
-     * Modifies the AST by inserting a {@linkplain WrapperNode wrapper node} between the node and
-     * its parent; the wrapper node must be provided by implementations of
-     * {@link #createWrapperNode()}.
-     * <p>
-     * Unlike {@link #probe()}, once {@link #probeLite(ASTInstrumentListener)} is called at a node,
-     * no additional probing can be added and no additional instrumentation can be attached.
-     * <p>
-     * This restricted form of instrumentation is intended for special cases where only one kind of
-     * instrumentation is desired, and for which performance is a concern
-     *
-     * @param instrumentListener
-     * @throws ProbeException (unchecked) when a probe cannot be created, leaving the AST unchanged
-     */
-    public final void probeLite(ASTInstrumentListener instrumentListener) {
-
-        if (this instanceof WrapperNode) {
-            throw new ProbeException(ProbeFailure.Reason.WRAPPER_NODE, null, this, null);
-        }
-
-        if (parent == null) {
-            throw new ProbeException(ProbeFailure.Reason.NO_PARENT, null, this, null);
-        }
-
-        if (parent instanceof WrapperNode) {
-            throw new ProbeException(ProbeFailure.Reason.LITE_VIOLATION, null, this, null);
-        }
-
-        if (!isInstrumentable()) {
-            throw new ProbeException(ProbeFailure.Reason.NOT_INSTRUMENTABLE, parent, this, null);
-        }
-
-        // Create a new wrapper/probe with this node as its child.
-        final WrapperNode wrapper = createWrapperNode();
-
-        if (wrapper == null || !(wrapper instanceof Node)) {
-            throw new ProbeException(ProbeFailure.Reason.NO_WRAPPER, parent, this, wrapper);
-        }
-
-        final Node wrapperNode = (Node) wrapper;
-
-        if (!this.isSafelyReplaceableBy(wrapperNode)) {
-            throw new ProbeException(ProbeFailure.Reason.WRAPPER_TYPE, parent, this, wrapper);
-        }
-
-        // Connect it to a Probe
-        ProbeNode.insertProbeLite(wrapper, instrumentListener);
-
-        // Replace this node in the AST with the wrapper
-        this.replace(wrapperNode);
-    }
-
-    /**
      * Converts this node to a textual representation useful for debugging.
      */
     @Override
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLExpressionWrapperNode.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLExpressionWrapperNode.java	Tue Mar 17 12:05:51 2015 +0100
@@ -72,11 +72,7 @@
     }
 
     public Probe getProbe() {
-        try {
-            return probeNode.getProbe();
-        } catch (IllegalStateException e) {
-            throw new IllegalStateException("A lite-Probed wrapper has no explicit Probe");
-        }
+        return probeNode.getProbe();
     }
 
     public Node getChild() {
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLStatementWrapperNode.java	Tue Mar 17 12:05:11 2015 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLStatementWrapperNode.java	Tue Mar 17 12:05:51 2015 +0100
@@ -65,11 +65,7 @@
     }
 
     public Probe getProbe() {
-        try {
-            return probeNode.getProbe();
-        } catch (IllegalStateException e) {
-            throw new IllegalStateException("A lite-Probed wrapper has no explicit Probe");
-        }
+        return probeNode.getProbe();
     }
 
     @Override
--- a/mxtool/mx.py	Tue Mar 17 12:05:11 2015 +0100
+++ b/mxtool/mx.py	Tue Mar 17 12:05:51 2015 +0100
@@ -2823,13 +2823,16 @@
         else:
             # Using just SC_ARG_MAX without extra downwards adjustment
             # results in "[Errno 7] Argument list too long" on MacOS.
-            syslimit = os.sysconf('SC_ARG_MAX') - 20000
+            commandLinePrefixAllowance -= 20000
+            syslimit = os.sysconf('SC_ARG_MAX')
             if syslimit == -1:
                 syslimit = 262144 # we could use sys.maxint but we prefer a more robust smaller value
             limit = syslimit - commandLinePrefixAllowance
+            assert limit > 0
     for i in range(len(files)):
         path = pathFunction(files[i])
         size = len(path) + 1
+        assert size < limit
         if chunkSize + size < limit:
             chunkSize += size
         else:
@@ -4172,6 +4175,31 @@
     out.open('project', {'name' : p.name, 'default' : 'default', 'basedir' : '.'})
     out.element('description', data='Builds, tests, and runs the project ' + p.name + '.')
     out.element('import', {'file' : 'nbproject/build-impl.xml'})
+    out.open('target', {'name' : '-post-init'})
+    out.open('pathconvert', {'property' : 'comma.javac.classpath', 'pathsep' : ','})
+    out.element('path', {'path' : '${javac.classpath}'})
+    out.close('pathconvert')
+
+    out.open('restrict', {'id' : 'missing.javac.classpath'})
+    out.element('filelist', {'dir' : '${basedir}', 'files' : '${comma.javac.classpath}'})
+    out.open('not')
+    out.element('exists')
+    out.close('not')
+    out.close('restrict')
+
+    out.element('property', {'name' : 'missing.javac.classpath', 'refid' : 'missing.javac.classpath'})
+
+    out.open('condition', {'property' : 'no.dependencies', 'value' : 'true'})
+    out.element('equals', {'arg1' : '${missing.javac.classpath}', 'arg2' : ''})
+    out.close('condition')
+
+    out.element('property', {'name' : 'no.dependencies', 'value' : 'false'})
+
+    out.open('condition', {'property' : 'no.deps'})
+    out.element('equals', {'arg1' : '${no.dependencies}', 'arg2' : 'true'})
+    out.close('condition')
+
+    out.close('target')
     out.open('target', {'name' : '-post-compile'})
     out.open('exec', {'executable' : sys.executable})
     out.element('env', {'key' : 'JAVA_HOME', 'value' : jdk.jdk})