changeset 8239:8fa2eed07f81

Merge.
author Christian Humer <christian.humer@gmail.com>
date Fri, 01 Mar 2013 17:06:08 +0100
parents 0b48dc5f37c3 (current diff) 748cb57f53cb (diff)
children 33e08aca06ff
files graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueProxyNode.java
diffstat 108 files changed, 3421 insertions(+), 1526 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Address.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Address.java	Fri Mar 01 17:06:08 2013 +0100
@@ -32,17 +32,6 @@
 
     private static final long serialVersionUID = -1003772042519945089L;
 
-    /**
-     * A sentinel value used as a place holder in an instruction stream for an address that will be
-     * patched.
-     */
-    /*
-     * @SuppressWarnings("serial") public static final Address Placeholder = new
-     * Address(Kind.Illegal) {
-     * 
-     * @Override public String toString() { return "[<placeholder>]"; } };
-     */
-
     public Address(Kind kind) {
         super(kind);
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/AllocatableValue.java	Fri Mar 01 17:06:08 2013 +0100
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.api.code;
+
+import com.oracle.graal.api.meta.*;
+
+/**
+ * Common base class for values that can be manipulated by the register allocator.
+ */
+public abstract class AllocatableValue extends Value {
+
+    private static final long serialVersionUID = 153019506717492133L;
+
+    /**
+     * Marker to tell the register allocator that no storage location needs to be allocated for this
+     * value.
+     */
+    @SuppressWarnings("serial") public static final AllocatableValue UNUSED = new AllocatableValue(Kind.Illegal) {
+
+        @Override
+        public String toString() {
+            return "-";
+        }
+    };
+
+    public AllocatableValue(Kind kind) {
+        super(kind);
+    }
+
+}
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Architecture.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Architecture.java	Fri Mar 01 17:06:08 2013 +0100
@@ -23,9 +23,6 @@
 package com.oracle.graal.api.code;
 
 import java.nio.*;
-import java.util.*;
-
-import com.oracle.graal.api.code.Register.RegisterFlag;
 
 /**
  * Represents a CPU architecture, including information such as its endianness, CPU registers, word
@@ -79,22 +76,6 @@
      */
     private final int returnAddressSize;
 
-    private final EnumMap<RegisterFlag, Register[]> registersByTypeAndEncoding;
-
-    /**
-     * Gets the register for a given {@linkplain Register#encoding encoding} and type.
-     * 
-     * @param encoding a register value as used in a machine instruction
-     * @param type the type of the register
-     */
-    public Register registerFor(int encoding, RegisterFlag type) {
-        Register[] regs = registersByTypeAndEncoding.get(type);
-        assert encoding >= 0 && encoding < regs.length;
-        Register reg = regs[encoding];
-        assert reg != null;
-        return reg;
-    }
-
     protected Architecture(String name, int wordSize, ByteOrder byteOrder, Register[] registers, int implicitMemoryBarriers, int nativeCallDisplacementOffset, int registerReferenceMapBitCount,
                     int returnAddressSize) {
         this.name = name;
@@ -105,18 +86,6 @@
         this.machineCodeCallDisplacementOffset = nativeCallDisplacementOffset;
         this.registerReferenceMapBitCount = registerReferenceMapBitCount;
         this.returnAddressSize = returnAddressSize;
-
-        registersByTypeAndEncoding = new EnumMap<>(RegisterFlag.class);
-        EnumMap<RegisterFlag, Register[]> categorizedRegs = Register.categorize(registers);
-        for (RegisterFlag type : RegisterFlag.values()) {
-            Register[] regs = categorizedRegs.get(type);
-            int max = Register.maxRegisterEncoding(regs);
-            Register[] regsByEnc = new Register[max + 1];
-            for (Register reg : regs) {
-                regsByEnc[reg.encoding] = reg;
-            }
-            registersByTypeAndEncoding.put(type, regsByEnc);
-        }
     }
 
     /**
@@ -161,14 +130,6 @@
     }
 
     /**
-     * Gets a mask of the barrier constants denoting the barriers that are not required to be
-     * explicitly inserted under this architecture.
-     */
-    public int getImplicitMemoryBarriers() {
-        return implicitMemoryBarriers;
-    }
-
-    /**
      * Gets the size of the return address pushed to the stack by a call instruction. A value of 0
      * denotes that call linkage uses registers instead.
      */
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterValue.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterValue.java	Fri Mar 01 17:06:08 2013 +0100
@@ -30,7 +30,7 @@
  * {@link Register#asValue(Kind)} to retrieve the canonical {@link RegisterValue} instance for a
  * given (register,kind) pair.
  */
-public final class RegisterValue extends Value {
+public final class RegisterValue extends AllocatableValue {
 
     private static final long serialVersionUID = 7999341472196897163L;
 
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/StackSlot.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/StackSlot.java	Fri Mar 01 17:06:08 2013 +0100
@@ -30,7 +30,7 @@
  * Represents a compiler spill slot or an outgoing stack-based argument in a method's frame or an
  * incoming stack-based argument in a method's {@linkplain #isInCallerFrame() caller's frame}.
  */
-public final class StackSlot extends Value {
+public final class StackSlot extends AllocatableValue {
 
     private static final long serialVersionUID = -7725071921307318433L;
 
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ValueUtil.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ValueUtil.java	Fri Mar 01 17:06:08 2013 +0100
@@ -58,6 +58,16 @@
         return (Constant) value;
     }
 
+    public static boolean isAllocatableValue(Value value) {
+        assert value != null;
+        return value instanceof AllocatableValue;
+    }
+
+    public static AllocatableValue asAllocatableValue(Value value) {
+        assert value != null;
+        return (AllocatableValue) value;
+    }
+
     public static boolean isStackSlot(Value value) {
         assert value != null;
         return value instanceof StackSlot;
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Fri Mar 01 17:06:08 2013 +0100
@@ -25,8 +25,8 @@
 
 import static com.oracle.graal.api.code.ValueUtil.*;
 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.AMD64BitManipulationOp.IntrinsicOpcode.*;
 import static com.oracle.graal.lir.amd64.AMD64MathIntrinsicOp.IntrinsicOpcode.*;
 
 import com.oracle.graal.amd64.*;
@@ -41,11 +41,12 @@
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.JumpOp;
 import com.oracle.graal.lir.amd64.AMD64Arithmetic.DivOp;
-import com.oracle.graal.lir.amd64.AMD64Arithmetic.Op1Reg;
-import com.oracle.graal.lir.amd64.AMD64Arithmetic.Op1Stack;
+import com.oracle.graal.lir.amd64.AMD64Arithmetic.DivRemOp;
 import com.oracle.graal.lir.amd64.AMD64Arithmetic.Op2Reg;
 import com.oracle.graal.lir.amd64.AMD64Arithmetic.Op2Stack;
 import com.oracle.graal.lir.amd64.AMD64Arithmetic.ShiftOp;
+import com.oracle.graal.lir.amd64.AMD64Arithmetic.Unary1Op;
+import com.oracle.graal.lir.amd64.AMD64Arithmetic.Unary2Op;
 import com.oracle.graal.lir.amd64.*;
 import com.oracle.graal.lir.amd64.AMD64Call.DirectCallOp;
 import com.oracle.graal.lir.amd64.AMD64Call.IndirectCallOp;
@@ -66,10 +67,11 @@
 import com.oracle.graal.lir.amd64.AMD64Move.MoveToRegOp;
 import com.oracle.graal.lir.amd64.AMD64Move.NullCheckOp;
 import com.oracle.graal.lir.amd64.AMD64Move.SpillMoveOp;
+import com.oracle.graal.lir.amd64.AMD64Move.StackLeaOp;
+import com.oracle.graal.lir.amd64.AMD64Move.StoreConstantOp;
 import com.oracle.graal.lir.amd64.AMD64Move.StoreOp;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.phases.util.*;
 
@@ -137,68 +139,14 @@
     }
 
     @Override
-    public Address makeAddress(Kind kind, Value base, int displacement) {
-        return new AMD64Address(kind, base, displacement);
-    }
-
-    @Override
-    public Address makeAddress(LocationNode location, ValueNode object) {
-        Value base = operand(object);
-        Value index = Value.ILLEGAL;
-        int scale = 1;
-        int displacement = location.displacement();
-
-        if (isConstant(base)) {
-            if (asConstant(base).isNull()) {
-                base = Value.ILLEGAL;
-            } else if (asConstant(base).getKind() != Kind.Object) {
-                long newDisplacement = displacement + asConstant(base).asLong();
-                if (NumUtil.isInt(newDisplacement)) {
-                    assert !runtime.needsDataPatch(asConstant(base));
-                    displacement = (int) newDisplacement;
-                    base = Value.ILLEGAL;
-                } else {
-                    Value newBase = newVariable(Kind.Long);
-                    emitMove(base, newBase);
-                    base = newBase;
-                }
-            }
-        }
-
-        if (location instanceof IndexedLocationNode) {
-            IndexedLocationNode indexedLoc = (IndexedLocationNode) location;
-
-            index = operand(indexedLoc.index());
-            scale = indexedLoc.indexScaling();
-            if (isConstant(index)) {
-                long newDisplacement = displacement + asConstant(index).asLong() * scale;
-                // only use the constant index if the resulting displacement fits into a 32 bit
-                // offset
-                if (NumUtil.isInt(newDisplacement)) {
-                    displacement = (int) newDisplacement;
-                    index = Value.ILLEGAL;
-                } else {
-                    // create a temporary variable for the index, the pointer load cannot handle a
-                    // constant index
-                    Value newIndex = newVariable(Kind.Long);
-                    emitMove(index, newIndex);
-                    index = newIndex;
-                }
-            }
-        }
-
-        return new AMD64Address(location.getValueKind(), base, index, AMD64Address.Scale.fromInt(scale), displacement);
-    }
-
-    @Override
     public Variable emitMove(Value input) {
         Variable result = newVariable(input.getKind());
-        emitMove(input, result);
+        emitMove(result, input);
         return result;
     }
 
     @Override
-    public void emitMove(Value src, Value dst) {
+    public void emitMove(Value dst, Value src) {
         if (isRegister(src) || isStackSlot(dst)) {
             append(new MoveFromRegOp(dst, src));
         } else {
@@ -206,27 +154,94 @@
         }
     }
 
+    private AMD64Address prepareAddress(Kind kind, Value base, int displacement, Value index, int scale) {
+        Value baseRegister = base;
+        int finalDisp = displacement;
+        if (isConstant(base)) {
+            if (asConstant(base).isNull()) {
+                baseRegister = Value.ILLEGAL;
+            } else if (asConstant(base).getKind() != Kind.Object) {
+                long newDisplacement = displacement + asConstant(base).asLong();
+                if (NumUtil.isInt(newDisplacement)) {
+                    assert !runtime.needsDataPatch(asConstant(base));
+                    finalDisp = (int) newDisplacement;
+                    baseRegister = Value.ILLEGAL;
+                } else {
+                    Value newBase = newVariable(Kind.Long);
+                    emitMove(newBase, base);
+                    baseRegister = newBase;
+                }
+            }
+        }
+
+        Value indexRegister = index;
+        AMD64Address.Scale scaleEnum;
+        if (index != Value.ILLEGAL && scale > 0) {
+            scaleEnum = AMD64Address.Scale.fromInt(scale);
+            if (isConstant(index)) {
+                long newDisplacement = finalDisp + asConstant(index).asLong() * scale;
+                // only use the constant index if the resulting displacement fits into a 32 bit
+                // offset
+                if (NumUtil.isInt(newDisplacement)) {
+                    finalDisp = (int) newDisplacement;
+                    indexRegister = Value.ILLEGAL;
+                } else {
+                    // create a temporary variable for the index, the pointer load cannot handle a
+                    // constant index
+                    Value newIndex = newVariable(Kind.Long);
+                    emitMove(newIndex, index);
+                    indexRegister = newIndex;
+                }
+            }
+        } else {
+            indexRegister = Value.ILLEGAL;
+            scaleEnum = AMD64Address.Scale.Times1;
+        }
+
+        return new AMD64Address(kind, baseRegister, indexRegister, scaleEnum, finalDisp);
+    }
+
     @Override
-    public Variable emitLoad(Value loadAddress, boolean canTrap) {
+    public Variable emitLoad(Kind kind, Value base, int displacement, Value index, int scale, boolean canTrap) {
+        AMD64Address loadAddress = prepareAddress(kind, base, displacement, index, scale);
         Variable result = newVariable(loadAddress.getKind());
         append(new LoadOp(result, loadAddress, canTrap ? state() : null));
         return result;
     }
 
     @Override
-    public void emitStore(Value storeAddress, Value inputVal, boolean canTrap) {
-        Value input = loadForStore(inputVal, storeAddress.getKind());
-        append(new StoreOp(storeAddress, input, canTrap ? state() : null));
+    public void emitStore(Kind kind, Value base, int displacement, Value index, int scale, Value inputVal, boolean canTrap) {
+        AMD64Address storeAddress = prepareAddress(kind, base, displacement, index, scale);
+        LIRFrameState state = canTrap ? state() : null;
+
+        if (isConstant(inputVal)) {
+            Constant c = asConstant(inputVal);
+            if (canStoreConstant(c)) {
+                append(new StoreConstantOp(storeAddress, c, state));
+                return;
+            }
+        }
+
+        Variable input = load(inputVal);
+        append(new StoreOp(storeAddress, input, state));
     }
 
     @Override
-    public Variable emitLea(Value address) {
+    public Variable emitLea(Value base, int displacement, Value index, int scale) {
         Variable result = newVariable(target().wordKind);
+        AMD64Address address = prepareAddress(result.getKind(), base, displacement, index, scale);
         append(new LeaOp(result, address));
         return result;
     }
 
     @Override
+    public Variable emitLea(StackSlot address) {
+        Variable result = newVariable(target().wordKind);
+        append(new StackLeaOp(result, address));
+        return result;
+    }
+
+    @Override
     public void emitJump(LabelRef label, LIRFrameState info) {
         append(new JumpOp(label, info));
     }
@@ -339,14 +354,15 @@
     }
 
     @Override
-    public Variable emitNegate(Value input) {
+    public Variable emitNegate(Value inputVal) {
+        AllocatableValue input = asAllocatable(inputVal);
         Variable result = newVariable(input.getKind());
         switch (input.getKind()) {
             case Int:
-                append(new Op1Stack(INEG, result, input));
+                append(new Unary1Op(INEG, result, input));
                 break;
             case Long:
-                append(new Op1Stack(LNEG, result, input));
+                append(new Unary1Op(LNEG, result, input));
                 break;
             case Float:
                 append(new Op2Reg(FXOR, result, input, Constant.forFloat(Float.intBitsToFloat(0x80000000))));
@@ -456,11 +472,11 @@
     public Value[] emitIntegerDivRem(Value a, Value b) {
         switch (a.getKind()) {
             case Int:
-                emitMove(a, RAX_I);
+                emitMove(RAX_I, a);
                 append(new DivRemOp(IDIVREM, RAX_I, load(b), state()));
                 return new Value[]{emitMove(RAX_I), emitMove(RDX_I)};
             case Long:
-                emitMove(a, RAX_L);
+                emitMove(RAX_L, a);
                 append(new DivRemOp(LDIVREM, RAX_L, load(b), state()));
                 return new Value[]{emitMove(RAX_L), emitMove(RDX_L)};
             default:
@@ -472,11 +488,11 @@
     public Value emitDiv(Value a, Value b) {
         switch (a.getKind()) {
             case Int:
-                emitMove(a, RAX_I);
+                emitMove(RAX_I, a);
                 append(new DivOp(IDIV, RAX_I, RAX_I, load(b), state()));
                 return emitMove(RAX_I);
             case Long:
-                emitMove(a, RAX_L);
+                emitMove(RAX_L, a);
                 append(new DivOp(LDIV, RAX_L, RAX_L, load(b), state()));
                 return emitMove(RAX_L);
             case Float: {
@@ -498,11 +514,11 @@
     public Value emitRem(Value a, Value b) {
         switch (a.getKind()) {
             case Int:
-                emitMove(a, RAX_I);
+                emitMove(RAX_I, a);
                 append(new DivOp(IREM, RDX_I, RAX_I, load(b), state()));
                 return emitMove(RDX_I);
             case Long:
-                emitMove(a, RAX_L);
+                emitMove(RAX_L, a);
                 append(new DivOp(LREM, RDX_L, RAX_L, load(b), state()));
                 return emitMove(RDX_L);
             case Float: {
@@ -522,11 +538,11 @@
     public Variable emitUDiv(Value a, Value b) {
         switch (a.getKind()) {
             case Int:
-                emitMove(a, RAX_I);
+                emitMove(RAX_I, a);
                 append(new DivOp(IUDIV, RAX_I, RAX_I, load(b), state()));
                 return emitMove(RAX_I);
             case Long:
-                emitMove(a, RAX_L);
+                emitMove(RAX_L, a);
                 append(new DivOp(LUDIV, RAX_L, RAX_L, load(b), state()));
                 return emitMove(RAX_L);
             default:
@@ -538,11 +554,11 @@
     public Variable emitURem(Value a, Value b) {
         switch (a.getKind()) {
             case Int:
-                emitMove(a, RAX_I);
+                emitMove(RAX_I, a);
                 append(new DivOp(IUREM, RDX_I, RAX_I, load(b), state()));
                 return emitMove(RDX_I);
             case Long:
-                emitMove(a, RAX_L);
+                emitMove(RAX_L, a);
                 append(new DivOp(LUREM, RDX_L, RAX_L, load(b), state()));
                 return emitMove(RDX_L);
             default:
@@ -651,7 +667,7 @@
             return value;
         }
         // Non-constant shift count must be in RCX
-        emitMove(value, RCX_I);
+        emitMove(RCX_I, value);
         return RCX_I;
     }
 
@@ -661,67 +677,67 @@
         Variable result = newVariable(opcode.to);
         switch (opcode) {
             case I2L:
-                append(new Op1Reg(I2L, result, input));
+                append(new Unary2Op(I2L, result, input));
                 break;
             case L2I:
-                append(new Op1Stack(L2I, result, input));
+                append(new Unary1Op(L2I, result, input));
                 break;
             case I2B:
-                append(new Op1Stack(I2B, result, input));
+                append(new Unary2Op(I2B, result, input));
                 break;
             case I2C:
-                append(new Op1Stack(I2C, result, input));
+                append(new Unary1Op(I2C, result, input));
                 break;
             case I2S:
-                append(new Op1Stack(I2S, result, input));
+                append(new Unary2Op(I2S, result, input));
                 break;
             case F2D:
-                append(new Op1Reg(F2D, result, input));
+                append(new Unary2Op(F2D, result, input));
                 break;
             case D2F:
-                append(new Op1Reg(D2F, result, input));
+                append(new Unary2Op(D2F, result, input));
                 break;
             case I2F:
-                append(new Op1Reg(I2F, result, input));
+                append(new Unary2Op(I2F, result, input));
                 break;
             case I2D:
-                append(new Op1Reg(I2D, result, input));
+                append(new Unary2Op(I2D, result, input));
                 break;
             case F2I:
-                append(new Op1Reg(F2I, result, input));
+                append(new Unary2Op(F2I, result, input));
                 break;
             case D2I:
-                append(new Op1Reg(D2I, result, input));
+                append(new Unary2Op(D2I, result, input));
                 break;
             case L2F:
-                append(new Op1Reg(L2F, result, input));
+                append(new Unary2Op(L2F, result, input));
                 break;
             case L2D:
-                append(new Op1Reg(L2D, result, input));
+                append(new Unary2Op(L2D, result, input));
                 break;
             case F2L:
-                append(new Op1Reg(F2L, result, input));
+                append(new Unary2Op(F2L, result, input));
                 break;
             case D2L:
-                append(new Op1Reg(D2L, result, input));
+                append(new Unary2Op(D2L, result, input));
                 break;
             case MOV_I2F:
-                append(new Op1Reg(MOV_I2F, result, input));
+                append(new Unary2Op(MOV_I2F, result, input));
                 break;
             case MOV_L2D:
-                append(new Op1Reg(MOV_L2D, result, input));
+                append(new Unary2Op(MOV_L2D, result, input));
                 break;
             case MOV_F2I:
-                append(new Op1Reg(MOV_F2I, result, input));
+                append(new Unary2Op(MOV_F2I, result, input));
                 break;
             case MOV_D2L:
-                append(new Op1Reg(MOV_D2L, result, input));
+                append(new Unary2Op(MOV_D2L, result, input));
                 break;
             case UNSIGNED_I2L:
                 // Instructions that move or generate 32-bit register values also set the upper 32
                 // bits of the register to zero.
                 // Consequently, there is no need for a special zero-extension move.
-                emitMove(input, result);
+                emitMove(result, input);
                 break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
@@ -761,7 +777,7 @@
         // The current register allocator cannot handle variables at call sites, need a fixed
         // register.
         Value targetAddress = AMD64.rax.asValue();
-        emitMove(operand(callTarget.computedAddress()), targetAddress);
+        emitMove(targetAddress, operand(callTarget.computedAddress()));
         append(new IndirectCallOp(callTarget.target(), result, parameters, temps, targetAddress, callState));
     }
 
@@ -777,23 +793,23 @@
     @Override
     public void emitBitCount(Variable result, Value value) {
         if (value.getKind().getStackKind() == Kind.Int) {
-            append(new AMD64BitManipulationOp(IPOPCNT, result, value));
+            append(new AMD64BitManipulationOp(IPOPCNT, result, asAllocatable(value)));
         } else {
-            append(new AMD64BitManipulationOp(LPOPCNT, result, value));
+            append(new AMD64BitManipulationOp(LPOPCNT, result, asAllocatable(value)));
         }
     }
 
     @Override
     public void emitBitScanForward(Variable result, Value value) {
-        append(new AMD64BitManipulationOp(BSF, result, value));
+        append(new AMD64BitManipulationOp(BSF, result, asAllocatable(value)));
     }
 
     @Override
     public void emitBitScanReverse(Variable result, Value value) {
         if (value.getKind().getStackKind() == Kind.Int) {
-            append(new AMD64BitManipulationOp(IBSR, result, value));
+            append(new AMD64BitManipulationOp(IBSR, result, asAllocatable(value)));
         } else {
-            append(new AMD64BitManipulationOp(LBSR, result, value));
+            append(new AMD64BitManipulationOp(LBSR, result, asAllocatable(value)));
         }
     }
 
@@ -885,7 +901,7 @@
         Value expected = loadNonConst(operand(node.expected()));
         Variable newValue = load(operand(node.newValue()));
 
-        Address address;
+        AMD64Address address;
         int displacement = node.displacement();
         Value index = operand(node.offset());
         if (isConstant(index) && NumUtil.isInt(asConstant(index).asLong() + displacement)) {
@@ -897,7 +913,7 @@
         }
 
         RegisterValue rax = AMD64.rax.asValue(kind);
-        emitMove(expected, rax);
+        emitMove(rax, expected);
         append(new CompareAndSwapOp(rax, address, rax, newValue));
 
         Variable result = newVariable(node.kind());
--- a/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java	Fri Mar 01 17:06:08 2013 +0100
@@ -50,7 +50,6 @@
 import com.oracle.graal.lir.ptx.PTXMove.StoreOp;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.ptx.*;
 
@@ -100,55 +99,14 @@
     }
 
     @Override
-    public Address makeAddress(Kind kind, Value base, int displacement) {
-        return new PTXAddress(kind, base, displacement);
-    }
-
-    @Override
-    public Address makeAddress(LocationNode location, ValueNode object) {
-        Value base = operand(object);
-        long displacement = location.displacement();
-
-        if (isConstant(base)) {
-            if (asConstant(base).isNull()) {
-                base = Value.ILLEGAL;
-            } else if (asConstant(base).getKind() != Kind.Object) {
-                displacement += asConstant(base).asLong();
-                base = Value.ILLEGAL;
-            }
-        }
-
-        if (location instanceof IndexedLocationNode) {
-            IndexedLocationNode indexedLoc = (IndexedLocationNode) location;
-
-            Value index = operand(indexedLoc.index());
-            int scale = indexedLoc.indexScaling();
-            if (isConstant(index)) {
-                displacement += asConstant(index).asLong() * scale;
-            } else {
-                if (scale != 1) {
-                    index = emitMul(index, Constant.forInt(scale));
-                }
-                if (base == Value.ILLEGAL) {
-                    base = index;
-                } else {
-                    base = emitAdd(base, index);
-                }
-            }
-        }
-
-        return new PTXAddress(location.getValueKind(), base, displacement);
-    }
-
-    @Override
     public Variable emitMove(Value input) {
         Variable result = newVariable(input.getKind());
-        emitMove(input, result);
+        emitMove(result, input);
         return result;
     }
 
     @Override
-    public void emitMove(Value src, Value dst) {
+    public void emitMove(Value dst, Value src) {
         if (isRegister(src) || isStackSlot(dst)) {
             append(new MoveFromRegOp(dst, src));
         } else {
@@ -156,21 +114,59 @@
         }
     }
 
+    private PTXAddress prepareAddress(Kind kind, Value base, int displacement, Value index, int scale) {
+        Value baseRegister = base;
+        long finalDisp = displacement;
+        if (isConstant(base)) {
+            if (asConstant(base).isNull()) {
+                baseRegister = Value.ILLEGAL;
+            } else if (asConstant(base).getKind() != Kind.Object) {
+                finalDisp += asConstant(base).asLong();
+                baseRegister = Value.ILLEGAL;
+            }
+        }
+
+        if (index != Value.ILLEGAL) {
+            if (isConstant(index)) {
+                finalDisp += asConstant(index).asLong() * scale;
+            } else {
+                Value indexRegister = index;
+                if (scale != 1) {
+                    indexRegister = emitMul(index, Constant.forInt(scale));
+                }
+                if (baseRegister == Value.ILLEGAL) {
+                    baseRegister = indexRegister;
+                } else {
+                    baseRegister = emitAdd(baseRegister, indexRegister);
+                }
+            }
+        }
+
+        return new PTXAddress(kind, baseRegister, finalDisp);
+    }
+
     @Override
-    public Variable emitLoad(Value loadAddress, boolean canTrap) {
+    public Variable emitLoad(Kind kind, Value base, int displacement, Value index, int scale, boolean canTrap) {
+        PTXAddress loadAddress = prepareAddress(kind, base, displacement, index, scale);
         Variable result = newVariable(loadAddress.getKind());
         append(new LoadOp(result, loadAddress, canTrap ? state() : null));
         return result;
     }
 
     @Override
-    public void emitStore(Value storeAddress, Value inputVal, boolean canTrap) {
-        Value input = loadForStore(inputVal, storeAddress.getKind());
+    public void emitStore(Kind kind, Value base, int displacement, Value index, int scale, Value inputVal, boolean canTrap) {
+        PTXAddress storeAddress = prepareAddress(kind, base, displacement, index, scale);
+        Variable input = load(inputVal);
         append(new StoreOp(storeAddress, input, canTrap ? state() : null));
     }
 
     @Override
-    public Variable emitLea(Value address) {
+    public Variable emitLea(Value base, int displacement, Value index, int scale) {
+        throw new InternalError("NYI");
+    }
+
+    @Override
+    public Variable emitLea(StackSlot address) {
         throw new InternalError("NYI");
     }
 
--- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java	Fri Mar 01 17:06:08 2013 +0100
@@ -31,7 +31,6 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.calc.ConvertNode.Op;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 
 /**
@@ -215,36 +214,31 @@
     }
 
     @Override
-    public Address makeAddress(Kind kind, Value base, int displacement) {
-        return null;
+    public void emitMove(Value dst, Value src) {
+        // SPARC: Auto-generated method stub
+
     }
 
     @Override
-    public Address makeAddress(LocationNode location, ValueNode object) {
+    public Value emitLoad(Kind kind, Value base, int displacement, Value index, int scale, boolean canTrap) {
         // SPARC: Auto-generated method stub
         return null;
     }
 
     @Override
-    public void emitMove(Value src, Value dst) {
+    public void emitStore(Kind kind, Value base, int displacement, Value index, int scale, Value input, boolean canTrap) {
         // SPARC: Auto-generated method stub
 
     }
 
     @Override
-    public Value emitLoad(Value loadAddress, boolean canTrap) {
+    public Value emitLea(Value base, int displacement, Value index, int scale) {
         // SPARC: Auto-generated method stub
         return null;
     }
 
     @Override
-    public void emitStore(Value storeAddress, Value input, boolean canTrap) {
-        // SPARC: Auto-generated method stub
-
-    }
-
-    @Override
-    public Value emitLea(Value address) {
+    public Value emitLea(StackSlot address) {
         // SPARC: Auto-generated method stub
         return null;
     }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CompiledMethodTest.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CompiledMethodTest.java	Fri Mar 01 17:06:08 2013 +0100
@@ -112,7 +112,7 @@
         Method method = CompilableObjectImpl.class.getDeclaredMethod("executeHelper", ObjectCompiler.class, String.class);
         ResolvedJavaMethod javaMethod = runtime.lookupJavaMethod(method);
         StructuredGraph graph = new StructuredGraph(javaMethod);
-        new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.NONE).apply(graph);
+        new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.NONE).apply(graph);
         new CanonicalizerPhase(runtime, new Assumptions(false)).apply(graph);
         new DeadCodeEliminationPhase().apply(graph);
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Fri Mar 01 17:06:08 2013 +0100
@@ -407,7 +407,7 @@
     protected StructuredGraph parse(Method m) {
         ResolvedJavaMethod javaMethod = runtime.lookupJavaMethod(m);
         StructuredGraph graph = new StructuredGraph(javaMethod);
-        new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.ALL).apply(graph);
+        new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL).apply(graph);
         return graph;
     }
 
@@ -423,7 +423,7 @@
 
     protected PhasePlan getDefaultPhasePlan() {
         PhasePlan plan = new PhasePlan();
-        plan.addPhase(PhasePosition.AFTER_PARSING, new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.ALL));
+        plan.addPhase(PhasePosition.AFTER_PARSING, new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL));
         return plan;
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java	Fri Mar 01 17:06:08 2013 +0100
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.test;
+
+import static org.junit.Assert.*;
+
+import java.util.concurrent.*;
+
+import org.junit.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.util.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.schedule.*;
+
+/**
+ * In these test the FrameStates are explicitly cleared out, so that the scheduling of
+ * FloatingReadNodes depends solely on the scheduling algorithm. The FrameStates normally keep the
+ * FloatingReadNodes above a certain point, so that they (most of the time...) magically do the
+ * right thing.
+ * 
+ * The scheduling shouldn't depend on FrameStates, which is tested by this class.
+ */
+public class MemoryScheduleTest extends GraphScheduleTest {
+
+    private static enum TestMode {
+        WITH_FRAMESTATES, WITHOUT_FRAMESTATES, INLINED_WITHOUT_FRAMESTATES
+    }
+
+    public static class Container {
+
+        public int a;
+        public int b;
+        public int c;
+    }
+
+    private static final Container container = new Container();
+
+    /**
+     * In this test the read should be scheduled before the write.
+     */
+    public static int testSimpleSnippet() {
+        try {
+            return container.a;
+        } finally {
+            container.a = 15;
+        }
+    }
+
+    @Test
+    public void testSimple() {
+        for (TestMode mode : TestMode.values()) {
+            SchedulePhase schedule = getFinalSchedule("testSimpleSnippet", mode);
+            assertReadAfterWrite(schedule, false);
+        }
+    }
+
+    /**
+     * In this case the read should be scheduled in the first block.
+     */
+    public static int testSplitSnippet1(int a) {
+        try {
+            return container.a;
+        } finally {
+            if (a < 0) {
+                container.a = 15;
+            } else {
+                container.b = 15;
+            }
+        }
+    }
+
+    @Test
+    public void testSplit1() {
+        for (TestMode mode : TestMode.values()) {
+            SchedulePhase schedule = getFinalSchedule("testSplitSnippet1", mode);
+            assertReadWithinStartBlock(schedule, true);
+        }
+    }
+
+    /**
+     * Here the read should float to the end.
+     */
+    public static int testSplit2Snippet(int a) {
+        try {
+            return container.a;
+        } finally {
+            if (a < 0) {
+                container.c = 15;
+            } else {
+                container.b = 15;
+            }
+        }
+    }
+
+    @Test
+    public void testSplit2() {
+        SchedulePhase schedule = getFinalSchedule("testSplit2Snippet", TestMode.WITHOUT_FRAMESTATES);
+        assertReadWithinStartBlock(schedule, false);
+    }
+
+    /**
+     * Here the read should not float to the end.
+     */
+    public static int testLoop1Snippet(int a, int b) {
+        try {
+            return container.a;
+        } finally {
+            for (int i = 0; i < a; i++) {
+                if (b < 0) {
+                    container.b = 10;
+                } else {
+                    container.a = 15;
+                }
+            }
+        }
+    }
+
+    @Test
+    public void testLoop1() {
+        SchedulePhase schedule = getFinalSchedule("testLoop1Snippet", TestMode.WITHOUT_FRAMESTATES);
+        assertEquals(7, schedule.getCFG().getBlocks().length);
+        assertReadWithinStartBlock(schedule, true);
+    }
+
+    /**
+     * Here the read should float to the end.
+     */
+    public static int testLoop2Snippet(int a, int b) {
+        try {
+            return container.a;
+        } finally {
+            for (int i = 0; i < a; i++) {
+                if (b < 0) {
+                    container.b = 10;
+                } else {
+                    container.c = 15;
+                }
+            }
+        }
+    }
+
+    @Test
+    public void testLoop2() {
+        SchedulePhase schedule = getFinalSchedule("testLoop2Snippet", TestMode.WITHOUT_FRAMESTATES);
+        assertEquals(7, schedule.getCFG().getBlocks().length);
+        assertReadWithinStartBlock(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) {
+        System.arraycopy(a, 0, b, 0, len);
+        return intValue.intValue();
+    }
+
+    @Test
+    public void testArrayCopy() {
+        SchedulePhase schedule = getFinalSchedule("testArrayCopySnippet", TestMode.INLINED_WITHOUT_FRAMESTATES);
+        StructuredGraph graph = (StructuredGraph) schedule.getCFG().getStartBlock().getBeginNode().graph();
+        ReturnNode ret = graph.getNodes(ReturnNode.class).first();
+        assertTrue(ret.result() instanceof FloatingReadNode);
+        assertEquals(schedule.getCFG().blockFor(ret), schedule.getCFG().blockFor(ret.result()));
+    }
+
+    private void assertReadAfterWrite(SchedulePhase schedule, boolean readAfterWrite) {
+        boolean writeEncountered = false;
+        assertEquals(1, schedule.getCFG().getBlocks().length);
+        for (Node node : schedule.getBlockToNodesMap().get(schedule.getCFG().getStartBlock())) {
+            if (node instanceof WriteNode) {
+                writeEncountered = true;
+            } else if (node instanceof FloatingReadNode) {
+                assertEquals(readAfterWrite, writeEncountered);
+            }
+        }
+    }
+
+    private void assertReadWithinStartBlock(SchedulePhase schedule, boolean withinStartBlock) {
+        boolean readEncountered = false;
+        for (Node node : schedule.getBlockToNodesMap().get(schedule.getCFG().getStartBlock())) {
+            if (node instanceof FloatingReadNode) {
+                readEncountered = true;
+            }
+        }
+        assertEquals(withinStartBlock, readEncountered);
+    }
+
+    private SchedulePhase getFinalSchedule(final String snippet, final TestMode mode) {
+        return Debug.scope("FloatingReadTest", new DebugDumpScope(snippet), new Callable<SchedulePhase>() {
+
+            @Override
+            public SchedulePhase call() throws Exception {
+                StructuredGraph graph = parse(snippet);
+                if (mode == TestMode.INLINED_WITHOUT_FRAMESTATES) {
+                    Assumptions assumptions = new Assumptions(false);
+                    new InliningPhase(runtime(), null, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph);
+                }
+                new LoweringPhase(null, runtime(), new Assumptions(false)).apply(graph);
+                if (mode == TestMode.WITHOUT_FRAMESTATES || mode == TestMode.INLINED_WITHOUT_FRAMESTATES) {
+                    for (Node node : graph.getNodes()) {
+                        if (node instanceof StateSplit) {
+                            FrameState stateAfter = ((StateSplit) node).stateAfter();
+                            if (stateAfter != null) {
+                                ((StateSplit) node).setStateAfter(null);
+                                GraphUtil.killWithUnusedFloatingInputs(stateAfter);
+                            }
+                        }
+                    }
+                }
+                new FloatingReadPhase().apply(graph);
+
+                new RemoveValueProxyPhase().apply(graph);
+
+                SchedulePhase schedule = new SchedulePhase();
+                schedule.apply(graph);
+                return schedule;
+            }
+        });
+    }
+}
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Fri Mar 01 17:06:08 2013 +0100
@@ -117,7 +117,7 @@
             new InliningPhase(runtime, null, assumptions, cache, plan, optimisticOpts).apply(graph);
             new DeadCodeEliminationPhase().apply(graph);
 
-            if (GraalOptions.CheckCastElimination && GraalOptions.OptCanonicalizer) {
+            if (GraalOptions.ConditionalElimination && GraalOptions.OptCanonicalizer) {
                 new CanonicalizerPhase(runtime, assumptions).apply(graph);
                 new IterativeConditionalEliminationPhase(runtime, assumptions).apply(graph);
             }
@@ -181,7 +181,7 @@
             new EliminatePartiallyRedundantGuardsPhase(false, true).apply(graph);
         }
 
-        if (GraalOptions.CheckCastElimination && GraalOptions.OptCanonicalizer) {
+        if (GraalOptions.ConditionalElimination && GraalOptions.OptCanonicalizer) {
             new IterativeConditionalEliminationPhase(runtime, assumptions).apply(graph);
         }
 
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Fri Mar 01 17:06:08 2013 +0100
@@ -90,6 +90,16 @@
      */
     private final ArrayList<StackSlot> lockDataSlots;
 
+    /**
+     * Checks whether the supplied constant can be used without loading it into a register for store
+     * operations, i.e., on the right hand side of a memory access.
+     * 
+     * @param c The constant to check.
+     * @return True if the constant can be used directly, false if the constant needs to be in a
+     *         register.
+     */
+    public abstract boolean canStoreConstant(Constant c);
+
     public LIRGenerator(StructuredGraph graph, CodeCacheProvider runtime, TargetDescription target, FrameMap frameMap, ResolvedJavaMethod method, LIR lir) {
         this.graph = graph;
         this.runtime = runtime;
@@ -183,6 +193,14 @@
     @Override
     public abstract Variable emitMove(Value input);
 
+    public AllocatableValue asAllocatable(Value value) {
+        if (isAllocatableValue(value)) {
+            return asAllocatableValue(value);
+        } else {
+            return emitMove(value);
+        }
+    }
+
     public Variable load(Value value) {
         if (!isVariable(value)) {
             return emitMove(value);
@@ -197,18 +215,6 @@
         return value;
     }
 
-    public Value loadForStore(Value value, Kind storeKind) {
-        if (isConstant(value) && canStoreConstant((Constant) value)) {
-            return value;
-        }
-        if (storeKind == Kind.Byte || storeKind == Kind.Boolean) {
-            Variable tempVar = new Variable(value.getKind(), lir.nextVariable(), Register.RegisterFlag.Byte);
-            emitMove(value, tempVar);
-            return tempVar;
-        }
-        return load(value);
-    }
-
     protected LabelRef getLIRBlock(FixedNode b) {
         Block result = lir.cfg.blockFor(b);
         int suxIndex = currentBlock.getSuccessors().indexOf(result);
@@ -525,7 +531,7 @@
         Value operand = Value.ILLEGAL;
         if (x.result() != null) {
             operand = resultOperandFor(x.result().kind());
-            emitMove(operand(x.result()), operand);
+            emitMove(operand, operand(x.result()));
         }
         emitReturn(operand);
     }
@@ -747,7 +753,7 @@
         for (ValueNode arg : arguments) {
             if (arg != null) {
                 Value operand = toStackKind(cc.getArgument(j));
-                emitMove(operand(arg), operand);
+                emitMove(operand, operand(arg));
                 result[j] = operand;
                 j++;
             } else {
@@ -770,7 +776,7 @@
         for (int i = 0; i < args.length; i++) {
             Value arg = args[i];
             Value loc = cc.getArgument(i);
-            emitMove(arg, loc);
+            emitMove(loc, arg);
             argLocations[i] = loc;
         }
         emitCall(callTarget, cc.getReturn(), argLocations, cc.getTemporaries(), Constant.forLong(0), info);
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/PhiResolver.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/PhiResolver.java	Fri Mar 01 17:06:08 2013 +0100
@@ -187,7 +187,7 @@
     private void emitMove(Value src, Value dest) {
         assert isLegal(src);
         assert isLegal(dest);
-        gen.emitMove(src, dest);
+        gen.emitMove(dest, src);
     }
 
     // Traverse assignment graph in depth first order and generate moves in post order
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeMap.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeMap.java	Fri Mar 01 17:06:08 2013 +0100
@@ -72,6 +72,10 @@
         assert !isNew(node) : "this node was added to the graph after creating the node map : " + node;
     }
 
+    public void clear() {
+        Arrays.fill(values, null);
+    }
+
     public Iterable<Entry<Node, T>> entries() {
         return new Iterable<Entry<Node, T>>() {
 
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Fri Mar 01 17:06:08 2013 +0100
@@ -112,11 +112,9 @@
         public void visitExceptionObject(ExceptionObjectNode x) {
             HotSpotVMConfig config = runtime().config;
             RegisterValue thread = runtime().threadRegister().asValue();
-            Address exceptionAddress = new AMD64Address(Kind.Object, thread, config.threadExceptionOopOffset);
-            Address pcAddress = new AMD64Address(Kind.Long, thread, config.threadExceptionPcOffset);
-            Value exception = emitLoad(exceptionAddress, false);
-            emitStore(exceptionAddress, Constant.NULL_OBJECT, false);
-            emitStore(pcAddress, Constant.LONG_0, false);
+            Value exception = emitLoad(Kind.Object, thread, config.threadExceptionOopOffset, Value.ILLEGAL, 0, false);
+            emitStore(Kind.Object, thread, config.threadExceptionOopOffset, Value.ILLEGAL, 0, Constant.NULL_OBJECT, false);
+            emitStore(Kind.Long, thread, config.threadExceptionPcOffset, Value.ILLEGAL, 0, Constant.LONG_0, false);
             setResult(x, exception);
         }
 
@@ -130,7 +128,7 @@
             Variable newVal = load(operand(x.newValue()));
 
             int disp = 0;
-            Address address;
+            AMD64Address address;
             Value index = operand(x.offset());
             if (ValueUtil.isConstant(index) && NumUtil.isInt(ValueUtil.asConstant(index).asLong() + disp)) {
                 assert !runtime.needsDataPatch(asConstant(index));
@@ -141,11 +139,11 @@
             }
 
             RegisterValue rax = AMD64.rax.asValue(kind);
-            emitMove(expected, rax);
+            emitMove(rax, expected);
             append(new CompareAndSwapOp(rax, address, rax, newVal));
 
             Variable result = newVariable(x.kind());
-            emitMove(rax, result);
+            emitMove(result, rax);
             setResult(x, result);
         }
 
@@ -163,9 +161,9 @@
         @Override
         protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) {
             Value metaspaceMethod = AMD64.rbx.asValue();
-            emitMove(operand(((HotSpotIndirectCallTargetNode) callTarget).metaspaceMethod()), metaspaceMethod);
+            emitMove(metaspaceMethod, operand(((HotSpotIndirectCallTargetNode) callTarget).metaspaceMethod()));
             Value targetAddress = AMD64.rax.asValue();
-            emitMove(operand(callTarget.computedAddress()), targetAddress);
+            emitMove(targetAddress, operand(callTarget.computedAddress()));
             append(new AMD64IndirectCallOp(callTarget.target(), result, parameters, temps, metaspaceMethod, targetAddress, callState));
         }
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ArrayWriteBarrier.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ArrayWriteBarrier.java	Fri Mar 01 17:06:08 2013 +0100
@@ -47,7 +47,7 @@
 
     @Override
     public void generate(LIRGeneratorTool gen) {
-        Value addr = gen.emitLea(gen.makeAddress(location(), object()));
+        Value addr = location().generateLea(gen, object());
         generateBarrier(addr, gen);
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java	Fri Mar 01 17:06:08 2013 +0100
@@ -52,6 +52,11 @@
     }
 
     @Override
+    public Object getLocationIdentity() {
+        return LocationNode.ANY_LOCATION;
+    }
+
+    @Override
     public void generate(LIRGenerator gen) {
         gen.lock();
         StackSlot lockData = gen.peekLock();
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentThread.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentThread.java	Fri Mar 01 17:06:08 2013 +0100
@@ -42,7 +42,7 @@
     public void generate(LIRGeneratorTool gen) {
         HotSpotGraalRuntime runtime = HotSpotGraalRuntime.getInstance();
         Register thread = runtime.getRuntime().threadRegister();
-        gen.setResult(this, gen.emitLoad(gen.makeAddress(Kind.Object, thread.asValue(gen.target().wordKind), runtime.getConfig().threadObjectOffset), false));
+        gen.setResult(this, gen.emitLoad(Kind.Object, thread.asValue(gen.target().wordKind), runtime.getConfig().threadObjectOffset, Value.ILLEGAL, 0, false));
     }
 
     @NodeIntrinsic
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DirectCompareAndSwapNode.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DirectCompareAndSwapNode.java	Fri Mar 01 17:06:08 2013 +0100
@@ -32,8 +32,8 @@
 
 /**
  * A special purpose store node that differs from {@link CompareAndSwapNode} in that it is not a
- * {@link StateSplit} and it {@linkplain #compareAndSwap(Object, long, Word, Word) returns} either
- * the expected value or the compared against value instead of a boolean.
+ * {@link StateSplit} and it {@linkplain #compareAndSwap(Object, long, Word, Word, Object)} returns
+ * either the expected value or the compared against value instead of a boolean.
  */
 public class DirectCompareAndSwapNode extends FixedWithNextNode implements LIRGenLowerable, MemoryCheckpoint {
 
@@ -42,17 +42,15 @@
     @Input private ValueNode expectedValue;
     @Input private ValueNode newValue;
 
-    public DirectCompareAndSwapNode(ValueNode object, ValueNode offset, ValueNode expected, ValueNode newValue) {
+    private final Object locationIdentity;
+
+    public DirectCompareAndSwapNode(ValueNode object, ValueNode offset, ValueNode expected, ValueNode newValue, Object locationIdentity) {
         super(expected.stamp());
         this.object = object;
         this.offset = offset;
         this.expectedValue = expected;
         this.newValue = newValue;
-    }
-
-    @Override
-    public void generate(LIRGenerator gen) {
-        ((HotSpotLIRGenerator) gen).visitDirectCompareAndSwap(this);
+        this.locationIdentity = locationIdentity;
     }
 
     public ValueNode object() {
@@ -71,6 +69,16 @@
         return newValue;
     }
 
+    @Override
+    public Object getLocationIdentity() {
+        return locationIdentity;
+    }
+
+    @Override
+    public void generate(LIRGenerator gen) {
+        ((HotSpotLIRGenerator) gen).visitDirectCompareAndSwap(this);
+    }
+
     /**
      * Compares an expected value with the actual value in a location denoted by an object and a
      * given offset. Iff they are same, {@code newValue} is placed into the location and the
@@ -84,5 +92,5 @@
      * @return either {@code expectedValue} or the actual value
      */
     @NodeIntrinsic
-    public static native Word compareAndSwap(Object object, long offset, Word expectedValue, Word newValue);
+    public static native Word compareAndSwap(Object object, long offset, Word expectedValue, Word newValue, @ConstantNodeParameter Object locationIdentity);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EndLockScopeNode.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EndLockScopeNode.java	Fri Mar 01 17:06:08 2013 +0100
@@ -44,6 +44,11 @@
     }
 
     @Override
+    public Object getLocationIdentity() {
+        return LocationNode.ANY_LOCATION;
+    }
+
+    @Override
     public void generate(LIRGenerator gen) {
         gen.unlock();
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/FieldWriteBarrier.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/FieldWriteBarrier.java	Fri Mar 01 17:06:08 2013 +0100
@@ -41,7 +41,7 @@
     @Override
     public void generate(LIRGeneratorTool generator) {
         Value obj = generator.newVariable(generator.target().wordKind);
-        generator.emitMove(generator.operand(object()), obj);
+        generator.emitMove(obj, generator.operand(object()));
         generateBarrier(obj, generator);
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/GetObjectAddressNode.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/GetObjectAddressNode.java	Fri Mar 01 17:06:08 2013 +0100
@@ -47,7 +47,7 @@
     @Override
     public void generate(LIRGeneratorTool gen) {
         Value obj = gen.newVariable(gen.target().wordKind);
-        gen.emitMove(gen.operand(object), obj);
+        gen.emitMove(obj, gen.operand(object));
         gen.setResult(this, obj);
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/RegisterNode.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/RegisterNode.java	Fri Mar 01 17:06:08 2013 +0100
@@ -54,7 +54,7 @@
             // The register allocator would prefer us not to tie up an allocatable
             // register for the complete lifetime of this node.
             result = generator.newVariable(kind());
-            generator.emitMove(register.asValue(kind()), result);
+            generator.emitMove(result, register.asValue(kind()));
         } else {
             result = register.asValue(kind());
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/TailcallNode.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/TailcallNode.java	Fri Mar 01 17:06:08 2013 +0100
@@ -69,7 +69,7 @@
             parameters.add(frameState.localAt(slot));
         }
         Value[] args = gen.visitInvokeArguments(cc, parameters);
-        Value entry = gen.emitLoad(gen.makeAddress(Kind.Long, gen.operand(target), config.nmethodEntryOffset), false);
+        Value entry = gen.emitLoad(Kind.Long, gen.operand(target), config.nmethodEntryOffset, Value.ILLEGAL, 0, false);
         HotSpotLIRGenerator hsgen = (HotSpotLIRGenerator) gen;
         hsgen.emitTailcall(args, entry);
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrier.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrier.java	Fri Mar 01 17:06:08 2013 +0100
@@ -45,6 +45,6 @@
         } else {
             base = gen.emitAdd(base, Constant.forLong(config.cardtableStartAddress));
         }
-        gen.emitStore(gen.makeAddress(Kind.Boolean, base, displacement), Constant.FALSE, false);
+        gen.emitStore(Kind.Boolean, base, displacement, Value.ILLEGAL, 0, Constant.FALSE, false);
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/OnStackReplacementPhase.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/OnStackReplacementPhase.java	Fri Mar 01 17:06:08 2013 +0100
@@ -26,14 +26,16 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.code.RuntimeCallTarget.*;
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Node.*;
 import com.oracle.graal.graph.iterators.*;
+import com.oracle.graal.java.*;
 import com.oracle.graal.loop.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.*;
@@ -43,6 +45,27 @@
 
     public static final Descriptor OSR_MIGRATION_END = new Descriptor("OSR_migration_end", true, void.class, long.class);
 
+    public class OSREntryProxyNode extends FloatingNode implements LIRLowerable {
+
+        @Input private ValueNode object;
+        @Input(notDataflow = true) private final RuntimeCallNode anchor;
+
+        public OSREntryProxyNode(ValueNode object, RuntimeCallNode anchor) {
+            super(object.stamp());
+            this.object = object;
+            this.anchor = anchor;
+        }
+
+        public RuntimeCallNode getAnchor() {
+            return anchor;
+        }
+
+        @Override
+        public void generate(LIRGeneratorTool generator) {
+            generator.setResult(this, generator.operand(object));
+        }
+    }
+
     @Override
     protected void run(StructuredGraph graph) {
         if (graph.getEntryBCI() == StructuredGraph.INVOCATION_ENTRY_BCI) {
@@ -81,7 +104,7 @@
 
             LoopTransformations.peel(osrLoop);
             for (Node usage : osr.usages().snapshot()) {
-                ValueProxyNode proxy = (ValueProxyNode) usage;
+                ProxyNode proxy = (ProxyNode) usage;
                 proxy.replaceAndDelete(proxy.value());
             }
             FixedNode next = osr.next();
@@ -108,15 +131,17 @@
         start.setStateAfter(null);
         GraphUtil.killWithUnusedFloatingInputs(oldStartState);
 
+        // mirroring the calculations in c1_GraphBuilder.cpp (setup_osr_entry_block)
         int localsOffset = (graph.method().getMaxLocals() - 1) * 8;
         for (int i = 0; i < osrState.localsSize(); i++) {
             ValueNode value = osrState.localAt(i);
             if (value != null) {
-                ValueProxyNode proxy = (ValueProxyNode) value;
-                int size = (value.kind() == Kind.Long || value.kind() == Kind.Double) ? 2 : 1;
+                ProxyNode proxy = (ProxyNode) value;
+                int size = FrameStateBuilder.stackSlots(value.kind());
                 int offset = localsOffset - (i + size - 1) * 8;
                 UnsafeLoadNode load = graph.add(new UnsafeLoadNode(buffer, offset, ConstantNode.forInt(0, graph), value.kind()));
-                proxy.replaceAndDelete(load);
+                OSREntryProxyNode newProxy = graph.add(new OSREntryProxyNode(load, migrationEnd));
+                proxy.replaceAndDelete(newProxy);
                 graph.addBeforeFixed(migrationEnd, load);
             }
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/AESCryptSubstitutions.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/AESCryptSubstitutions.java	Fri Mar 01 17:06:08 2013 +0100
@@ -70,7 +70,7 @@
     }
 
     private static void crypt(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset, boolean encrypt) {
-        Word kAddr = Word.fromObject(rcvr).readWord(Word.unsigned(kOffset)).add(arrayBaseOffset(Kind.Byte));
+        Word kAddr = Word.fromObject(rcvr).readWord(Word.unsigned(kOffset), UNKNOWN_LOCATION).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);
         if (encrypt) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ArrayCopyNode.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ArrayCopyNode.java	Fri Mar 01 17:06:08 2013 +0100
@@ -30,6 +30,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.virtual.*;
+import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.snippets.nodes.*;
 
@@ -59,21 +60,19 @@
         return arguments.get(4);
     }
 
-    private ResolvedJavaMethod selectSnippet(LoweringTool tool) {
+    private StructuredGraph selectSnippet(LoweringTool tool) {
         ResolvedJavaType srcType = getSource().objectStamp().type();
         ResolvedJavaType destType = getDestination().objectStamp().type();
 
-        if (srcType != null && srcType.isArray() && destType != null && destType.isArray()) {
-            Kind componentKind = srcType.getComponentType().getKind();
-            if (componentKind != Kind.Object) {
-                if (srcType.getComponentType() == destType.getComponentType()) {
-                    return tool.getRuntime().lookupJavaMethod(ArrayCopySnippets.getSnippetForKind(componentKind));
-                }
-            } else if (destType.getComponentType().isAssignableFrom(srcType.getComponentType()) && getDestination().objectStamp().isExactType()) {
-                return tool.getRuntime().lookupJavaMethod(ArrayCopySnippets.getSnippetForKind(Kind.Object));
-            }
+        if (srcType == null || !srcType.isArray() || destType == null || !destType.isArray()) {
+            return null;
         }
-        return null;
+        if (!destType.getComponentType().isAssignableFrom(srcType.getComponentType()) || !getDestination().objectStamp().isExactType()) {
+            return null;
+        }
+        Kind componentKind = srcType.getComponentType().getKind();
+        ResolvedJavaMethod snippetMethod = tool.getRuntime().lookupJavaMethod(ArrayCopySnippets.getSnippetForKind(componentKind));
+        return (StructuredGraph) snippetMethod.getCompilerStorage().get(Graph.class);
     }
 
     private static void unrollFixedLengthLoop(StructuredGraph snippetGraph, int length, LoweringTool tool) {
@@ -88,27 +87,43 @@
         new CanonicalizerPhase(tool.getRuntime(), tool.assumptions()).apply(snippetGraph);
     }
 
+    private static void replaceSnippetInvokes(StructuredGraph snippetGraph, ResolvedJavaMethod targetMethod, int bci) {
+        for (InvokeNode invoke : snippetGraph.getNodes(InvokeNode.class)) {
+            if (invoke.methodCallTarget().targetMethod() != targetMethod) {
+                throw new GraalInternalError("unexpected invoke in arraycopy snippet");
+            }
+            if (invoke.stateAfter().bci == FrameState.INVALID_FRAMESTATE_BCI) {
+                InvokeNode newInvoke = snippetGraph.add(new InvokeNode(invoke.methodCallTarget(), bci));
+                newInvoke.setStateAfter(snippetGraph.add(new FrameState(FrameState.AFTER_BCI)));
+                snippetGraph.replaceFixedWithFixed(invoke, newInvoke);
+            } else {
+                assert invoke.stateAfter().bci == FrameState.AFTER_BCI : invoke;
+            }
+        }
+    }
+
     @Override
-    public void lower(LoweringTool tool) {
-        ResolvedJavaMethod snippetMethod = selectSnippet(tool);
-        if (snippetMethod == null) {
-            snippetMethod = tool.getRuntime().lookupJavaMethod(ArrayCopySnippets.increaseGenericCallCounterMethod);
-            // we will call the generic method. the generic snippet will only increase the counter,
-            // not call the actual method. therefore we create a second invoke here.
-            ((StructuredGraph) graph()).addAfterFixed(this, createInvoke());
-        }
-        if (Debug.isLogEnabled()) {
-            Debug.log("%s > Intrinsify (%s)", Debug.currentScope(), snippetMethod.getSignature().getParameterType(0, snippetMethod.getDeclaringClass()).getComponentType());
+    protected StructuredGraph getSnippetGraph(LoweringTool tool) {
+        if (!GraalOptions.IntrinsifyArrayCopy) {
+            return null;
         }
 
-        StructuredGraph snippetGraph = (StructuredGraph) snippetMethod.getCompilerStorage().get(Graph.class);
-        assert snippetGraph != null : "ArrayCopySnippets should be installed";
-        if (getLength().isConstant()) {
-            snippetGraph = snippetGraph.copy();
-            unrollFixedLengthLoop(snippetGraph, getLength().asConstant().asInt(), tool);
+        StructuredGraph snippetGraph = selectSnippet(tool);
+        if (snippetGraph == null) {
+            ResolvedJavaMethod snippetMethod = tool.getRuntime().lookupJavaMethod(ArrayCopySnippets.genericArraycopySnippet);
+            snippetGraph = ((StructuredGraph) snippetMethod.getCompilerStorage().get(Graph.class)).copy();
+            assert snippetGraph != null : "ArrayCopySnippets should be installed";
+
+            replaceSnippetInvokes(snippetGraph, getTargetMethod(), getBci());
+        } else {
+            assert snippetGraph != null : "ArrayCopySnippets should be installed";
+
+            if (getLength().isConstant()) {
+                snippetGraph = snippetGraph.copy();
+                unrollFixedLengthLoop(snippetGraph, getLength().asConstant().asInt(), tool);
+            }
         }
-        InvokeNode invoke = replaceWithInvoke();
-        InliningUtil.inline(invoke, snippetGraph, false);
+        return snippetGraph;
     }
 
     private static boolean checkBounds(int position, int length, VirtualObjectNode virtualObject) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ArrayCopySnippets.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ArrayCopySnippets.java	Fri Mar 01 17:06:08 2013 +0100
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.hotspot.snippets;
 
-import static com.oracle.graal.api.code.DeoptimizationAction.*;
-import static com.oracle.graal.api.meta.DeoptimizationReason.*;
 import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*;
 import static com.oracle.graal.snippets.nodes.BranchProbabilityNode.*;
 
@@ -33,24 +31,21 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
-import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.snippets.*;
 import com.oracle.graal.snippets.Snippet.ConstantParameter;
-import com.oracle.graal.snippets.Snippet.Fold;
 import com.oracle.graal.snippets.nodes.*;
+import com.oracle.graal.word.*;
 
 @SuppressWarnings("unused")
 public class ArrayCopySnippets implements SnippetsInterface {
 
     private static final EnumMap<Kind, Method> arraycopyMethods = new EnumMap<>(Kind.class);
-    public static final Method increaseGenericCallCounterMethod;
+    public static final Method genericArraycopySnippet;
 
     private static void addArraycopySnippetMethod(Kind kind, Class<?> arrayClass) throws NoSuchMethodException {
         arraycopyMethods.put(kind, ArrayCopySnippets.class.getDeclaredMethod("arraycopy", arrayClass, int.class, arrayClass, int.class, int.class));
@@ -67,7 +62,7 @@
             addArraycopySnippetMethod(Kind.Float, float[].class);
             addArraycopySnippetMethod(Kind.Double, double[].class);
             addArraycopySnippetMethod(Kind.Object, Object[].class);
-            increaseGenericCallCounterMethod = ArrayCopySnippets.class.getDeclaredMethod("increaseGenericCallCounter", Object.class, int.class, Object.class, int.class, int.class);
+            genericArraycopySnippet = ArrayCopySnippets.class.getDeclaredMethod("arraycopy", Object.class, int.class, Object.class, int.class, int.class);
         } catch (SecurityException | NoSuchMethodException e) {
             throw new GraalInternalError(e);
         }
@@ -81,7 +76,9 @@
     private static final long VECTOR_SIZE = arrayIndexScale(Kind.Long);
 
     public static void vectorizedCopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter("baseKind") Kind baseKind) {
-        checkInputs(src, srcPos, dest, destPos, length);
+        checkNonNull(src);
+        checkNonNull(dest);
+        checkLimits(src, srcPos, dest, destPos, length);
         int header = arrayBaseOffset(baseKind);
         int elementSize = arrayIndexScale(baseKind);
         long byteLength = (long) length * elementSize;
@@ -109,17 +106,24 @@
         }
     }
 
-    public static void checkInputs(Object src, int srcPos, Object dest, int destPos, int length) {
-        if (src == null) {
+    public static void checkNonNull(Object obj) {
+        if (obj == null) {
             probability(DEOPT_PATH_PROBABILITY);
             checkNPECounter.inc();
             DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
         }
-        if (dest == null) {
+    }
+
+    public static int checkArrayType(Word hub) {
+        int layoutHelper = readLayoutHelper(hub);
+        if (layoutHelper >= 0) {
             probability(DEOPT_PATH_PROBABILITY);
-            checkNPECounter.inc();
             DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
         }
+        return layoutHelper;
+    }
+
+    public static void checkLimits(Object src, int srcPos, Object dest, int destPos, int length) {
         if (srcPos < 0) {
             probability(DEOPT_PATH_PROBABILITY);
             checkAIOOBECounter.inc();
@@ -187,7 +191,9 @@
     @Snippet
     public static void arraycopy(long[] src, int srcPos, long[] dest, int destPos, int length) {
         longCounter.inc();
-        checkInputs(src, srcPos, dest, destPos, length);
+        checkNonNull(src);
+        checkNonNull(dest);
+        checkLimits(src, srcPos, dest, destPos, length);
         Kind baseKind = Kind.Long;
         int header = arrayBaseOffset(baseKind);
         long byteLength = (long) length * arrayIndexScale(baseKind);
@@ -209,7 +215,9 @@
     @Snippet
     public static void arraycopy(double[] src, int srcPos, double[] dest, int destPos, int length) {
         doubleCounter.inc();
-        checkInputs(src, srcPos, dest, destPos, length);
+        checkNonNull(src);
+        checkNonNull(dest);
+        checkLimits(src, srcPos, dest, destPos, length);
         Kind baseKind = Kind.Double;
         int header = arrayBaseOffset(baseKind);
         long byteLength = (long) length * arrayIndexScale(baseKind);
@@ -232,7 +240,9 @@
     @Snippet
     public static void arraycopy(Object[] src, int srcPos, Object[] dest, int destPos, int length) {
         objectCounter.inc();
-        checkInputs(src, srcPos, dest, destPos, length);
+        checkNonNull(src);
+        checkNonNull(dest);
+        checkLimits(src, srcPos, dest, destPos, length);
         final int scale = arrayIndexScale(Kind.Object);
         int header = arrayBaseOffset(Kind.Object);
         if (src == dest && srcPos < destPos) { // bad aliased case
@@ -262,12 +272,67 @@
     }
 
     @Snippet
-    public static void increaseGenericCallCounter(Object src, int srcPos, Object dest, int destPos, int length) {
-        if (GraalOptions.SnippetCounters) {
-            if (src.getClass().getComponentType().isPrimitive()) {
-                genericPrimitiveCallCounter.inc();
-            } else {
-                genericObjectCallCounter.inc();
+    public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length) {
+
+        // loading the hubs also checks for nullness
+        Word srcHub = loadHub(src);
+        Word destHub = loadHub(dest);
+
+        int layoutHelper = checkArrayType(srcHub);
+        if (srcHub.equal(destHub) && src != dest) {
+            probability(FAST_PATH_PROBABILITY);
+
+            checkLimits(src, srcPos, dest, destPos, length);
+
+            arraycopyInnerloop(src, srcPos, dest, destPos, length, layoutHelper);
+        } else {
+            genericObjectCallCounter.inc();
+            System.arraycopy(src, srcPos, dest, destPos, length);
+        }
+    }
+
+    public static void arraycopyInnerloop(Object src, int srcPos, Object dest, int destPos, int length, int layoutHelper) {
+        int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask();
+        int headerSize = (layoutHelper >> layoutHelperHeaderSizeShift()) & layoutHelperHeaderSizeMask();
+
+        Word memory = (Word) Word.fromObject(src);
+
+        Word srcOffset = (Word) Word.fromObject(src).add(headerSize).add(srcPos << log2ElementSize);
+        Word destOffset = (Word) Word.fromObject(dest).add(headerSize).add(destPos << log2ElementSize);
+        Word destStart = destOffset;
+        long sizeInBytes = ((long) length) << log2ElementSize;
+        Word destEnd = destOffset.add(Word.unsigned(length).shiftLeft(log2ElementSize));
+
+        int nonVectorBytes = (int) (sizeInBytes % VECTOR_SIZE);
+        Word destNonVectorEnd = destStart.add(nonVectorBytes);
+
+        while (destOffset.belowThan(destNonVectorEnd)) {
+            destOffset.writeByte(0, srcOffset.readByte(0, UNKNOWN_LOCATION), ANY_LOCATION);
+            destOffset = destOffset.add(1);
+            srcOffset = srcOffset.add(1);
+        }
+        while (destOffset.belowThan(destEnd)) {
+            destOffset.writeWord(0, srcOffset.readWord(0, UNKNOWN_LOCATION), ANY_LOCATION);
+            destOffset = destOffset.add(wordSize());
+            srcOffset = srcOffset.add(wordSize());
+        }
+
+        if ((layoutHelper & layoutHelperElementTypePrimitiveInPlace()) != 0) {
+            genericPrimitiveCallCounter.inc();
+
+        } else {
+            probability(LIKELY_PROBABILITY);
+            genericObjectExactCallCounter.inc();
+
+            if (length > 0) {
+                int cardShift = cardTableShift();
+                long cardStart = cardTableStart();
+                Word destCardOffset = destStart.unsignedShiftRight(cardShift).add(Word.unsigned(cardStart));
+                Word destCardEnd = destEnd.subtract(1).unsignedShiftRight(cardShift).add(Word.unsigned(cardStart));
+                while (destCardOffset.belowOrEqual(destCardEnd)) {
+                    DirectStoreNode.store(destCardOffset.rawValue(), false, Kind.Boolean);
+                    destCardOffset = destCardOffset.add(1);
+                }
             }
         }
     }
@@ -287,7 +352,8 @@
     private static final SnippetCounter objectCounter = new SnippetCounter(counters, "Object[]", "arraycopy for Object[] arrays");
     private static final SnippetCounter floatCounter = new SnippetCounter(counters, "float[]", "arraycopy for float[] arrays");
     private static final SnippetCounter doubleCounter = new SnippetCounter(counters, "double[]", "arraycopy for double[] arrays");
-    private static final SnippetCounter genericPrimitiveCallCounter = new SnippetCounter(counters, "genericPrimitive", "call to the generic, native arraycopy method");
+    private static final SnippetCounter genericPrimitiveCallCounter = new SnippetCounter(counters, "genericPrimitive", "generic arraycopy snippet for primitive arrays");
+    private static final SnippetCounter genericObjectExactCallCounter = new SnippetCounter(counters, "genericObjectExact", "generic arraycopy snippet for special object arrays");
     private static final SnippetCounter genericObjectCallCounter = new SnippetCounter(counters, "genericObject", "call to the generic, native arraycopy method");
 
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java	Fri Mar 01 17:06:08 2013 +0100
@@ -108,7 +108,7 @@
             isNull.inc();
         } else {
             Word objectHub = loadHub(object);
-            if (objectHub.readWord(superCheckOffset).notEqual(hub)) {
+            if (objectHub.readWord(superCheckOffset, FINAL_LOCATION).notEqual(hub)) {
                 probability(DEOPT_PATH_PROBABILITY);
                 displayMiss.inc();
                 DeoptimizeNode.deopt(InvalidateReprofile, ClassCastException);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CipherBlockChainingSubstitutions.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CipherBlockChainingSubstitutions.java	Fri Mar 01 17:06:08 2013 +0100
@@ -66,7 +66,7 @@
 
     @MethodSubstitution(isStatic = false)
     static void encrypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) {
-        Object embeddedCipher = Word.fromObject(rcvr).readObject(Word.unsigned(embeddedCipherOffset));
+        Object embeddedCipher = Word.fromObject(rcvr).readObject(Word.unsigned(embeddedCipherOffset), UNKNOWN_LOCATION);
         if (getAESCryptClass().isInstance(embeddedCipher)) {
             crypt(rcvr, in, inOffset, inLength, out, outOffset, embeddedCipher, true);
         } else {
@@ -75,8 +75,8 @@
     }
 
     private static void crypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset, Object embeddedCipher, boolean encrypt) {
-        Word kAddr = Word.fromObject(embeddedCipher).readWord(Word.unsigned(AESCryptSubstitutions.kOffset)).add(arrayBaseOffset(Kind.Byte));
-        Word rAddr = Word.unsigned(GetObjectAddressNode.get(rcvr)).readWord(Word.unsigned(rOffset)).add(arrayBaseOffset(Kind.Byte));
+        Word kAddr = Word.fromObject(embeddedCipher).readWord(Word.unsigned(AESCryptSubstitutions.kOffset), UNKNOWN_LOCATION).add(arrayBaseOffset(Kind.Byte));
+        Word rAddr = Word.unsigned(GetObjectAddressNode.get(rcvr)).readWord(Word.unsigned(rOffset), UNKNOWN_LOCATION).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);
         if (encrypt) {
@@ -89,7 +89,7 @@
 
     @MethodSubstitution(isStatic = false)
     static void decrypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) {
-        Object embeddedCipher = Word.fromObject(rcvr).readObject(Word.unsigned(embeddedCipherOffset));
+        Object embeddedCipher = Word.fromObject(rcvr).readObject(Word.unsigned(embeddedCipherOffset), UNKNOWN_LOCATION);
         if (in != out && getAESCryptClass().isInstance(embeddedCipher)) {
             crypt(rcvr, in, inOffset, inLength, out, outOffset, embeddedCipher, false);
         } else {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ClassSubstitutions.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ClassSubstitutions.java	Fri Mar 01 17:06:08 2013 +0100
@@ -45,7 +45,7 @@
             // Class for primitive type
             return Modifier.ABSTRACT | Modifier.FINAL | Modifier.PUBLIC;
         } else {
-            return klass.readInt(klassModifierFlagsOffset());
+            return klass.readInt(klassModifierFlagsOffset(), FINAL_LOCATION);
         }
     }
 
@@ -55,7 +55,7 @@
         if (klass.equal(0)) {
             return false;
         } else {
-            int accessFlags = klass.readInt(klassAccessFlagsOffset());
+            int accessFlags = klass.readInt(klassAccessFlagsOffset(), FINAL_LOCATION);
             return (accessFlags & Modifier.INTERFACE) != 0;
         }
     }
@@ -66,8 +66,7 @@
         if (klass.equal(0)) {
             return false;
         } else {
-            int layoutHelper = klass.readInt(klassLayoutHelperOffset());
-            return (layoutHelper & arrayKlassLayoutHelperIdentifier()) != 0;
+            return (readLayoutHelper(klass) & arrayKlassLayoutHelperIdentifier()) != 0;
         }
     }
 
@@ -81,17 +80,16 @@
     public static Class<?> getSuperclass(final Class<?> thisObj) {
         Word klass = loadWordFromObject(thisObj, klassOffset());
         if (klass.notEqual(0)) {
-            int accessFlags = klass.readInt(klassAccessFlagsOffset());
+            int accessFlags = klass.readInt(klassAccessFlagsOffset(), FINAL_LOCATION);
             if ((accessFlags & Modifier.INTERFACE) == 0) {
-                int layoutHelper = klass.readInt(klassLayoutHelperOffset());
-                if ((layoutHelper & arrayKlassLayoutHelperIdentifier()) != 0) {
+                if ((readLayoutHelper(klass) & arrayKlassLayoutHelperIdentifier()) != 0) {
                     return Object.class;
                 } else {
-                    Word superKlass = klass.readWord(klassSuperKlassOffset());
+                    Word superKlass = klass.readWord(klassSuperKlassOffset(), FINAL_LOCATION);
                     if (superKlass.equal(0)) {
                         return null;
                     } else {
-                        return unsafeCast(superKlass.readObject(classMirrorOffset()), Class.class, true, true);
+                        return unsafeCast(superKlass.readObject(classMirrorOffset(), FINAL_LOCATION), Class.class, true, true);
                     }
                 }
             }
@@ -103,9 +101,8 @@
     public static Class<?> getComponentType(final Class<?> thisObj) {
         Word klass = loadWordFromObject(thisObj, klassOffset());
         if (klass.notEqual(0)) {
-            int layoutHelper = klass.readInt(klassLayoutHelperOffset());
-            if ((layoutHelper & arrayKlassLayoutHelperIdentifier()) != 0) {
-                return unsafeCast(klass.readObject(arrayKlassComponentMirrorOffset()), Class.class, true, true);
+            if ((readLayoutHelper(klass) & arrayKlassLayoutHelperIdentifier()) != 0) {
+                return unsafeCast(klass.readObject(arrayKlassComponentMirrorOffset(), FINAL_LOCATION), Class.class, true, true);
             }
         }
         return null;
@@ -113,6 +110,6 @@
 
     @MethodSubstitution(isStatic = false)
     public static boolean isInstance(final Class<?> thisObj, Object obj) {
-        return !thisObj.isPrimitive() && ConditionalNode.materializeIsInstance(thisObj, obj);
+        return !isPrimitive(thisObj) && ConditionalNode.materializeIsInstance(thisObj, obj);
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/HotSpotSnippetUtils.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/HotSpotSnippetUtils.java	Fri Mar 01 17:06:08 2013 +0100
@@ -43,6 +43,10 @@
  */
 public class HotSpotSnippetUtils {
 
+    public static final Object ANY_LOCATION = LocationNode.ANY_LOCATION;
+    public static final Object UNKNOWN_LOCATION = LocationNode.UNKNOWN_LOCATION;
+    public static final Object FINAL_LOCATION = LocationNode.FINAL_LOCATION;
+
     public static HotSpotVMConfig config() {
         return HotSpotGraalRuntime.getInstance().getConfig();
     }
@@ -52,16 +56,49 @@
         return config().verifyOops;
     }
 
+    public static final Object TLAB_TOP_LOCATION = LocationNode.createLocation("TlabTop");
+
     @Fold
     public static int threadTlabTopOffset() {
         return config().threadTlabTopOffset;
     }
 
+    public static final Object TLAB_END_LOCATION = LocationNode.createLocation("TlabEnd");
+
     @Fold
-    public static int threadTlabEndOffset() {
+    private static int threadTlabEndOffset() {
         return config().threadTlabEndOffset;
     }
 
+    public static final Object TLAB_START_LOCATION = LocationNode.createLocation("TlabStart");
+
+    @Fold
+    private static int threadTlabStartOffset() {
+        return config().threadTlabStartOffset;
+    }
+
+    public static Word readTlabTop(Word thread) {
+        return thread.readWord(threadTlabTopOffset(), TLAB_TOP_LOCATION);
+    }
+
+    public static Word readTlabEnd(Word thread) {
+        return thread.readWord(threadTlabEndOffset(), TLAB_END_LOCATION);
+    }
+
+    public static Word readTlabStart(Word thread) {
+        return thread.readWord(threadTlabStartOffset(), TLAB_START_LOCATION);
+    }
+
+    public static void writeTlabTop(Word thread, Word top) {
+        thread.writeWord(threadTlabTopOffset(), top, TLAB_TOP_LOCATION);
+    }
+
+    public static void initializeTlab(Word thread, Word start, Word end) {
+        thread.writeWord(threadTlabStartOffset(), start, TLAB_START_LOCATION);
+        thread.writeWord(threadTlabTopOffset(), start, TLAB_TOP_LOCATION);
+        thread.writeWord(threadTlabEndOffset(), end, TLAB_END_LOCATION);
+    }
+
     @Fold
     public static int threadObjectOffset() {
         return config().threadObjectOffset;
@@ -102,6 +139,8 @@
         return Unsafe.getUnsafe().pageSize();
     }
 
+    public static final Object PROTOTYPE_MARK_WORD_LOCATION = LocationNode.createLocation("PrototypeMarkWord");
+
     @Fold
     public static int prototypeMarkWordOffset() {
         return config().prototypeMarkWordOffset;
@@ -118,10 +157,14 @@
     }
 
     @Fold
-    public static int klassLayoutHelperOffset() {
+    private static int klassLayoutHelperOffset() {
         return config().klassLayoutHelperOffset;
     }
 
+    public static int readLayoutHelper(Word hub) {
+        return hub.readInt(klassLayoutHelperOffset(), FINAL_LOCATION);
+    }
+
     @Fold
     public static int arrayKlassLayoutHelperIdentifier() {
         return config().arrayKlassLayoutHelperIdentifier;
@@ -137,11 +180,25 @@
         return config().klassSuperKlassOffset;
     }
 
+    public static final Object MARK_WORD_LOCATION = LocationNode.createLocation("MarkWord");
+
     @Fold
     public static int markOffset() {
         return config().markOffset;
     }
 
+    public static final Object HUB_LOCATION = LocationNode.createLocation("Hub");
+
+    @Fold
+    private static int hubOffset() {
+        return config().hubOffset;
+    }
+
+    public static void initializeObjectHeader(Word memory, Word markWord, Word hub) {
+        memory.writeWord(markOffset(), markWord, MARK_WORD_LOCATION);
+        memory.writeWord(hubOffset(), hub, HUB_LOCATION);
+    }
+
     @Fold
     public static int unlockedMask() {
         return config().unlockedMask;
@@ -188,11 +245,6 @@
     }
 
     @Fold
-    public static int hubOffset() {
-        return config().hubOffset;
-    }
-
-    @Fold
     public static int metaspaceArrayLengthOffset() {
         return config().metaspaceArrayLengthOffset;
     }
@@ -232,16 +284,22 @@
         return config().superCheckOffsetOffset;
     }
 
+    public static final Object SECONDARY_SUPER_CACHE_LOCATION = LocationNode.createLocation("SecondarySuperCache");
+
     @Fold
     public static int secondarySuperCacheOffset() {
         return config().secondarySuperCacheOffset;
     }
 
+    public static final Object SECONDARY_SUPERS_LOCATION = LocationNode.createLocation("SecondarySupers");
+
     @Fold
     public static int secondarySupersOffset() {
         return config().secondarySupersOffset;
     }
 
+    public static final Object DISPLACED_MARK_WORD_LOCATION = LocationNode.createLocation("DisplacedMarkWord");
+
     @Fold
     public static int lockDisplacedMarkOffset() {
         return config().basicLockDisplacedHeaderOffset;
@@ -308,12 +366,19 @@
         return CodeUtil.log2(wordSize());
     }
 
+    public static final Object CLASS_STATE_LOCATION = LocationNode.createLocation("ClassState");
+
     @Fold
     public static int klassStateOffset() {
         return config().klassStateOffset;
     }
 
     @Fold
+    public static int klassStateFullyInitialized() {
+        return config().klassStateFullyInitialized;
+    }
+
+    @Fold
     public static int klassModifierFlagsOffset() {
         return config().klassModifierFlagsOffset;
     }
@@ -333,22 +398,21 @@
         return config().klassInstanceSizeOffset;
     }
 
+    public static final Object HEAP_TOP_LOCATION = LocationNode.createLocation("HeapTop");
+
     @Fold
     public static long heapTopAddress() {
         return config().heapTopAddress;
     }
 
+    public static final Object HEAP_END_LOCATION = LocationNode.createLocation("HeapEnd");
+
     @Fold
     public static long heapEndAddress() {
         return config().heapEndAddress;
     }
 
     @Fold
-    public static int threadTlabStartOffset() {
-        return config().threadTlabStartOffset;
-    }
-
-    @Fold
     public static long tlabIntArrayMarkWord() {
         return config().tlabIntArrayMarkWord;
     }
@@ -363,36 +427,43 @@
         return config().tlabAlignmentReserve;
     }
 
+    public static final Object TLAB_SIZE_LOCATION = LocationNode.createLocation("TlabSize");
+
     @Fold
     public static int threadTlabSizeOffset() {
         return config().threadTlabSizeOffset;
     }
 
+    public static final Object TLAB_THREAD_ALLOCATED_BYTES_LOCATION = LocationNode.createLocation("TlabThreadAllocatedBytes");
+
     @Fold
     public static int threadAllocatedBytesOffset() {
         return config().threadAllocatedBytesOffset;
     }
 
-    @Fold
-    public static int klassStateFullyInitialized() {
-        return config().klassStateFullyInitialized;
-    }
+    public static final Object TLAB_REFILL_WASTE_LIMIT_LOCATION = LocationNode.createLocation("RefillWasteLimit");
 
     @Fold
     public static int tlabRefillWasteLimitOffset() {
         return config().tlabRefillWasteLimitOffset;
     }
 
+    public static final Object TLAB_NOF_REFILLS_LOCATION = LocationNode.createLocation("TlabNOfRefills");
+
     @Fold
     public static int tlabNumberOfRefillsOffset() {
         return config().tlabNumberOfRefillsOffset;
     }
 
+    public static final Object TLAB_FAST_REFILL_WASTE_LOCATION = LocationNode.createLocation("TlabFastRefillWaste");
+
     @Fold
     public static int tlabFastRefillWasteOffset() {
         return config().tlabFastRefillWasteOffset;
     }
 
+    public static final Object TLAB_SLOW_ALLOCATIONS_LOCATION = LocationNode.createLocation("TlabSlowAllocations");
+
     @Fold
     public static int tlabSlowAllocationsOffset() {
         return config().tlabSlowAllocationsOffset;
@@ -445,7 +516,6 @@
 
     @Fold
     public static int layoutHelperElementTypePrimitiveInPlace() {
-        System.out.println(String.format("%x", config().layoutHelperElementTypePrimitiveInPlace));
         return config().layoutHelperElementTypePrimitiveInPlace;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/InstanceOfSnippets.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/InstanceOfSnippets.java	Fri Mar 01 17:06:08 2013 +0100
@@ -99,7 +99,7 @@
             return falseValue;
         }
         Word objectHub = loadHub(object);
-        if (objectHub.readWord(superCheckOffset).notEqual(hub)) {
+        if (objectHub.readWord(superCheckOffset, FINAL_LOCATION).notEqual(hub)) {
             probability(NOT_LIKELY_PROBABILITY);
             displayMiss.inc();
             return falseValue;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/MonitorSnippets.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/MonitorSnippets.java	Fri Mar 01 17:06:08 2013 +0100
@@ -40,6 +40,7 @@
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.spi.*;
@@ -109,7 +110,7 @@
                 // The bias pattern is present in the object's mark word. Need to check
                 // whether the bias owner and the epoch are both still current.
                 Word hub = loadHub(object);
-                final Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset());
+                final Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION);
                 final Word thread = thread();
                 final Word tmp = prototypeMarkWord.or(thread).xor(mark).and(~ageMaskInPlace());
                 trace(trace, "prototypeMarkWord: 0x%016lx\n", prototypeMarkWord);
@@ -154,7 +155,7 @@
                         Word biasedMark = unbiasedMark.or(thread);
                         trace(trace, "     unbiasedMark: 0x%016lx\n", unbiasedMark);
                         trace(trace, "       biasedMark: 0x%016lx\n", biasedMark);
-                        if (compareAndSwap(object, markOffset(), unbiasedMark, biasedMark).equal(unbiasedMark)) {
+                        if (compareAndSwap(object, markOffset(), unbiasedMark, biasedMark, MARK_WORD_LOCATION).equal(unbiasedMark)) {
                             // Object is now biased to current thread -> done
                             traceObject(trace, "+lock{bias:acquired}", object);
                             return;
@@ -175,7 +176,7 @@
                         // the bias from one thread to another directly in this situation.
                         Word biasedMark = prototypeMarkWord.or(thread);
                         trace(trace, "       biasedMark: 0x%016lx\n", biasedMark);
-                        if (compareAndSwap(object, markOffset(), mark, biasedMark).equal(mark)) {
+                        if (compareAndSwap(object, markOffset(), mark, biasedMark, MARK_WORD_LOCATION).equal(mark)) {
                             // Object is now biased to current thread -> done
                             traceObject(trace, "+lock{bias:transfer}", object);
                             return;
@@ -197,7 +198,7 @@
                     // that another thread raced us for the privilege of revoking the
                     // bias of this particular object, so it's okay to continue in the
                     // normal locking code.
-                    Word result = compareAndSwap(object, markOffset(), mark, prototypeMarkWord);
+                    Word result = compareAndSwap(object, markOffset(), mark, prototypeMarkWord, MARK_WORD_LOCATION);
 
                     // Fall through to the normal CAS-based lock, because no matter what
                     // the result of the above CAS, some thread must have succeeded in
@@ -215,11 +216,11 @@
         trace(trace, "     unlockedMark: 0x%016lx\n", unlockedMark);
 
         // Copy this unlocked mark word into the lock slot on the stack
-        lock.writeWord(lockDisplacedMarkOffset(), unlockedMark);
+        lock.writeWord(lockDisplacedMarkOffset(), unlockedMark, DISPLACED_MARK_WORD_LOCATION);
 
         // Test if the object's mark word is unlocked, and if so, store the
         // (address of) the lock slot into the object's mark word.
-        Word currentMark = compareAndSwap(object, markOffset(), unlockedMark, lock);
+        Word currentMark = compareAndSwap(object, markOffset(), unlockedMark, lock, MARK_WORD_LOCATION);
         if (currentMark.notEqual(unlockedMark)) {
             trace(trace, "      currentMark: 0x%016lx\n", currentMark);
             // The mark word in the object header was not the same.
@@ -247,7 +248,7 @@
                 return;
             } else {
                 // Recursively locked => write 0 to the lock slot
-                lock.writeWord(lockDisplacedMarkOffset(), Word.zero());
+                lock.writeWord(lockDisplacedMarkOffset(), Word.zero(), DISPLACED_MARK_WORD_LOCATION);
                 traceObject(trace, "+lock{recursive}", object);
             }
         } else {
@@ -302,7 +303,7 @@
         final Word lock = CurrentLockNode.currentLock();
 
         // Load displaced mark
-        final Word displacedMark = lock.readWord(lockDisplacedMarkOffset());
+        final Word displacedMark = lock.readWord(lockDisplacedMarkOffset(), DISPLACED_MARK_WORD_LOCATION);
         trace(trace, "    displacedMark: 0x%016lx\n", displacedMark);
 
         if (displacedMark.equal(0)) {
@@ -313,7 +314,7 @@
             // Test if object's mark word is pointing to the displaced mark word, and if so, restore
             // the displaced mark in the object - if the object's mark word is not pointing to
             // the displaced mark word, do unlocking via runtime call.
-            if (DirectCompareAndSwapNode.compareAndSwap(object, markOffset(), lock, displacedMark).notEqual(lock)) {
+            if (DirectCompareAndSwapNode.compareAndSwap(object, markOffset(), lock, displacedMark, MARK_WORD_LOCATION).notEqual(lock)) {
                 // The object's mark word was not pointing to the displaced header,
                 // we do unlocking via runtime call.
                 probability(DEOPT_PATH_PROBABILITY);
@@ -365,35 +366,37 @@
      */
     private static final boolean ENABLE_BREAKPOINT = false;
 
+    private static final Object MONITOR_COUNTER_LOCATION = LocationNode.createLocation("MonitorCounter");
+
     @NodeIntrinsic(BreakpointNode.class)
     static native void bkpt(Object object, Word mark, Word tmp, Word value);
 
     private static void incCounter() {
         if (CHECK_BALANCED_MONITORS) {
             final Word counter = MonitorCounterNode.counter();
-            final int count = counter.readInt(0);
-            counter.writeInt(0, count + 1);
+            final int count = counter.readInt(0, MONITOR_COUNTER_LOCATION);
+            counter.writeInt(0, count + 1, MONITOR_COUNTER_LOCATION);
         }
     }
 
     private static void decCounter() {
         if (CHECK_BALANCED_MONITORS) {
             final Word counter = MonitorCounterNode.counter();
-            final int count = counter.readInt(0);
-            counter.writeInt(0, count - 1);
+            final int count = counter.readInt(0, MONITOR_COUNTER_LOCATION);
+            counter.writeInt(0, count - 1, MONITOR_COUNTER_LOCATION);
         }
     }
 
     @Snippet
     private static void initCounter() {
         final Word counter = MonitorCounterNode.counter();
-        counter.writeInt(0, 0);
+        counter.writeInt(0, 0, MONITOR_COUNTER_LOCATION);
     }
 
     @Snippet
     private static void checkCounter(String errMsg) {
         final Word counter = MonitorCounterNode.counter();
-        final int count = counter.readInt(0);
+        final int count = counter.readInt(0, MONITOR_COUNTER_LOCATION);
         if (count != 0) {
             vmError(errMsg, count);
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/NewObjectSnippets.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/NewObjectSnippets.java	Fri Mar 01 17:06:08 2013 +0100
@@ -29,8 +29,8 @@
 import static com.oracle.graal.snippets.Snippet.Varargs.*;
 import static com.oracle.graal.snippets.SnippetTemplate.*;
 import static com.oracle.graal.snippets.SnippetTemplate.Arguments.*;
+import static com.oracle.graal.snippets.nodes.BranchProbabilityNode.*;
 import static com.oracle.graal.snippets.nodes.ExplodeLoopNode.*;
-import static com.oracle.graal.snippets.nodes.BranchProbabilityNode.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
@@ -62,13 +62,13 @@
     @Snippet
     public static Word allocate(@Parameter("size") int size) {
         Word thread = thread();
-        Word top = thread.readWord(threadTlabTopOffset());
-        Word end = thread.readWord(threadTlabEndOffset());
+        Word top = readTlabTop(thread);
+        Word end = readTlabEnd(thread);
         Word newTop = top.add(size);
         // this check might lead to problems if the TLAB is within 16GB of the address space end (checked in c++ code)
         if (newTop.belowOrEqual(end)) {
             probability(FAST_PATH_PROBABILITY);
-            thread.writeWord(threadTlabTopOffset(), newTop);
+            writeTlabTop(thread, newTop);
             return top;
         }
         return Word.zero();
@@ -178,7 +178,7 @@
         Word dims = DimensionsNode.allocaDimsArray(rank);
         ExplodeLoopNode.explodeLoop();
         for (int i = 0; i < rank; i++) {
-            dims.writeInt(i * 4, dimensions[i]);
+            dims.writeInt(i * 4, dimensions[i], ANY_LOCATION);
         }
         return NewMultiArrayStubCall.call(hub, rank, dims);
     }
@@ -194,20 +194,19 @@
      * Formats some allocated memory with an object header zeroes out the rest.
      */
     private static void formatObject(Word hub, int size, Word memory, Word compileTimePrototypeMarkWord, boolean fillContents) {
-        Word prototypeMarkWord = useBiasedLocking() ? hub.readWord(prototypeMarkWordOffset()) : compileTimePrototypeMarkWord;
-        memory.writeWord(markOffset(), prototypeMarkWord);
-        memory.writeWord(hubOffset(), hub);
+        Word prototypeMarkWord = useBiasedLocking() ? hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION) : compileTimePrototypeMarkWord;
+        initializeObjectHeader(memory, prototypeMarkWord, hub);
         if (fillContents) {
             if (size <= MAX_UNROLLED_OBJECT_ZEROING_SIZE) {
                 new_seqInit.inc();
                 explodeLoop();
                 for (int offset = 2 * wordSize(); offset < size; offset += wordSize()) {
-                    memory.writeWord(offset, Word.zero());
+                    memory.writeWord(offset, Word.zero(), ANY_LOCATION);
                 }
             } else {
                 new_loopInit.inc();
                 for (int offset = 2 * wordSize(); offset < size; offset += wordSize()) {
-                    memory.writeWord(offset, Word.zero());
+                    memory.writeWord(offset, Word.zero(), ANY_LOCATION);
                 }
             }
         }
@@ -217,13 +216,12 @@
      * Formats some allocated memory with an object header zeroes out the rest.
      */
     public static void formatArray(Word hub, int allocationSize, int length, int headerSize, Word memory, Word prototypeMarkWord, boolean fillContents) {
-        memory.writeWord(markOffset(), prototypeMarkWord);
-        memory.writeInt(arrayLengthOffset(), length);
+        memory.writeInt(arrayLengthOffset(), length, ANY_LOCATION);
         // store hub last as the concurrent garbage collectors assume length is valid if hub field is not null
-        memory.writeWord(hubOffset(), hub);
+        initializeObjectHeader(memory, prototypeMarkWord, hub);
         if (fillContents) {
             for (int offset = headerSize; offset < allocationSize; offset += wordSize()) {
-                memory.writeWord(offset, Word.zero());
+                memory.writeWord(offset, Word.zero(), ANY_LOCATION);
             }
         }
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectCloneNode.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectCloneNode.java	Fri Mar 01 17:06:08 2013 +0100
@@ -26,7 +26,6 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
@@ -34,7 +33,6 @@
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.common.*;
 import com.oracle.graal.snippets.nodes.*;
 
 public class ObjectCloneNode extends MacroNode implements VirtualizableAllocation, ArrayLengthProvider {
@@ -52,33 +50,30 @@
         return arguments.get(0);
     }
 
-    private Method selectSnippetMethod(LoweringTool tool) {
-        ResolvedJavaType type = getObject().objectStamp().type();
-        if (type.isArray()) {
-            return ObjectCloneSnippets.arrayCloneMethod;
-        } else if (type.isAssignableFrom(tool.getRuntime().lookupJavaType(Object[].class))) {
-            // arrays are assignable to Object, Cloneable and Serializable
-            return ObjectCloneSnippets.genericCloneMethod;
-        } else {
-            return ObjectCloneSnippets.instanceCloneMethod;
-        }
-    }
-
     @Override
-    public void lower(LoweringTool tool) {
+    protected StructuredGraph getSnippetGraph(LoweringTool tool) {
         if (!GraalOptions.IntrinsifyObjectClone) {
-            super.lower(tool);
-            return;
-        }
-        ResolvedJavaMethod snippetMethod = tool.getRuntime().lookupJavaMethod(selectSnippetMethod(tool));
-        if (Debug.isLogEnabled()) {
-            Debug.log("%s > Intrinsify (%s)", Debug.currentScope(), snippetMethod.getSignature().getParameterType(0, snippetMethod.getDeclaringClass()).getComponentType());
+            return null;
         }
 
+        ResolvedJavaType type = getObject().objectStamp().type();
+        Method method;
+        /*
+         * The first condition tests if the parameter is an array, the second condition tests if the
+         * parameter can be an array. Otherwise, the parameter is known to be a non-array object.
+         */
+        if (type.isArray()) {
+            method = ObjectCloneSnippets.arrayCloneMethod;
+        } else if (type == null || type.isAssignableFrom(tool.getRuntime().lookupJavaType(Object[].class))) {
+            method = ObjectCloneSnippets.genericCloneMethod;
+        } else {
+            method = ObjectCloneSnippets.instanceCloneMethod;
+        }
+        ResolvedJavaMethod snippetMethod = tool.getRuntime().lookupJavaMethod(method);
         StructuredGraph snippetGraph = (StructuredGraph) snippetMethod.getCompilerStorage().get(Graph.class);
+
         assert snippetGraph != null : "ObjectCloneSnippets should be installed";
-        InvokeNode invoke = replaceWithInvoke();
-        InliningUtil.inline(invoke, snippetGraph, false);
+        return snippetGraph;
     }
 
     private static boolean isCloneableType(ResolvedJavaType type, MetaAccessProvider metaAccess) {
@@ -86,7 +81,7 @@
     }
 
     private static ResolvedJavaType getConcreteType(ObjectStamp stamp, Assumptions assumptions) {
-        if (stamp.isExactType()) {
+        if (stamp.isExactType() || stamp.type() == null) {
             return stamp.type();
         } else {
             ResolvedJavaType type = stamp.type().findUniqueConcreteSubtype();
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectCloneSnippets.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectCloneSnippets.java	Fri Mar 01 17:06:08 2013 +0100
@@ -53,12 +53,12 @@
     private static Object instanceClone(Object src, Word hub, int layoutHelper) {
         int instanceSize = layoutHelper;
         Pointer memory = NewObjectSnippets.allocate(instanceSize);
-        Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset());
+        Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION);
         Object result = NewObjectSnippets.initializeObject((Word) memory, hub, prototypeMarkWord, instanceSize, false, false);
 
         memory = Word.fromObject(result);
         for (int offset = 2 * wordSize(); offset < instanceSize; offset += wordSize()) {
-            memory.writeWord(offset, Word.fromObject(src).readWord(offset));
+            memory.writeWord(offset, Word.fromObject(src).readWord(offset, UNKNOWN_LOCATION), ANY_LOCATION);
         }
 
         return result;
@@ -71,12 +71,12 @@
         int sizeInBytes = NewObjectSnippets.computeArrayAllocationSize(arrayLength, wordSize(), headerSize, log2ElementSize);
 
         Pointer memory = NewObjectSnippets.allocate(sizeInBytes);
-        Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset());
+        Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION);
         Object result = NewObjectSnippets.initializeArray((Word) memory, hub, arrayLength, sizeInBytes, prototypeMarkWord, headerSize, false, false);
 
         memory = Word.fromObject(result);
         for (int offset = headerSize; offset < sizeInBytes; offset += wordSize()) {
-            memory.writeWord(offset, Word.fromObject(src).readWord(offset));
+            memory.writeWord(offset, Word.fromObject(src).readWord(offset, UNKNOWN_LOCATION), ANY_LOCATION);
         }
         return result;
     }
@@ -94,14 +94,14 @@
     public static Object instanceClone(Object src) {
         instanceCloneCounter.inc();
         Word hub = getAndCheckHub(src);
-        return instanceClone(src, hub, hub.readInt(layoutHelperOffset()));
+        return instanceClone(src, hub, hub.readInt(layoutHelperOffset(), FINAL_LOCATION));
     }
 
     @Snippet
     public static Object arrayClone(Object src) {
         arrayCloneCounter.inc();
         Word hub = getAndCheckHub(src);
-        int layoutHelper = hub.readInt(layoutHelperOffset());
+        int layoutHelper = hub.readInt(layoutHelperOffset(), FINAL_LOCATION);
         return arrayClone(src, hub, layoutHelper);
     }
 
@@ -109,7 +109,7 @@
     public static Object genericClone(Object src) {
         genericCloneCounter.inc();
         Word hub = getAndCheckHub(src);
-        int layoutHelper = hub.readInt(layoutHelperOffset());
+        int layoutHelper = hub.readInt(layoutHelperOffset(), FINAL_LOCATION);
         if (layoutHelper < 0) {
             probability(LIKELY_PROBABILITY);
             genericArrayCloneCounter.inc();
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectSubstitutions.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectSubstitutions.java	Fri Mar 01 17:06:08 2013 +0100
@@ -25,8 +25,10 @@
 import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*;
 import static com.oracle.graal.nodes.extended.UnsafeCastNode.*;
 
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.snippets.*;
-import com.oracle.graal.snippets.ClassSubstitution.*;
+import com.oracle.graal.snippets.ClassSubstitution.MacroSubstitution;
+import com.oracle.graal.snippets.ClassSubstitution.MethodSubstitution;
 import com.oracle.graal.word.*;
 
 /**
@@ -38,7 +40,7 @@
     @MethodSubstitution(isStatic = false)
     public static Class<?> getClass(final Object thisObj) {
         Word hub = loadHub(thisObj);
-        return unsafeCast(hub.readFinalObject(Word.signed(classMirrorOffset())), Class.class, true, true);
+        return unsafeCast(hub.readObject(Word.signed(classMirrorOffset()), LocationNode.FINAL_LOCATION), Class.class, true, true);
     }
 
     @MethodSubstitution(isStatic = false)
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ThreadSubstitutions.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ThreadSubstitutions.java	Fri Mar 01 17:06:08 2013 +0100
@@ -43,10 +43,10 @@
     @MethodSubstitution(isStatic = false)
     private static boolean isInterrupted(final Thread thisObject, boolean clearInterrupted) {
         Word rawThread = HotSpotCurrentRawThreadNode.get();
-        Thread thread = (Thread) rawThread.readObject(threadObjectOffset());
+        Thread thread = (Thread) rawThread.readObject(threadObjectOffset(), FINAL_LOCATION);
         if (thisObject == thread) {
-            Word osThread = rawThread.readWord(osThreadOffset());
-            boolean interrupted = osThread.readInt(osThreadInterruptedOffset()) != 0;
+            Word osThread = rawThread.readWord(osThreadOffset(), FINAL_LOCATION);
+            boolean interrupted = osThread.readInt(osThreadInterruptedOffset(), UNKNOWN_LOCATION) != 0;
             if (!interrupted || !clearInterrupted) {
                 return interrupted;
             }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/TypeCheckSnippetUtils.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/TypeCheckSnippetUtils.java	Fri Mar 01 17:06:08 2013 +0100
@@ -30,6 +30,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.snippets.*;
 import com.oracle.graal.word.*;
@@ -39,9 +40,11 @@
  */
 public class TypeCheckSnippetUtils {
 
+    public static final Object TYPE_DISPLAY_LOCATION = LocationNode.createLocation("TypeDisplay");
+
     static boolean checkSecondarySubType(Word t, Word s) {
         // if (S.cache == T) return true
-        if (s.readWord(secondarySuperCacheOffset()).equal(t)) {
+        if (s.readWord(secondarySuperCacheOffset(), SECONDARY_SUPER_CACHE_LOCATION).equal(t)) {
             cacheHit.inc();
             return true;
         }
@@ -51,11 +54,11 @@
 
     static boolean checkUnknownSubType(Word t, Word s) {
         // int off = T.offset
-        int superCheckOffset = t.readInt(superCheckOffsetOffset());
+        int superCheckOffset = t.readInt(superCheckOffsetOffset(), FINAL_LOCATION);
         boolean primary = superCheckOffset != secondarySuperCacheOffset();
 
         // if (T = S[off]) return true
-        if (s.readWord(superCheckOffset).equal(t)) {
+        if (s.readWord(superCheckOffset, TYPE_DISPLAY_LOCATION).equal(t)) {
             if (primary) {
                 cacheHit.inc();
             } else {
@@ -81,12 +84,12 @@
         }
 
         // if (S.scan_s_s_array(T)) { S.cache = T; return true; }
-        Word secondarySupers = s.readWord(secondarySupersOffset());
-        int length = secondarySupers.readInt(metaspaceArrayLengthOffset());
+        Word secondarySupers = s.readWord(secondarySupersOffset(), SECONDARY_SUPERS_LOCATION);
+        int length = secondarySupers.readInt(metaspaceArrayLengthOffset(), FINAL_LOCATION);
         for (int i = 0; i < length; i++) {
-            if (t.equal(loadWordElement(secondarySupers, i))) {
+            if (t.equal(loadSecondarySupersElement(secondarySupers, i))) {
                 probability(NOT_LIKELY_PROBABILITY);
-                s.writeWord(secondarySuperCacheOffset(), t);
+                s.writeWord(secondarySuperCacheOffset(), t, SECONDARY_SUPER_CACHE_LOCATION);
                 secondariesHit.inc();
                 return true;
             }
@@ -103,8 +106,8 @@
         return hintHubs;
     }
 
-    static Word loadWordElement(Word metaspaceArray, int index) {
-        return metaspaceArray.readWord(metaspaceArrayBaseOffset() + index * wordSize());
+    static Word loadSecondarySupersElement(Word metaspaceArray, int index) {
+        return metaspaceArray.readWord(metaspaceArrayBaseOffset() + index * wordSize(), FINAL_LOCATION);
     }
 
     private static final SnippetCounter.Group counters = GraalOptions.SnippetCounters ? new SnippetCounter.Group("TypeCheck") : null;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java	Fri Mar 01 17:06:08 2013 +0100
@@ -67,7 +67,7 @@
      */
     @Snippet
     private static Object newArray(@Parameter("hub") Word hub, @Parameter("length") int length, @ConstantParameter("intArrayHub") Word intArrayHub, @ConstantParameter("log") boolean log) {
-        int layoutHelper = hub.readInt(layoutHelperOffset());
+        int layoutHelper = hub.readInt(layoutHelperOffset(), FINAL_LOCATION);
         int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask();
         int headerSize = (layoutHelper >> layoutHelperHeaderSizeShift()) & layoutHelperHeaderSizeMask();
         int elementKind = (layoutHelper >> layoutHelperElementTypeShift()) & layoutHelperElementTypeMask();
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java	Fri Mar 01 17:06:08 2013 +0100
@@ -67,16 +67,15 @@
      */
     @Snippet
     private static Object newInstance(@Parameter("hub") Word hub, @ConstantParameter("intArrayHub") Word intArrayHub, @ConstantParameter("log") boolean log) {
-        int sizeInBytes = hub.readInt(klassInstanceSizeOffset());
+        int sizeInBytes = hub.readInt(klassInstanceSizeOffset(), FINAL_LOCATION);
         if (!forceSlowPath() && inlineContiguousAllocationSupported()) {
-            if (hub.readInt(klassStateOffset()) == klassStateFullyInitialized()) {
+            if (hub.readInt(klassStateOffset(), CLASS_STATE_LOCATION) == klassStateFullyInitialized()) {
                 Word memory = refillAllocate(intArrayHub, sizeInBytes, log);
                 if (memory.notEqual(0)) {
-                    Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset());
-                    memory.writeWord(markOffset(), prototypeMarkWord);
-                    memory.writeWord(hubOffset(), hub);
+                    Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION);
+                    initializeObjectHeader(memory, prototypeMarkWord, hub);
                     for (int offset = 2 * wordSize(); offset < sizeInBytes; offset += wordSize()) {
-                        memory.writeWord(offset, Word.zero());
+                        memory.writeWord(offset, Word.zero(), ANY_LOCATION);
                     }
                     return verifyOop(memory.toObject());
                 }
@@ -100,8 +99,8 @@
         int alignmentReserveInBytes = tlabAlignmentReserveInHeapWords() * wordSize();
 
         Word thread = thread();
-        Word top = thread.readWord(threadTlabTopOffset());
-        Word end = thread.readWord(threadTlabEndOffset());
+        Word top = readTlabTop(thread);
+        Word end = readTlabEnd(thread);
 
         // calculate amount of free space
         Word tlabFreeSpaceInBytes = end.subtract(top);
@@ -115,16 +114,16 @@
 
         // Retain TLAB and allocate object in shared space if
         // the amount free in the TLAB is too large to discard.
-        Word refillWasteLimit = thread.readWord(tlabRefillWasteLimitOffset());
+        Word refillWasteLimit = thread.readWord(tlabRefillWasteLimitOffset(), TLAB_REFILL_WASTE_LIMIT_LOCATION);
         if (tlabFreeSpaceInWords.belowOrEqual(refillWasteLimit)) {
             if (tlabStats()) {
                 // increment number of refills
-                thread.writeInt(tlabNumberOfRefillsOffset(), thread.readInt(tlabNumberOfRefillsOffset()) + 1);
-                log(log, "thread: %p -- number_of_refills %d\n", thread, thread.readInt(tlabNumberOfRefillsOffset()));
+                thread.writeInt(tlabNumberOfRefillsOffset(), thread.readInt(tlabNumberOfRefillsOffset(), TLAB_NOF_REFILLS_LOCATION) + 1, TLAB_NOF_REFILLS_LOCATION);
+                log(log, "thread: %p -- number_of_refills %d\n", thread, thread.readInt(tlabNumberOfRefillsOffset(), TLAB_NOF_REFILLS_LOCATION));
                 // accumulate wastage
-                Word wastage = thread.readWord(tlabFastRefillWasteOffset()).add(tlabFreeSpaceInWords);
+                Word wastage = thread.readWord(tlabFastRefillWasteOffset(), TLAB_FAST_REFILL_WASTE_LOCATION).add(tlabFreeSpaceInWords);
                 log(log, "thread: %p -- accumulated wastage %d\n", thread, wastage);
-                thread.writeWord(tlabFastRefillWasteOffset(), wastage);
+                thread.writeWord(tlabFastRefillWasteOffset(), wastage, TLAB_FAST_REFILL_WASTE_LOCATION);
             }
 
             // if TLAB is currently allocated (top or end != null) then
@@ -137,22 +136,19 @@
                 int length = ((alignmentReserveInBytes - headerSize) >>> 2) + tlabFreeSpaceInInts;
                 NewObjectSnippets.formatArray(intArrayHub, -1, length, headerSize, top, intArrayMarkWord, false);
 
-                Word allocated = thread.readWord(threadAllocatedBytesOffset());
-                allocated = allocated.add(top.subtract(thread.readWord(threadTlabStartOffset())));
-                thread.writeWord(threadAllocatedBytesOffset(), allocated);
+                Word allocated = thread.readWord(threadAllocatedBytesOffset(), TLAB_THREAD_ALLOCATED_BYTES_LOCATION);
+                allocated = allocated.add(top.subtract(readTlabStart(thread)));
+                thread.writeWord(threadAllocatedBytesOffset(), allocated, TLAB_THREAD_ALLOCATED_BYTES_LOCATION);
             }
 
             // refill the TLAB with an eden allocation
-            Word tlabRefillSizeInWords = thread.readWord(threadTlabSizeOffset());
+            Word tlabRefillSizeInWords = thread.readWord(threadTlabSizeOffset(), TLAB_SIZE_LOCATION);
             Word tlabRefillSizeInBytes = tlabRefillSizeInWords.multiply(wordSize());
             // allocate new TLAB, address returned in top
             top = edenAllocate(tlabRefillSizeInBytes, log);
             if (top.notEqual(0)) {
-                thread.writeWord(threadTlabStartOffset(), top);
-                thread.writeWord(threadTlabTopOffset(), top);
-
                 end = top.add(tlabRefillSizeInBytes.subtract(alignmentReserveInBytes));
-                thread.writeWord(threadTlabEndOffset(), end);
+                initializeTlab(thread, top, end);
 
                 return allocate(sizeInBytes);
             } else {
@@ -161,11 +157,11 @@
         } else {
             // Retain TLAB
             Word newRefillWasteLimit = refillWasteLimit.add(tlabRefillWasteIncrement());
-            thread.writeWord(tlabRefillWasteLimitOffset(), newRefillWasteLimit);
+            thread.writeWord(tlabRefillWasteLimitOffset(), newRefillWasteLimit, TLAB_REFILL_WASTE_LIMIT_LOCATION);
             log(log, "refillTLAB: retaining TLAB - newRefillWasteLimit=%p\n", newRefillWasteLimit);
 
             if (tlabStats()) {
-                thread.writeInt(tlabSlowAllocationsOffset(), thread.readInt(tlabSlowAllocationsOffset()) + 1);
+                thread.writeInt(tlabSlowAllocationsOffset(), thread.readInt(tlabSlowAllocationsOffset(), TLAB_SLOW_ALLOCATIONS_LOCATION) + 1, TLAB_SLOW_ALLOCATIONS_LOCATION);
             }
 
             return edenAllocate(Word.unsigned(sizeInBytes), log);
@@ -184,18 +180,18 @@
         Word heapEndAddress = Word.unsigned(heapEndAddress());
 
         while (true) {
-            Word heapTop = heapTopAddress.readWord(0);
+            Word heapTop = heapTopAddress.readWord(0, HEAP_TOP_LOCATION);
             Word newHeapTop = heapTop.add(sizeInBytes);
             if (newHeapTop.belowOrEqual(heapTop)) {
                 return Word.zero();
             }
 
-            Word heapEnd = heapEndAddress.readWord(0);
+            Word heapEnd = heapEndAddress.readWord(0, HEAP_END_LOCATION);
             if (newHeapTop.aboveThan(heapEnd)) {
                 return Word.zero();
             }
 
-            if (compareAndSwap(heapTopAddress, 0, heapTop, newHeapTop).equal(heapTop)) {
+            if (compareAndSwap(heapTopAddress, 0, heapTop, newHeapTop, HEAP_TOP_LOCATION).equal(heapTop)) {
                 return heapTop;
             }
         }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java	Fri Mar 01 17:06:08 2013 +0100
@@ -203,16 +203,16 @@
     }
 
     private void propagateDelete(FloatingNode node) {
-        assert node instanceof PhiNode || node instanceof ValueProxyNode;
+        assert node instanceof PhiNode || node instanceof ProxyNode;
         if (node.isDeleted()) {
             return;
         }
         // Collect all phi functions that use this phi so that we can delete them recursively (after
         // we delete ourselves to avoid circles).
-        List<FloatingNode> propagateUsages = node.usages().filter(FloatingNode.class).filter(isA(PhiNode.class).or(ValueProxyNode.class)).snapshot();
+        List<FloatingNode> propagateUsages = node.usages().filter(FloatingNode.class).filter(isA(PhiNode.class).or(ProxyNode.class)).snapshot();
 
         // Remove the phi function from all FrameStates where it is used and then delete it.
-        assert node.usages().filter(isNotA(FrameState.class).nor(PhiNode.class).nor(ValueProxyNode.class)).isEmpty() : "phi function that gets deletes must only be used in frame states";
+        assert node.usages().filter(isNotA(FrameState.class).nor(PhiNode.class).nor(ProxyNode.class)).isEmpty() : "phi function that gets deletes must only be used in frame states";
         node.replaceAtUsages(null);
         node.safeDelete();
 
@@ -235,21 +235,21 @@
             ValueNode value = localAt(i);
             if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) {
                 Debug.log(" inserting proxy for %s", value);
-                storeLocal(i, graph.unique(new ValueProxyNode(value, loopExit, PhiType.Value)));
+                storeLocal(i, graph.unique(new ProxyNode(value, loopExit, PhiType.Value)));
             }
         }
         for (int i = 0; i < stackSize(); i++) {
             ValueNode value = stackAt(i);
             if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) {
                 Debug.log(" inserting proxy for %s", value);
-                storeStack(i, graph.unique(new ValueProxyNode(value, loopExit, PhiType.Value)));
+                storeStack(i, graph.unique(new ProxyNode(value, loopExit, PhiType.Value)));
             }
         }
         for (int i = 0; i < locks.length; i++) {
             ValueNode value = locks[i];
             if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) {
                 Debug.log(" inserting proxy for %s", value);
-                locks[i] = graph.unique(new ValueProxyNode(value, loopExit, PhiType.Value));
+                locks[i] = graph.unique(new ProxyNode(value, loopExit, PhiType.Value));
             }
         }
     }
@@ -259,21 +259,21 @@
             ValueNode value = localAt(i);
             if (value != null) {
                 Debug.log(" inserting proxy for %s", value);
-                storeLocal(i, graph.unique(new ValueProxyNode(value, begin, PhiType.Value)));
+                storeLocal(i, graph.unique(new ProxyNode(value, begin, PhiType.Value)));
             }
         }
         for (int i = 0; i < stackSize(); i++) {
             ValueNode value = stackAt(i);
             if (value != null) {
                 Debug.log(" inserting proxy for %s", value);
-                storeStack(i, graph.unique(new ValueProxyNode(value, begin, PhiType.Value)));
+                storeStack(i, graph.unique(new ProxyNode(value, begin, PhiType.Value)));
             }
         }
         for (int i = 0; i < locks.length; i++) {
             ValueNode value = locks[i];
             if (value != null) {
                 Debug.log(" inserting proxy for %s", value);
-                locks[i] = graph.unique(new ValueProxyNode(value, begin, PhiType.Value));
+                locks[i] = graph.unique(new ProxyNode(value, begin, PhiType.Value));
             }
         }
     }
@@ -292,7 +292,7 @@
     public void cleanupDeletedPhis() {
         for (int i = 0; i < localsSize(); i++) {
             if (localAt(i) != null && localAt(i).isDeleted()) {
-                assert localAt(i) instanceof PhiNode || localAt(i) instanceof ValueProxyNode : "Only phi and value proxies can be deleted during parsing: " + localAt(i);
+                assert localAt(i) instanceof PhiNode || localAt(i) instanceof ProxyNode : "Only phi and value proxies can be deleted during parsing: " + localAt(i);
                 storeLocal(i, null);
             }
         }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderConfiguration.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderConfiguration.java	Fri Mar 01 17:06:08 2013 +0100
@@ -23,21 +23,16 @@
 package com.oracle.graal.java;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.phases.*;
 
 public class GraphBuilderConfiguration {
 
-    public static enum ResolvePolicy {
-        Default, EagerForSnippets, Eager,
-    }
-
-    private final ResolvePolicy resolving;
-    private final PhasePlan plan;
+    private final boolean eagerResolving;
+    private final boolean omitAllExceptionEdges;
     private ResolvedJavaType[] skippedExceptionTypes;
 
-    public GraphBuilderConfiguration(ResolvePolicy resolving, PhasePlan plan) {
-        this.resolving = resolving;
-        this.plan = plan;
+    protected GraphBuilderConfiguration(boolean eagerResolving, boolean omitAllExceptionEdges) {
+        this.eagerResolving = eagerResolving;
+        this.omitAllExceptionEdges = omitAllExceptionEdges;
     }
 
     public void setSkippedExceptionTypes(ResolvedJavaType[] skippedExceptionTypes) {
@@ -48,31 +43,23 @@
         return skippedExceptionTypes;
     }
 
-    public boolean eagerResolvingForSnippets() {
-        return (resolving == ResolvePolicy.EagerForSnippets || resolving == ResolvePolicy.Eager);
+    public boolean eagerResolving() {
+        return eagerResolving;
     }
 
-    public boolean eagerResolving() {
-        return (resolving == ResolvePolicy.Eager);
-    }
-
-    public PhasePlan plan() {
-        return plan;
+    public boolean omitAllExceptionEdges() {
+        return omitAllExceptionEdges;
     }
 
     public static GraphBuilderConfiguration getDefault() {
-        return getDefault(null);
+        return new GraphBuilderConfiguration(false, false);
     }
 
-    public static GraphBuilderConfiguration getDefault(PhasePlan plan) {
-        return new GraphBuilderConfiguration(ResolvePolicy.Default, plan);
+    public static GraphBuilderConfiguration getEagerDefault() {
+        return new GraphBuilderConfiguration(true, false);
     }
 
     public static GraphBuilderConfiguration getSnippetDefault() {
-        return getSnippetDefault(null);
-    }
-
-    public static GraphBuilderConfiguration getSnippetDefault(PhasePlan plan) {
-        return new GraphBuilderConfiguration(ResolvePolicy.EagerForSnippets, plan);
+        return new GraphBuilderConfiguration(true, true);
     }
 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Fri Mar 01 17:06:08 2013 +0100
@@ -182,11 +182,12 @@
         currentBlock = blockMap.startBlock;
         blockMap.startBlock.entryState = frameState;
         if (blockMap.startBlock.isLoopHeader) {
-            // TODO(lstadler,gduboscq) createTarget might not be safe at this position, since it
-            // expects currentBlock,
-            // etc. to be set up correctly. A better solution to this problem of start blocks that
-            // are loop headers
-            // would be to create a dummy block in BciBlockMapping.
+            /*
+             * TODO(lstadler,gduboscq) createTarget might not be safe at this position, since it
+             * expects currentBlock, etc. to be set up correctly. A better solution to this problem
+             * of start blocks that are loop headers would be to create a dummy block in
+             * BciBlockMapping.
+             */
             appendGoto(createTarget(blockMap.startBlock, frameState));
         } else {
             blockMap.startBlock.firstInstruction = lastInstr;
@@ -635,21 +636,21 @@
     private JavaType lookupType(int cpi, int bytecode) {
         eagerResolvingForSnippets(cpi, bytecode);
         JavaType result = constantPool.lookupType(cpi, bytecode);
-        assert !graphBuilderConfig.eagerResolvingForSnippets() || result instanceof ResolvedJavaType;
+        assert !graphBuilderConfig.eagerResolving() || result instanceof ResolvedJavaType;
         return result;
     }
 
     private JavaMethod lookupMethod(int cpi, int opcode) {
         eagerResolvingForSnippets(cpi, opcode);
         JavaMethod result = constantPool.lookupMethod(cpi, opcode);
-        assert !graphBuilderConfig.eagerResolvingForSnippets() || ((result instanceof ResolvedJavaMethod) && ((ResolvedJavaMethod) result).getDeclaringClass().isInitialized()) : result;
+        assert !graphBuilderConfig.eagerResolving() || ((result instanceof ResolvedJavaMethod) && ((ResolvedJavaMethod) result).getDeclaringClass().isInitialized()) : result;
         return result;
     }
 
     private JavaField lookupField(int cpi, int opcode) {
         eagerResolvingForSnippets(cpi, opcode);
         JavaField result = constantPool.lookupField(cpi, opcode);
-        assert !graphBuilderConfig.eagerResolvingForSnippets() || (result instanceof ResolvedJavaField && ((ResolvedJavaField) result).getDeclaringClass().isInitialized()) : result;
+        assert !graphBuilderConfig.eagerResolving() || (result instanceof ResolvedJavaField && ((ResolvedJavaField) result).getDeclaringClass().isInitialized()) : result;
         return result;
     }
 
@@ -660,14 +661,8 @@
         return result;
     }
 
-    // private void eagerResolving(int cpi, int bytecode) {
-    // if (graphBuilderConfig.eagerResolving()) {
-    // constantPool.loadReferencedType(cpi, bytecode);
-    // }
-    // }
-
     private void eagerResolvingForSnippets(int cpi, int bytecode) {
-        if (graphBuilderConfig.eagerResolvingForSnippets()) {
+        if (graphBuilderConfig.eagerResolving()) {
             constantPool.loadReferencedType(cpi, bytecode);
         }
     }
@@ -1038,13 +1033,13 @@
         }
 
         JavaType returnType = targetMethod.getSignature().getReturnType(method.getDeclaringClass());
-        if (graphBuilderConfig.eagerResolvingForSnippets()) {
+        if (graphBuilderConfig.eagerResolving()) {
             returnType = returnType.resolve(targetMethod.getDeclaringClass());
         }
         MethodCallTargetNode callTarget = currentGraph.add(new MethodCallTargetNode(invokeKind, targetMethod, args, returnType));
         // be conservative if information was not recorded (could result in endless recompiles
         // otherwise)
-        if (optimisticOpts.useExceptionProbability() && profilingInfo.getExceptionSeen(bci()) == ExceptionSeen.FALSE) {
+        if (graphBuilderConfig.omitAllExceptionEdges() || (optimisticOpts.useExceptionProbability() && profilingInfo.getExceptionSeen(bci()) == ExceptionSeen.FALSE)) {
             ValueNode result = appendWithBCI(currentGraph.add(new InvokeNode(callTarget, bci())));
             frameState.pushReturn(resultType, result);
 
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java	Fri Mar 01 17:06:08 2013 +0100
@@ -26,10 +26,11 @@
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 
 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.ConditionFlag;
 import com.oracle.graal.asm.amd64.*;
-import com.oracle.graal.asm.amd64.AMD64Assembler.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
@@ -48,12 +49,12 @@
     MOV_I2F, MOV_L2D, MOV_F2I, MOV_D2L;
 
 
-    public static class Op1Reg extends AMD64LIRInstruction {
+    public static class Unary2Op extends AMD64LIRInstruction {
         @Opcode private final AMD64Arithmetic opcode;
-        @Def({REG, HINT}) protected Value result;
-        @Use({REG}) protected Value x;
+        @Def({REG}) protected AllocatableValue result;
+        @Use({REG}) protected AllocatableValue x;
 
-        public Op1Reg(AMD64Arithmetic opcode, Value result, Value x) {
+        public Unary2Op(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x) {
             this.opcode = opcode;
             this.result = result;
             this.x = x;
@@ -65,12 +66,12 @@
         }
     }
 
-    public static class Op1Stack extends AMD64LIRInstruction {
+    public static class Unary1Op extends AMD64LIRInstruction {
         @Opcode private final AMD64Arithmetic opcode;
-        @Def({REG, HINT}) protected Value result;
-        @Use({REG, STACK, CONST}) protected Value x;
+        @Def({REG, HINT}) protected AllocatableValue result;
+        @Use({REG, STACK}) protected AllocatableValue x;
 
-        public Op1Stack(AMD64Arithmetic opcode, Value result, Value x) {
+        public Unary1Op(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x) {
             this.opcode = opcode;
             this.result = result;
             this.x = x;
@@ -264,14 +265,12 @@
 
 
     @SuppressWarnings("unused")
-    protected static void emit(TargetMethodAssembler tasm, AMD64MacroAssembler masm, AMD64Arithmetic opcode, Value result) {
+    protected static void emit(TargetMethodAssembler tasm, AMD64MacroAssembler masm, AMD64Arithmetic opcode, AllocatableValue result) {
         switch (opcode) {
             case INEG: masm.negl(asIntReg(result)); break;
             case LNEG: masm.negq(asLongReg(result)); break;
             case L2I:  masm.andl(asIntReg(result), 0xFFFFFFFF); break;
-            case I2B:  masm.signExtendByte(asIntReg(result)); break;
             case I2C:  masm.andl(asIntReg(result), 0xFFFF); break;
-            case I2S:  masm.signExtendShort(asIntReg(result)); break;
             default:   throw GraalInternalError.shouldNotReachHere();
         }
     }
@@ -286,9 +285,9 @@
                 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: masm.shll(asIntReg(dst)); break;
-                case ISHR: masm.sarl(asIntReg(dst)); break;
-                case IUSHR:masm.shrl(asIntReg(dst)); break;
+                case ISHL: assert asIntReg(src) == AMD64.rcx; masm.shll(asIntReg(dst)); break;
+                case ISHR: assert asIntReg(src) == AMD64.rcx; masm.sarl(asIntReg(dst)); break;
+                case IUSHR: assert asIntReg(src) == AMD64.rcx; masm.shrl(asIntReg(dst)); break;
 
                 case LADD: masm.addq(asLongReg(dst),  asLongReg(src)); break;
                 case LSUB: masm.subq(asLongReg(dst),  asLongReg(src)); break;
@@ -296,9 +295,9 @@
                 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: masm.shlq(asLongReg(dst)); break;
-                case LSHR: masm.sarq(asLongReg(dst)); break;
-                case LUSHR:masm.shrq(asLongReg(dst)); break;
+                case LSHL: assert asIntReg(src) == AMD64.rcx; masm.shlq(asLongReg(dst)); break;
+                case LSHR: assert asIntReg(src) == AMD64.rcx; masm.sarq(asLongReg(dst)); break;
+                case LUSHR: assert asIntReg(src) == AMD64.rcx; masm.shrq(asLongReg(dst)); break;
 
                 case FADD: masm.addss(asFloatReg(dst), asFloatReg(src)); break;
                 case FSUB: masm.subss(asFloatReg(dst), asFloatReg(src)); break;
@@ -316,6 +315,8 @@
                 case DOR:  masm.orpd(asDoubleReg(dst),  asDoubleReg(src)); break;
                 case DXOR: masm.xorpd(asDoubleReg(dst), asDoubleReg(src)); break;
 
+                case I2B: masm.movsxb(asIntReg(dst), asIntReg(src)); break;
+                case I2S: masm.movsxw(asIntReg(dst), asIntReg(src)); break;
                 case I2L: masm.movslq(asLongReg(dst), asIntReg(src)); break;
                 case F2D: masm.cvtss2sd(asDoubleReg(dst), asFloatReg(src)); break;
                 case D2F: masm.cvtsd2ss(asFloatReg(dst), asDoubleReg(src)); break;
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BitManipulationOp.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BitManipulationOp.java	Fri Mar 01 17:06:08 2013 +0100
@@ -24,7 +24,6 @@
 
 import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.lir.asm.*;
 
@@ -35,10 +34,10 @@
     }
 
     @Opcode private final IntrinsicOpcode opcode;
-    @Def protected Value result;
-    @Use({OperandFlag.REG, OperandFlag.ADDR}) protected Value input;
+    @Def protected AllocatableValue result;
+    @Use({OperandFlag.REG, OperandFlag.STACK}) protected AllocatableValue input;
 
-    public AMD64BitManipulationOp(IntrinsicOpcode opcode, Value result, Value input) {
+    public AMD64BitManipulationOp(IntrinsicOpcode opcode, AllocatableValue result, AllocatableValue input) {
         this.opcode = opcode;
         this.result = result;
         this.input = input;
@@ -47,8 +46,8 @@
     @Override
     public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
         Register dst = ValueUtil.asIntReg(result);
-        if (ValueUtil.isAddress(input)) {
-            AMD64Address src = (AMD64Address) ValueUtil.asAddress(input);
+        if (ValueUtil.isRegister(input)) {
+            Register src = ValueUtil.asRegister(input);
             switch (opcode) {
                 case IPOPCNT:
                     masm.popcntl(dst, src);
@@ -67,7 +66,7 @@
                     break;
             }
         } else {
-            Register src = ValueUtil.asRegister(input);
+            AMD64Address src = (AMD64Address) tasm.asAddress(input);
             switch (opcode) {
                 case IPOPCNT:
                     masm.popcntl(dst, src);
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java	Fri Mar 01 17:06:08 2013 +0100
@@ -24,6 +24,7 @@
 
 import static com.oracle.graal.api.code.ValueUtil.*;
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
 import static java.lang.Double.*;
 import static java.lang.Float.*;
 
@@ -42,6 +43,7 @@
 
     @Opcode("MOVE")
     public static class SpillMoveOp extends AMD64LIRInstruction implements MoveOp {
+
         @Def({REG, STACK}) protected Value result;
         @Use({REG, STACK, CONST}) protected Value input;
 
@@ -59,15 +61,16 @@
         public Value getInput() {
             return input;
         }
+
         @Override
         public Value getResult() {
             return result;
         }
     }
 
-
     @Opcode("MOVE")
     public static class MoveToRegOp extends AMD64LIRInstruction implements MoveOp {
+
         @Def({REG, HINT}) protected Value result;
         @Use({REG, STACK, CONST}) protected Value input;
 
@@ -85,15 +88,16 @@
         public Value getInput() {
             return input;
         }
+
         @Override
         public Value getResult() {
             return result;
         }
     }
 
-
     @Opcode("MOVE")
     public static class MoveFromRegOp extends AMD64LIRInstruction implements MoveOp {
+
         @Def({REG, STACK}) protected Value result;
         @Use({REG, CONST, HINT}) protected Value input;
 
@@ -111,66 +115,201 @@
         public Value getInput() {
             return input;
         }
+
         @Override
         public Value getResult() {
             return result;
         }
     }
 
+    public abstract static class MemOp extends AMD64LIRInstruction {
 
-    public static class LoadOp extends AMD64LIRInstruction {
-        @Def({REG}) protected Value result;
-        @Use({ADDR}) protected Value address;
+        @Use({ADDR}) protected AMD64Address address;
         @State protected LIRFrameState state;
 
-        public LoadOp(Value result, Value address, LIRFrameState state) {
-            this.result = result;
+        public MemOp(AMD64Address address, LIRFrameState state) {
             this.address = address;
             this.state = state;
         }
 
+        protected abstract void emitMemAccess(AMD64MacroAssembler masm);
+
         @Override
         public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
-            load(tasm, masm, result, (AMD64Address) address, state);
+            if (state != null) {
+                tasm.recordImplicitException(masm.codeBuffer.position(), state);
+            }
+            emitMemAccess(masm);
+        }
+    }
+
+    public static class LoadOp extends MemOp {
+
+        @Def({REG}) protected AllocatableValue result;
+
+        public LoadOp(AllocatableValue result, AMD64Address address, LIRFrameState state) {
+            super(address, state);
+            this.result = result;
+        }
+
+        @Override
+        public void emitMemAccess(AMD64MacroAssembler masm) {
+            switch (address.getKind()) {
+                case Boolean:
+                case Byte:
+                    masm.movsxb(asRegister(result), address);
+                    break;
+                case Char:
+                    masm.movzxl(asRegister(result), address);
+                    break;
+                case Short:
+                    masm.movswl(asRegister(result), address);
+                    break;
+                case Int:
+                    masm.movslq(asRegister(result), address);
+                    break;
+                case Long:
+                    masm.movq(asRegister(result), address);
+                    break;
+                case Float:
+                    masm.movflt(asFloatReg(result), address);
+                    break;
+                case Double:
+                    masm.movdbl(asDoubleReg(result), address);
+                    break;
+                case Object:
+                    masm.movq(asRegister(result), address);
+                    break;
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
+            }
         }
     }
 
+    public static class StoreOp extends MemOp {
 
-    public static class StoreOp extends AMD64LIRInstruction {
-        @Use({ADDR}) protected Value address;
-        @Use({REG, CONST}) protected Value input;
-        @State protected LIRFrameState state;
+        @Use({REG}) protected AllocatableValue input;
 
-        public StoreOp(Value address, Value input, LIRFrameState state) {
-            this.address = address;
+        public StoreOp(AMD64Address address, AllocatableValue input, LIRFrameState state) {
+            super(address, state);
             this.input = input;
-            this.state = state;
         }
 
         @Override
-        public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
-            store(tasm, masm, (AMD64Address) address, input, state);
+        public void emitMemAccess(AMD64MacroAssembler masm) {
+            assert isRegister(input);
+            switch (address.getKind()) {
+                case Boolean:
+                case Byte:
+                    masm.movb(address, asRegister(input));
+                    break;
+                case Char:
+                case Short:
+                    masm.movw(address, asRegister(input));
+                    break;
+                case Int:
+                    masm.movl(address, asRegister(input));
+                    break;
+                case Long:
+                    masm.movq(address, asRegister(input));
+                    break;
+                case Float:
+                    masm.movflt(address, asFloatReg(input));
+                    break;
+                case Double:
+                    masm.movsd(address, asDoubleReg(input));
+                    break;
+                case Object:
+                    masm.movq(address, asRegister(input));
+                    break;
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
+            }
         }
     }
 
+    public static class StoreConstantOp extends MemOp {
+
+        @Use({CONST}) protected Constant input;
+
+        public StoreConstantOp(AMD64Address address, Constant input, LIRFrameState state) {
+            super(address, state);
+            this.input = input;
+        }
+
+        @Override
+        public void emitMemAccess(AMD64MacroAssembler masm) {
+            switch (address.getKind()) {
+                case Boolean:
+                case Byte:
+                    masm.movb(address, input.asInt() & 0xFF);
+                    break;
+                case Char:
+                case Short:
+                    masm.movw(address, input.asInt() & 0xFFFF);
+                    break;
+                case Int:
+                    masm.movl(address, input.asInt());
+                    break;
+                case Long:
+                    if (NumUtil.isInt(input.asLong())) {
+                        masm.movslq(address, (int) input.asLong());
+                    } else {
+                        throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory");
+                    }
+                    break;
+                case Float:
+                    masm.movl(address, floatToRawIntBits(input.asFloat()));
+                    break;
+                case Double:
+                    throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory");
+                case Object:
+                    if (input.isNull()) {
+                        masm.movptr(address, 0);
+                    } else {
+                        throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory");
+                    }
+                    break;
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
+            }
+        }
+    }
 
     public static class LeaOp extends AMD64LIRInstruction {
-        @Def({REG}) protected Value result;
-        @Use({ADDR, STACK, UNINITIALIZED}) protected Value address;
 
-        public LeaOp(Value result, Value address) {
+        @Def({REG}) protected AllocatableValue result;
+        @Use({ADDR, UNINITIALIZED}) protected AMD64Address address;
+
+        public LeaOp(AllocatableValue result, AMD64Address address) {
             this.result = result;
             this.address = address;
         }
 
         @Override
         public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
-            masm.leaq(asLongReg(result), (AMD64Address) tasm.asAddress(address));
+            masm.leaq(asLongReg(result), address);
         }
     }
 
+    public static class StackLeaOp extends AMD64LIRInstruction {
+
+        @Def({REG}) protected AllocatableValue result;
+        @Use({STACK, UNINITIALIZED}) protected StackSlot slot;
+
+        public StackLeaOp(AllocatableValue result, StackSlot slot) {
+            this.result = result;
+            this.slot = slot;
+        }
+
+        @Override
+        public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
+            masm.leaq(asLongReg(result), (AMD64Address) tasm.asAddress(slot));
+        }
+    }
 
     public static class MembarOp extends AMD64LIRInstruction {
+
         private final int barriers;
 
         public MembarOp(final int barriers) {
@@ -183,9 +322,9 @@
         }
     }
 
+    public static class NullCheckOp extends AMD64LIRInstruction {
 
-    public static class NullCheckOp extends AMD64LIRInstruction {
-        @Use protected Value input;
+        @Use protected AllocatableValue input;
         @State protected LIRFrameState state;
 
         public NullCheckOp(Variable input, LIRFrameState state) {
@@ -200,15 +339,15 @@
         }
     }
 
-
     @Opcode("CAS")
     public static class CompareAndSwapOp extends AMD64LIRInstruction {
-        @Def protected Value result;
-        @Use({ADDR}) protected Value address;
-        @Use protected Value cmpValue;
-        @Use protected Value newValue;
 
-        public CompareAndSwapOp(Value result, Address address, Value cmpValue, Value newValue) {
+        @Def protected AllocatableValue result;
+        @Use({ADDR}) protected AMD64Address address;
+        @Use protected AllocatableValue cmpValue;
+        @Use protected AllocatableValue newValue;
+
+        public CompareAndSwapOp(AllocatableValue result, AMD64Address address, AllocatableValue cmpValue, AllocatableValue newValue) {
             this.result = result;
             this.address = address;
             this.cmpValue = cmpValue;
@@ -217,11 +356,10 @@
 
         @Override
         public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
-            compareAndSwap(tasm, masm, result, (AMD64Address) address, cmpValue, newValue);
+            compareAndSwap(tasm, masm, result, address, cmpValue, newValue);
         }
     }
 
-
     public static void move(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Value result, Value input) {
         if (isRegister(input)) {
             if (isRegister(result)) {
@@ -255,43 +393,79 @@
             return;
         }
         switch (input.getKind()) {
-            case Int:    masm.movl(asRegister(result),    asRegister(input)); break;
-            case Long:   masm.movq(asRegister(result),    asRegister(input)); break;
-            case Float:  masm.movflt(asFloatReg(result),  asFloatReg(input)); break;
-            case Double: masm.movdbl(asDoubleReg(result), asDoubleReg(input)); break;
-            case Object: masm.movq(asRegister(result),    asRegister(input)); break;
-            default:     throw GraalInternalError.shouldNotReachHere("kind=" + result.getKind());
+            case Int:
+                masm.movl(asRegister(result), asRegister(input));
+                break;
+            case Long:
+                masm.movq(asRegister(result), asRegister(input));
+                break;
+            case Float:
+                masm.movflt(asFloatReg(result), asFloatReg(input));
+                break;
+            case Double:
+                masm.movdbl(asDoubleReg(result), asDoubleReg(input));
+                break;
+            case Object:
+                masm.movq(asRegister(result), asRegister(input));
+                break;
+            default:
+                throw GraalInternalError.shouldNotReachHere("kind=" + result.getKind());
         }
     }
 
     private static void reg2stack(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Value result, Value input) {
         AMD64Address dest = (AMD64Address) tasm.asAddress(result);
         switch (input.getKind()) {
-            case Int:    masm.movl(dest,   asRegister(input)); break;
-            case Long:   masm.movq(dest,   asRegister(input)); break;
-            case Float:  masm.movflt(dest, asFloatReg(input)); break;
-            case Double: masm.movsd(dest,  asDoubleReg(input)); break;
-            case Object: masm.movq(dest,   asRegister(input)); break;
-            default:     throw GraalInternalError.shouldNotReachHere();
+            case Int:
+                masm.movl(dest, asRegister(input));
+                break;
+            case Long:
+                masm.movq(dest, asRegister(input));
+                break;
+            case Float:
+                masm.movflt(dest, asFloatReg(input));
+                break;
+            case Double:
+                masm.movsd(dest, asDoubleReg(input));
+                break;
+            case Object:
+                masm.movq(dest, asRegister(input));
+                break;
+            default:
+                throw GraalInternalError.shouldNotReachHere();
         }
     }
 
     private static void stack2reg(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Value result, Value input) {
         AMD64Address src = (AMD64Address) tasm.asAddress(input);
         switch (input.getKind()) {
-            case Int:    masm.movl(asRegister(result),    src); break;
-            case Long:   masm.movq(asRegister(result),    src); break;
-            case Float:  masm.movflt(asFloatReg(result),  src); break;
-            case Double: masm.movdbl(asDoubleReg(result), src); break;
-            case Object: masm.movq(asRegister(result),    src); break;
-            default:     throw GraalInternalError.shouldNotReachHere();
+            case Int:
+                masm.movl(asRegister(result), src);
+                break;
+            case Long:
+                masm.movq(asRegister(result), src);
+                break;
+            case Float:
+                masm.movflt(asFloatReg(result), src);
+                break;
+            case Double:
+                masm.movdbl(asDoubleReg(result), src);
+                break;
+            case Object:
+                masm.movq(asRegister(result), src);
+                break;
+            default:
+                throw GraalInternalError.shouldNotReachHere();
         }
     }
 
     private static void const2reg(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Value result, Constant input) {
-        // Note: we use the kind of the input operand (and not the kind of the result operand) because they don't match
-        // in all cases. For example, an object constant can be loaded to a long register when unsafe casts occurred (e.g.,
-        // for a write barrier where arithmetic operations are then performed on the pointer).
+        /*
+         * Note: we use the kind of the input operand (and not the kind of the result operand)
+         * because they don't match in all cases. For example, an object constant can be loaded to a
+         * long register when unsafe casts occurred (e.g., for a write barrier where arithmetic
+         * operations are then performed on the pointer).
+         */
         switch (input.getKind().getStackKind()) {
             case Int:
                 if (tasm.runtime.needsDataPatch(input)) {
@@ -352,10 +526,18 @@
         assert !tasm.runtime.needsDataPatch(input);
         AMD64Address dest = (AMD64Address) tasm.asAddress(result);
         switch (input.getKind().getStackKind()) {
-            case Int:    masm.movl(dest, input.asInt()); break;
-            case Long:   masm.movlong(dest, input.asLong()); break;
-            case Float:  masm.movl(dest, floatToRawIntBits(input.asFloat())); break;
-            case Double: masm.movlong(dest, doubleToRawLongBits(input.asDouble())); break;
+            case Int:
+                masm.movl(dest, input.asInt());
+                break;
+            case Long:
+                masm.movlong(dest, input.asLong());
+                break;
+            case Float:
+                masm.movl(dest, floatToRawIntBits(input.asFloat()));
+                break;
+            case Double:
+                masm.movlong(dest, doubleToRawLongBits(input.asDouble()));
+                break;
             case Object:
                 if (input.isNull()) {
                     masm.movlong(dest, 0L);
@@ -368,87 +550,22 @@
         }
     }
 
-
-    public static void load(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Value result, AMD64Address loadAddr, LIRFrameState info) {
-        if (info != null) {
-            tasm.recordImplicitException(masm.codeBuffer.position(), info);
-        }
-        switch (loadAddr.getKind()) {
-            case Boolean:
-            case Byte:   masm.movsxb(asRegister(result),  loadAddr); break;
-            case Char:   masm.movzxl(asRegister(result),  loadAddr); break;
-            case Short:  masm.movswl(asRegister(result),  loadAddr); break;
-            case Int:    masm.movslq(asRegister(result),  loadAddr); break;
-            case Long:   masm.movq(asRegister(result),    loadAddr); break;
-            case Float:  masm.movflt(asFloatReg(result),  loadAddr); break;
-            case Double: masm.movdbl(asDoubleReg(result), loadAddr); break;
-            case Object: masm.movq(asRegister(result),    loadAddr); break;
-            default:     throw GraalInternalError.shouldNotReachHere();
-        }
-    }
-
-    public static void store(TargetMethodAssembler tasm, AMD64MacroAssembler masm, AMD64Address storeAddr, Value input, LIRFrameState info) {
-        if (info != null) {
-            tasm.recordImplicitException(masm.codeBuffer.position(), info);
-        }
-
-        if (isRegister(input)) {
-            switch (storeAddr.getKind()) {
-                case Boolean:
-                case Byte:   masm.movb(storeAddr,   asRegister(input)); break;
-                case Char:
-                case Short:  masm.movw(storeAddr,   asRegister(input)); break;
-                case Int:    masm.movl(storeAddr,   asRegister(input)); break;
-                case Long:   masm.movq(storeAddr,   asRegister(input)); break;
-                case Float:  masm.movflt(storeAddr, asFloatReg(input)); break;
-                case Double: masm.movsd(storeAddr,  asDoubleReg(input)); break;
-                case Object: masm.movq(storeAddr,   asRegister(input)); break;
-                default:     throw GraalInternalError.shouldNotReachHere();
-            }
-        } else if (isConstant(input)) {
-            Constant c = (Constant) input;
-            switch (storeAddr.getKind()) {
-                case Boolean:
-                case Byte:   masm.movb(storeAddr, c.asInt() & 0xFF); break;
-                case Char:
-                case Short:  masm.movw(storeAddr, c.asInt() & 0xFFFF); break;
-                case Int:    masm.movl(storeAddr, c.asInt()); break;
-                case Long:
-                    if (NumUtil.isInt(c.asLong())) {
-                        masm.movslq(storeAddr, (int) c.asLong());
-                    } else {
-                        throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory");
-                    }
-                    break;
-                case Float:  masm.movl(storeAddr, floatToRawIntBits(c.asFloat())); break;
-                case Double: throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory");
-                case Object:
-                    if (c.isNull()) {
-                        masm.movptr(storeAddr, 0);
-                    } else {
-                        throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory");
-                    }
-                    break;
-                default:
-                    throw GraalInternalError.shouldNotReachHere();
-            }
-
-        } else {
-            throw GraalInternalError.shouldNotReachHere();
-        }
-    }
-
-    protected static void compareAndSwap(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Value result, AMD64Address address, Value cmpValue, Value newValue) {
+    protected static void compareAndSwap(TargetMethodAssembler tasm, AMD64MacroAssembler masm, AllocatableValue result, AMD64Address address, AllocatableValue cmpValue, AllocatableValue newValue) {
         assert asRegister(cmpValue) == AMD64.rax && asRegister(result) == AMD64.rax;
 
         if (tasm.target.isMP) {
             masm.lock();
         }
         switch (cmpValue.getKind()) {
-            case Int:    masm.cmpxchgl(asRegister(newValue), address); break;
+            case Int:
+                masm.cmpxchgl(asRegister(newValue), address);
+                break;
             case Long:
-            case Object: masm.cmpxchgq(asRegister(newValue), address); break;
-            default:     throw GraalInternalError.shouldNotReachHere();
+            case Object:
+                masm.cmpxchgq(asRegister(newValue), address);
+                break;
+            default:
+                throw GraalInternalError.shouldNotReachHere();
         }
     }
 }
--- a/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXMove.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXMove.java	Fri Mar 01 17:06:08 2013 +0100
@@ -120,11 +120,11 @@
 
     public static class LoadOp extends PTXLIRInstruction {
 
-        @Def({REG}) protected Value result;
-        @Use({ADDR}) protected Value address;
+        @Def({REG}) protected AllocatableValue result;
+        @Use({ADDR}) protected PTXAddress address;
         @State protected LIRFrameState state;
 
-        public LoadOp(Value result, Value address, LIRFrameState state) {
+        public LoadOp(AllocatableValue result, PTXAddress address, LIRFrameState state) {
             this.result = result;
             this.address = address;
             this.state = state;
@@ -132,17 +132,28 @@
 
         @Override
         public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) {
-            load(tasm, masm, result, (PTXAddress) address, state);
+            Register a = asRegister(address.getBase());
+            long immOff = address.getDisplacement();
+            switch (address.getKind()) {
+                case Int:
+                    masm.ld_global_s32(asRegister(result), a, immOff);
+                    break;
+                case Object:
+                    masm.ld_global_u32(asRegister(result), a, immOff);
+                    break;
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
+            }
         }
     }
 
     public static class StoreOp extends PTXLIRInstruction {
 
-        @Use({ADDR}) protected Value address;
-        @Use({REG, CONST}) protected Value input;
+        @Use({ADDR}) protected PTXAddress address;
+        @Use({REG}) protected AllocatableValue input;
         @State protected LIRFrameState state;
 
-        public StoreOp(Value address, Value input, LIRFrameState state) {
+        public StoreOp(PTXAddress address, AllocatableValue input, LIRFrameState state) {
             this.address = address;
             this.input = input;
             this.state = state;
@@ -150,16 +161,26 @@
 
         @Override
         public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) {
-            store(tasm, masm, (PTXAddress) address, input, state);
+            Register a = asRegister(address.getBase());
+            long immOff = address.getDisplacement();
+
+            assert isRegister(input);
+            switch (address.getKind()) {
+                case Int:
+                    masm.st_global_s32(a, immOff, asRegister(input));
+                    break;
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
+            }
         }
     }
 
     public static class LeaOp extends PTXLIRInstruction {
 
-        @Def({REG}) protected Value result;
-        @Use({ADDR, STACK, UNINITIALIZED}) protected Value address;
+        @Def({REG}) protected AllocatableValue result;
+        @Use({ADDR, UNINITIALIZED}) protected PTXAddress address;
 
-        public LeaOp(Value result, Value address) {
+        public LeaOp(AllocatableValue result, PTXAddress address) {
             this.result = result;
             this.address = address;
         }
@@ -170,15 +191,31 @@
         }
     }
 
+    public static class StackLeaOp extends PTXLIRInstruction {
+
+        @Def({REG}) protected AllocatableValue result;
+        @Use({STACK, UNINITIALIZED}) protected StackSlot slot;
+
+        public StackLeaOp(AllocatableValue result, StackSlot slot) {
+            this.result = result;
+            this.slot = slot;
+        }
+
+        @Override
+        public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) {
+            throw new InternalError("NYI");
+        }
+    }
+
     @Opcode("CAS")
     public static class CompareAndSwapOp extends PTXLIRInstruction {
 
-        @Def protected Value result;
-        @Use({ADDR}) protected Value address;
-        @Use protected Value cmpValue;
-        @Use protected Value newValue;
+        @Def protected AllocatableValue result;
+        @Use({ADDR}) protected PTXAddress address;
+        @Use protected AllocatableValue cmpValue;
+        @Use protected AllocatableValue newValue;
 
-        public CompareAndSwapOp(Value result, Address address, Value cmpValue, Value newValue) {
+        public CompareAndSwapOp(AllocatableValue result, PTXAddress address, AllocatableValue cmpValue, AllocatableValue newValue) {
             this.result = result;
             this.address = address;
             this.cmpValue = cmpValue;
@@ -187,7 +224,7 @@
 
         @Override
         public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) {
-            compareAndSwap(tasm, masm, result, (Address) address, cmpValue, newValue);
+            compareAndSwap(tasm, masm, result, address, cmpValue, newValue);
         }
     }
 
@@ -239,47 +276,7 @@
     }
 
     @SuppressWarnings("unused")
-    public static void load(TargetMethodAssembler tasm, PTXAssembler masm, Value result, PTXAddress loadAddr, LIRFrameState info) {
-        Register a = asRegister(loadAddr.getBase());
-        long immOff = loadAddr.getDisplacement();
-        switch (loadAddr.getKind()) {
-            case Int:
-                masm.ld_global_s32(asRegister(result), a, immOff);
-                break;
-            case Object:
-                masm.ld_global_u32(asRegister(result), a, immOff);
-                break;
-            default:
-                throw GraalInternalError.shouldNotReachHere();
-        }
-    }
-
-    @SuppressWarnings("unused")
-    public static void store(TargetMethodAssembler tasm, PTXAssembler masm, PTXAddress storeAddr, Value input, LIRFrameState info) {
-        Register a = asRegister(storeAddr.getBase());
-        long immOff = storeAddr.getDisplacement();
-        if (isRegister(input)) {
-            switch (storeAddr.getKind()) {
-                case Int:
-                    masm.st_global_s32(a, immOff, asRegister(input));
-                    break;
-                default:
-                    throw GraalInternalError.shouldNotReachHere();
-            }
-        } else if (isConstant(input)) {
-            Constant c = (Constant) input;
-            switch (storeAddr.getKind()) {
-                default:
-                    throw GraalInternalError.shouldNotReachHere();
-            }
-
-        } else {
-            throw GraalInternalError.shouldNotReachHere();
-        }
-    }
-
-    @SuppressWarnings("unused")
-    protected static void compareAndSwap(TargetMethodAssembler tasm, PTXAssembler masm, Value result, Address address, Value cmpValue, Value newValue) {
+    protected static void compareAndSwap(TargetMethodAssembler tasm, PTXAssembler masm, AllocatableValue result, PTXAddress address, AllocatableValue cmpValue, AllocatableValue newValue) {
         throw new InternalError("NYI");
     }
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java	Fri Mar 01 17:06:08 2013 +0100
@@ -347,28 +347,4 @@
             }
         }
     }
-
-    /**
-     * Clears the specified location as a reference in the reference map of the debug information.
-     * The tracked location can be a {@link RegisterValue} or a {@link StackSlot}. Note that a
-     * {@link Constant} is automatically tracked.
-     * 
-     * @param location The location to be removed from the reference map.
-     * @param registerRefMap A register reference map, as created by {@link #initRegisterRefMap()}.
-     * @param frameRefMap A frame reference map, as created by {@link #initFrameRefMap()}.
-     */
-    public void clearReference(Value location, BitSet registerRefMap, BitSet frameRefMap) {
-        if (location.getKind() == Kind.Object) {
-            if (location instanceof RegisterValue) {
-                registerRefMap.clear(asRegister(location).number);
-            } else if (isStackSlot(location)) {
-                int index = frameRefMapIndex(asStackSlot(location));
-                if (index < frameRefMap.size()) {
-                    frameRefMap.clear(index);
-                }
-            } else {
-                assert isConstant(location);
-            }
-        }
-    }
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java	Fri Mar 01 17:06:08 2013 +0100
@@ -181,6 +181,11 @@
         ILLEGAL,
 
         /**
+         * The value can be {@link AllocatableValue#UNUSED}.
+         */
+        UNUSED,
+
+        /**
          * The register allocator should try to assign a certain register to improve code quality.
          * Use {@link LIRInstruction#forEachRegisterHint} to access the register hints.
          */
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRVerifier.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRVerifier.java	Fri Mar 01 17:06:08 2013 +0100
@@ -232,7 +232,8 @@
 
     private static Value allowed(Object op, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
         if ((isVariable(value) && flags.contains(OperandFlag.REG)) || (isRegister(value) && flags.contains(OperandFlag.REG)) || (isStackSlot(value) && flags.contains(OperandFlag.STACK)) ||
-                        (isConstant(value) && flags.contains(OperandFlag.CONST) && mode != OperandMode.DEF) || (isIllegal(value) && flags.contains(OperandFlag.ILLEGAL))) {
+                        (isConstant(value) && flags.contains(OperandFlag.CONST) && mode != OperandMode.DEF) || (isIllegal(value) && flags.contains(OperandFlag.ILLEGAL)) ||
+                        (value == AllocatableValue.UNUSED && flags.contains(OperandFlag.UNUSED))) {
             return value;
         }
         TTY.println("instruction %s", op);
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java	Fri Mar 01 17:06:08 2013 +0100
@@ -33,8 +33,6 @@
  */
 public class StandardOp {
 
-    private static Value[] EMPTY = new Value[0];
-
     /**
      * Marker interface for LIR ops that can fall through to the next operation, like a switch
      * statement. setFallThroughTarget(null) can be used to make the operation fall through to the
@@ -99,24 +97,6 @@
         }
     }
 
-    public static class PhiJumpOp extends JumpOp {
-
-        @Alive({REG, STACK, CONST}) protected Value[] phiInputs;
-
-        public PhiJumpOp(LabelRef destination, Value[] phiInputs) {
-            super(destination, null);
-            this.phiInputs = phiInputs;
-        }
-
-        public void markResolved() {
-            phiInputs = EMPTY;
-        }
-
-        public Value[] getPhiInputs() {
-            return phiInputs;
-        }
-    }
-
     /**
      * Marker interface for a LIR operation that is a conditional jump to {@link #destination()}.
      * Conditional jumps may be negated or optimized away after register allocation.
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/Variable.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/Variable.java	Fri Mar 01 17:06:08 2013 +0100
@@ -29,7 +29,7 @@
  * Represents a value that is yet to be bound to a machine location (such as a {@link RegisterValue}
  * or {@link StackSlot}) by a register allocator.
  */
-public final class Variable extends Value {
+public final class Variable extends AllocatableValue {
 
     private static final long serialVersionUID = 4507578431686109809L;
 
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java	Fri Mar 01 17:06:08 2013 +0100
@@ -179,7 +179,7 @@
                 });
             }
             nodes.mark(earlyExit);
-            for (ValueProxyNode proxy : earlyExit.proxies()) {
+            for (ProxyNode proxy : earlyExit.proxies()) {
                 nodes.mark(proxy);
             }
         }
@@ -271,9 +271,9 @@
                 anchored.replaceFirstInput(earlyExit, merge);
             }
 
-            for (final ValueProxyNode vpn : earlyExit.proxies().snapshot()) {
+            for (final ProxyNode vpn : earlyExit.proxies().snapshot()) {
                 final ValueNode replaceWith;
-                ValueProxyNode newVpn = getDuplicatedNode(vpn);
+                ProxyNode newVpn = getDuplicatedNode(vpn);
                 if (newVpn != null) {
                     PhiNode phi = graph.add(vpn.type() == PhiType.Value ? vpn.stamp() == StampFactory.virtual() ? new PhiNode(vpn.stamp(), merge) : new PhiNode(vpn.kind(), merge) : new PhiNode(
                                     vpn.type(), merge));
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java	Fri Mar 01 17:06:08 2013 +0100
@@ -108,7 +108,7 @@
     }
 
     public void removeProxies() {
-        for (ValueProxyNode vpn : proxies().snapshot()) {
+        for (ProxyNode vpn : proxies().snapshot()) {
             // can not use graph.replaceFloating because vpn.value may be null during killCFG
             vpn.replaceAtUsages(vpn.value());
             vpn.safeDelete();
@@ -131,11 +131,11 @@
     }
 
     public NodeIterable<Node> anchored() {
-        return usages().filter(isNotA(ValueProxyNode.class));
+        return usages().filter(isNotA(ProxyNode.class));
     }
 
-    public NodeIterable<ValueProxyNode> proxies() {
-        return usages().filter(ValueProxyNode.class);
+    public NodeIterable<ProxyNode> proxies() {
+        return usages().filter(ProxyNode.class);
     }
 
     public NodeIterable<FixedNode> getBlockNodes() {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Fri Mar 01 17:06:08 2013 +0100
@@ -68,6 +68,12 @@
      */
     public static final int AFTER_EXCEPTION_BCI = -3;
 
+    /**
+     * This BCI should be used for frame states that cannot be the target of a deoptimization, like
+     * snippet frame states.
+     */
+    public static final int INVALID_FRAMESTATE_BCI = -5;
+
     @Input private FrameState outerFrameState;
 
     @Input private final NodeInputList<ValueNode> values;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java	Fri Mar 01 17:06:08 2013 +0100
@@ -109,6 +109,11 @@
     }
 
     @Override
+    public Object getLocationIdentity() {
+        return LocationNode.ANY_LOCATION;
+    }
+
+    @Override
     public void lower(LoweringTool tool) {
         tool.getRuntime().lower(this, tool);
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Fri Mar 01 17:06:08 2013 +0100
@@ -161,6 +161,11 @@
         return true;
     }
 
+    @Override
+    public Object getLocationIdentity() {
+        return LocationNode.ANY_LOCATION;
+    }
+
     public FrameState stateDuring() {
         FrameState tempStateAfter = stateAfter();
         FrameState stateDuring = tempStateAfter.duplicateModified(bci(), tempStateAfter.rethrowException(), kind());
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ProxyNode.java	Fri Mar 01 17:06:08 2013 +0100
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.Node.ValueNumberable;
+import com.oracle.graal.nodes.PhiNode.PhiType;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+
+/**
+ * A value proxy that is inserted in the frame state of a loop exit for any value that is created
+ * inside the loop (i.e. was not live on entry to the loop) and is (potentially) used after the
+ * loop.
+ */
+@NodeInfo(nameTemplate = "{p#type/s}Proxy")
+public class ProxyNode extends FloatingNode implements Node.IterableNodeType, ValueNumberable, Canonicalizable, Virtualizable, LIRLowerable {
+
+    @Input(notDataflow = true) private BeginNode proxyPoint;
+    @Input private ValueNode value;
+    private final PhiType type;
+
+    public ProxyNode(ValueNode value, BeginNode exit, PhiType type) {
+        super(type == PhiType.Value ? value.stamp() : type.stamp);
+        this.type = type;
+        assert exit != null;
+        this.proxyPoint = exit;
+        this.value = value;
+    }
+
+    public ValueNode value() {
+        return value;
+    }
+
+    @Override
+    public boolean inferStamp() {
+        return updateStamp(value.stamp());
+    }
+
+    @Override
+    public Stamp stamp() {
+        return value().stamp();
+    }
+
+    public BeginNode proxyPoint() {
+        return proxyPoint;
+    }
+
+    public PhiType type() {
+        return type;
+    }
+
+    @Override
+    public boolean verify() {
+        assert value != null;
+        assert proxyPoint != null;
+        return super.verify();
+    }
+
+    @Override
+    public void generate(LIRGeneratorTool generator) {
+        assert type == PhiType.Memory;
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool) {
+        if (type == PhiType.Value && value.isConstant()) {
+            return value;
+        }
+        return this;
+    }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        if (type == PhiType.Value) {
+            State state = tool.getObjectState(value);
+            if (state != null && state.getState() == EscapeState.Virtual) {
+                tool.replaceWithVirtual(state.getVirtualObject());
+            }
+        }
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StartNode.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StartNode.java	Fri Mar 01 17:06:08 2013 +0100
@@ -29,4 +29,8 @@
  */
 public class StartNode extends BeginStateSplitNode implements MemoryCheckpoint {
 
+    @Override
+    public Object getLocationIdentity() {
+        return LocationNode.ANY_LOCATION;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueProxyNode.java	Fri Mar 01 17:05:14 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,95 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes;
-
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.Node.ValueNumberable;
-import com.oracle.graal.nodes.PhiNode.PhiType;
-import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
-
-/**
- * A value proxy that is inserted in the frame state of a loop exit for any value that is created
- * inside the loop (i.e. was not live on entry to the loop) and is (potentially) used after the
- * loop.
- */
-public class ValueProxyNode extends FloatingNode implements Node.IterableNodeType, ValueNumberable, Canonicalizable, Virtualizable {
-
-    @Input(notDataflow = true) private BeginNode proxyPoint;
-    @Input private ValueNode value;
-    private final PhiType type;
-
-    public ValueProxyNode(ValueNode value, BeginNode exit, PhiType type) {
-        super(value.stamp());
-        this.type = type;
-        assert exit != null;
-        this.proxyPoint = exit;
-        this.value = value;
-    }
-
-    public ValueNode value() {
-        return value;
-    }
-
-    @Override
-    public boolean inferStamp() {
-        return updateStamp(value.stamp());
-    }
-
-    @Override
-    public Stamp stamp() {
-        return value().stamp();
-    }
-
-    public BeginNode proxyPoint() {
-        return proxyPoint;
-    }
-
-    public PhiType type() {
-        return type;
-    }
-
-    @Override
-    public boolean verify() {
-        assert value != null;
-        assert proxyPoint != null;
-        return super.verify();
-    }
-
-    @Override
-    public ValueNode canonical(CanonicalizerTool tool) {
-        if (value.isConstant()) {
-            return value;
-        }
-        return this;
-    }
-
-    @Override
-    public void virtualize(VirtualizerTool tool) {
-        State state = tool.getObjectState(value);
-        if (state != null && state.getState() == EscapeState.Virtual) {
-            tool.replaceWithVirtual(state.getVirtualObject());
-        }
-    }
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java	Fri Mar 01 17:06:08 2013 +0100
@@ -108,9 +108,38 @@
         return loops;
     }
 
+    public void clearNodeToBlock() {
+        nodeToBlock.clear();
+        for (Block block : reversePostOrder) {
+            identifyBlock(block, block.beginNode);
+        }
+    }
+
     protected static final int BLOCK_ID_INITIAL = -1;
     protected static final int BLOCK_ID_VISITED = -2;
 
+    private void identifyBlock(Block block, BeginNode begin) {
+        block.beginNode = begin;
+        Node cur = begin;
+        Node last;
+        do {
+            assert !cur.isDeleted();
+
+            assert nodeToBlock.get(cur) == null;
+            nodeToBlock.set(cur, block);
+            if (cur instanceof MergeNode) {
+                for (PhiNode phi : ((MergeNode) cur).phis()) {
+                    nodeToBlock.set(phi, block);
+                }
+            }
+
+            last = cur;
+            cur = cur.successors().first();
+        } while (cur != null && !(cur instanceof BeginNode));
+
+        block.endNode = (FixedNode) last;
+    }
+
     private void identifyBlocks() {
         // Find all block headers
         int numBlocks = 0;
@@ -118,26 +147,7 @@
             if (node instanceof BeginNode) {
                 Block block = new Block();
                 numBlocks++;
-
-                block.beginNode = (BeginNode) node;
-                Node cur = node;
-                Node last;
-                do {
-                    assert !cur.isDeleted();
-
-                    assert nodeToBlock.get(cur) == null;
-                    nodeToBlock.set(cur, block);
-                    if (cur instanceof MergeNode) {
-                        for (PhiNode phi : ((MergeNode) cur).phis()) {
-                            nodeToBlock.set(phi, block);
-                        }
-                    }
-
-                    last = cur;
-                    cur = cur.successors().first();
-                } while (cur != null && !(cur instanceof BeginNode));
-
-                block.endNode = (FixedNode) last;
+                identifyBlock(block, (BeginNode) node);
             }
         }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java	Fri Mar 01 17:06:08 2013 +0100
@@ -53,7 +53,7 @@
 
     @Override
     public void generate(LIRGeneratorTool gen) {
-        gen.setResult(this, gen.emitLoad(gen.makeAddress(location(), object()), getNullCheck()));
+        gen.setResult(this, location().generateLoad(gen, object(), getNullCheck()));
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java	Fri Mar 01 17:06:08 2013 +0100
@@ -79,4 +79,19 @@
         }
         return this;
     }
+
+    @Override
+    public Value generateLea(LIRGeneratorTool gen, ValueNode base) {
+        return gen.emitLea(gen.operand(base), displacement(), gen.operand(index()), indexScaling());
+    }
+
+    @Override
+    public Value generateLoad(LIRGeneratorTool gen, ValueNode base, boolean canTrap) {
+        return gen.emitLoad(getValueKind(), gen.operand(base), displacement(), gen.operand(index()), indexScaling(), canTrap);
+    }
+
+    @Override
+    public void generateStore(LIRGeneratorTool gen, ValueNode base, ValueNode value, boolean canTrap) {
+        gen.emitStore(getValueKind(), gen.operand(base), displacement(), gen.operand(index()), indexScaling(), gen.operand(value), canTrap);
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LocationNode.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LocationNode.java	Fri Mar 01 17:06:08 2013 +0100
@@ -25,6 +25,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Node.ValueNumberable;
+import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
@@ -42,27 +43,37 @@
     private Object locationIdentity;
 
     /**
+     * Creates a new unique location identity for read and write operations.
+     * 
+     * @param name the name of the new location identity, for debugging purposes
+     * @return the new location identity
+     */
+    public static Object createLocation(final String name) {
+        return new Object() {
+
+            @Override
+            public String toString() {
+                return name;
+            }
+        };
+    }
+
+    /**
      * Denotes any location. A write to such a location kills all values in a memory map during an
      * analysis of memory accesses in a graph.
      */
-    public static final Object ANY_LOCATION = new Object() {
+    public static final Object ANY_LOCATION = createLocation("ANY_LOCATION");
 
-        @Override
-        public String toString() {
-            return "ANY_LOCATION";
-        }
-    };
+    /**
+     * Denotes an unknown location. A read from this location cannot be moved or coalesced with
+     * other reads because its interaction with other reads is not known.
+     */
+    public static final Object UNKNOWN_LOCATION = createLocation("UNKNOWN_LOCATION");
 
     /**
      * Denotes the location of a value that is guaranteed to be final.
      */
-    public static final Object FINAL_LOCATION = new Object() {
-
-        @Override
-        public String toString() {
-            return "FINAL_LOCATION";
-        }
-    };
+    public static final Object FINAL_LOCATION = createLocation("FINAL_LOCATION");
 
     public static Object getArrayLocation(Kind elementKind) {
         return elementKind;
@@ -96,4 +107,16 @@
     public void generate(LIRGeneratorTool generator) {
         // nothing to do...
     }
+
+    public Value generateLea(LIRGeneratorTool gen, ValueNode base) {
+        return gen.emitLea(gen.operand(base), displacement(), Value.ILLEGAL, 0);
+    }
+
+    public Value generateLoad(LIRGeneratorTool gen, ValueNode base, boolean canTrap) {
+        return gen.emitLoad(getValueKind(), gen.operand(base), displacement(), Value.ILLEGAL, 0, canTrap);
+    }
+
+    public void generateStore(LIRGeneratorTool gen, ValueNode base, ValueNode value, boolean canTrap) {
+        gen.emitStore(getValueKind(), gen.operand(base), displacement(), Value.ILLEGAL, 0, gen.operand(value), canTrap);
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MembarNode.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MembarNode.java	Fri Mar 01 17:06:08 2013 +0100
@@ -43,6 +43,11 @@
     }
 
     @Override
+    public Object getLocationIdentity() {
+        return LocationNode.ANY_LOCATION;
+    }
+
+    @Override
     public void generate(LIRGeneratorTool generator) {
         generator.emitMembar(barriers);
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryCheckpoint.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryCheckpoint.java	Fri Mar 01 17:06:08 2013 +0100
@@ -22,6 +22,21 @@
  */
 package com.oracle.graal.nodes.extended;
 
+import com.oracle.graal.nodes.*;
+
+/**
+ * This interface marks is used for subclasses of {@link FixedNode} that kill a set of memory
+ * locations represented by a location identity (i.e. change a value at one or more locations that
+ * belong to this location identity).
+ */
 public interface MemoryCheckpoint {
 
+    /**
+     * This method is used to determine which set of memory locations is killed by this node.
+     * Returning the special value {@link LocationNode#ANY_LOCATION} will kill all memory locations.
+     * 
+     * @return the identity of the location killed by this node.
+     */
+    Object getLocationIdentity();
+
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java	Fri Mar 01 17:06:08 2013 +0100
@@ -51,7 +51,7 @@
 
     @Override
     public void generate(LIRGeneratorTool gen) {
-        gen.setResult(this, gen.emitLoad(gen.makeAddress(location(), object()), getNullCheck()));
+        gen.setResult(this, location().generateLoad(gen, object(), getNullCheck()));
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/RuntimeCallNode.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/RuntimeCallNode.java	Fri Mar 01 17:06:08 2013 +0100
@@ -49,6 +49,11 @@
     }
 
     @Override
+    public Object getLocationIdentity() {
+        return LocationNode.ANY_LOCATION;
+    }
+
+    @Override
     public void generate(LIRGeneratorTool gen) {
         gen.visitRuntimeCall(this);
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java	Fri Mar 01 17:06:08 2013 +0100
@@ -93,7 +93,7 @@
         if (kind() != object.kind()) {
             assert generator.target().sizeInBytes(kind()) == generator.target().sizeInBytes(object.kind()) : "unsafe cast cannot be used to change the size of a value";
             Value result = generator.newVariable(kind());
-            generator.emitMove(generator.operand(object), result);
+            generator.emitMove(result, generator.operand(object));
             generator.setResult(this, result);
         } else {
             // The LIR only cares about the kind of an operand, not the actual type of an object. So
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java	Fri Mar 01 17:06:08 2013 +0100
@@ -33,7 +33,7 @@
  * Store of a value at a location specified as an offset relative to an object. No null check is
  * performed before the store.
  */
-public class UnsafeStoreNode extends UnsafeAccessNode implements StateSplit, Lowerable, Virtualizable, Canonicalizable {
+public class UnsafeStoreNode extends UnsafeAccessNode implements StateSplit, Lowerable, Virtualizable, Canonicalizable, MemoryCheckpoint {
 
     @Input private ValueNode value;
     @Input(notDataflow = true) private FrameState stateAfter;
@@ -72,6 +72,11 @@
     }
 
     @Override
+    public Object getLocationIdentity() {
+        return LocationNode.ANY_LOCATION;
+    }
+
+    @Override
     public void virtualize(VirtualizerTool tool) {
         State state = tool.getObjectState(object());
         if (state != null && state.getState() == EscapeState.Virtual) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteMemoryCheckpointNode.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteMemoryCheckpointNode.java	Fri Mar 01 17:06:08 2013 +0100
@@ -37,6 +37,11 @@
     }
 
     @Override
+    public Object getLocationIdentity() {
+        return LocationNode.ANY_LOCATION;
+    }
+
+    @Override
     public void generate(LIRGeneratorTool generator) {
         // nothing to do...
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java	Fri Mar 01 17:06:08 2013 +0100
@@ -29,7 +29,7 @@
 /**
  * Writes a given {@linkplain #value() value} a {@linkplain AccessNode memory location}.
  */
-public final class WriteNode extends AccessNode implements StateSplit, LIRLowerable {
+public final class WriteNode extends AccessNode implements StateSplit, LIRLowerable, MemoryCheckpoint {
 
     @Input private ValueNode value;
     @Input(notDataflow = true) private FrameState stateAfter;
@@ -59,9 +59,14 @@
 
     @Override
     public void generate(LIRGeneratorTool gen) {
-        gen.emitStore(gen.makeAddress(location(), object()), gen.operand(value()), getNullCheck());
+        location().generateStore(gen, object(), value(), getNullCheck());
     }
 
     @NodeIntrinsic
     public static native void writeMemory(Object object, Object value, Object location);
+
+    @Override
+    public Object getLocationIdentity() {
+        return location().locationIdentity();
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java	Fri Mar 01 17:06:08 2013 +0100
@@ -71,6 +71,11 @@
     }
 
     @Override
+    public Object getLocationIdentity() {
+        return LocationNode.ANY_LOCATION;
+    }
+
+    @Override
     public void generate(LIRGeneratorTool gen) {
         gen.visitCompareAndSwap(this);
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java	Fri Mar 01 17:06:08 2013 +0100
@@ -42,6 +42,11 @@
     }
 
     @Override
+    public Object getLocationIdentity() {
+        return LocationNode.ANY_LOCATION;
+    }
+
+    @Override
     public void generate(LIRGeneratorTool gen) {
         gen.visitExceptionObject(this);
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java	Fri Mar 01 17:06:08 2013 +0100
@@ -40,6 +40,11 @@
         super(object);
     }
 
+    @Override
+    public Object getLocationIdentity() {
+        return LocationNode.ANY_LOCATION;
+    }
+
     public void lower(LoweringTool tool) {
         tool.getRuntime().lower(this, tool);
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java	Fri Mar 01 17:06:08 2013 +0100
@@ -41,6 +41,11 @@
         super(object);
     }
 
+    @Override
+    public Object getLocationIdentity() {
+        return LocationNode.ANY_LOCATION;
+    }
+
     public void lower(LoweringTool tool) {
         tool.getRuntime().lower(this, tool);
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java	Fri Mar 01 17:06:08 2013 +0100
@@ -45,16 +45,6 @@
      */
     public abstract boolean canInlineConstant(Constant c);
 
-    /**
-     * Checks whether the supplied constant can be used without loading it into a register for store
-     * operations, i.e., on the right hand side of a memory access.
-     * 
-     * @param c The constant to check.
-     * @return True if the constant can be used directly, false if the constant needs to be in a
-     *         register.
-     */
-    public abstract boolean canStoreConstant(Constant c);
-
     public abstract RegisterAttributes attributes(Register register);
 
     public abstract Value operand(ValueNode object);
@@ -63,27 +53,17 @@
 
     public abstract Value setResult(ValueNode x, Value operand);
 
-    public abstract Address makeAddress(LocationNode location, ValueNode object);
-
-    public abstract Address makeAddress(Kind kind, Value base, int displacement);
-
-    public Address makeAddress(Kind kind, Value base) {
-        return makeAddress(kind, base, 0);
-    }
-
-    public Address makeAddress(Kind kind, int address) {
-        return makeAddress(kind, Value.ILLEGAL, address);
-    }
-
     public abstract Value emitMove(Value input);
 
-    public abstract void emitMove(Value src, Value dst);
+    public abstract void emitMove(Value dst, Value src);
 
-    public abstract Value emitLoad(Value loadAddress, boolean canTrap);
+    public abstract Value emitLoad(Kind kind, Value base, int displacement, Value index, int scale, boolean canTrap);
 
-    public abstract void emitStore(Value storeAddress, Value input, boolean canTrap);
+    public abstract void emitStore(Kind kind, Value base, int displacement, Value index, int scale, Value input, boolean canTrap);
 
-    public abstract Value emitLea(Value address);
+    public abstract Value emitLea(Value base, int displacement, Value index, int scale);
+
+    public abstract Value emitLea(StackSlot slot);
 
     public abstract Value emitNegate(Value input);
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Fri Mar 01 17:06:08 2013 +0100
@@ -140,18 +140,18 @@
         ValueNode singleValue = phiNode.singleValue();
         if (singleValue != null) {
             Collection<PhiNode> phiUsages = phiNode.usages().filter(PhiNode.class).snapshot();
-            Collection<ValueProxyNode> proxyUsages = phiNode.usages().filter(ValueProxyNode.class).snapshot();
+            Collection<ProxyNode> proxyUsages = phiNode.usages().filter(ProxyNode.class).snapshot();
             ((StructuredGraph) phiNode.graph()).replaceFloating(phiNode, singleValue);
             for (PhiNode phi : phiUsages) {
                 checkRedundantPhi(phi);
             }
-            for (ValueProxyNode proxy : proxyUsages) {
+            for (ProxyNode proxy : proxyUsages) {
                 checkRedundantProxy(proxy);
             }
         }
     }
 
-    public static void checkRedundantProxy(ValueProxyNode vpn) {
+    public static void checkRedundantProxy(ProxyNode vpn) {
         BeginNode proxyPoint = vpn.proxyPoint();
         if (proxyPoint instanceof LoopExitNode) {
             LoopExitNode exit = (LoopExitNode) proxyPoint;
@@ -164,12 +164,12 @@
                 }
                 if (vpnValue == v2) {
                     Collection<PhiNode> phiUsages = vpn.usages().filter(PhiNode.class).snapshot();
-                    Collection<ValueProxyNode> proxyUsages = vpn.usages().filter(ValueProxyNode.class).snapshot();
+                    Collection<ProxyNode> proxyUsages = vpn.usages().filter(ProxyNode.class).snapshot();
                     ((StructuredGraph) vpn.graph()).replaceFloating(vpn, vpnValue);
                     for (PhiNode phi : phiUsages) {
                         checkRedundantPhi(phi);
                     }
-                    for (ValueProxyNode proxy : proxyUsages) {
+                    for (ProxyNode proxy : proxyUsages) {
                         checkRedundantProxy(proxy);
                     }
                     return;
@@ -185,7 +185,7 @@
             GraphUtil.checkRedundantPhi(phi);
         }
         for (LoopExitNode exit : begin.loopExits()) {
-            for (ValueProxyNode vpn : exit.proxies().snapshot()) {
+            for (ProxyNode vpn : exit.proxies().snapshot()) {
                 GraphUtil.checkRedundantProxy(vpn);
             }
         }
@@ -259,8 +259,8 @@
 
     public static ValueNode unProxify(ValueNode proxy) {
         ValueNode v = proxy;
-        while (v instanceof ValueProxyNode) {
-            v = ((ValueProxyNode) v).value();
+        while (v instanceof ProxyNode) {
+            v = ((ProxyNode) v).value();
         }
         return v;
     }
@@ -293,8 +293,8 @@
     public static ValueNode originalValue(ValueNode proxy) {
         ValueNode v = proxy;
         do {
-            if (v instanceof ValueProxyNode) {
-                v = ((ValueProxyNode) v).value();
+            if (v instanceof ProxyNode) {
+                v = ((ProxyNode) v).value();
             } else if (v instanceof PhiNode) {
                 v = ((PhiNode) v).singleValue();
             } else {
@@ -308,8 +308,8 @@
             NodeWorkList worklist = proxy.graph().createNodeWorkList();
             worklist.add(proxy);
             for (Node node : worklist) {
-                if (node instanceof ValueProxyNode) {
-                    worklist.add(((ValueProxyNode) node).value());
+                if (node instanceof ProxyNode) {
+                    worklist.add(((ProxyNode) node).value());
                 } else if (node instanceof PhiNode) {
                     worklist.addAll(((PhiNode) node).values());
                 } else {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CullFrameStatesPhase.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CullFrameStatesPhase.java	Fri Mar 01 17:06:08 2013 +0100
@@ -37,11 +37,14 @@
 public class CullFrameStatesPhase extends Phase {
 
     private static final DebugMetric metricFrameStatesCulled = Debug.metric("FrameStatesCulled");
+    private static final DebugMetric metricNodesRemoved = Debug.metric("NodesRemoved");
     private static final DebugMetric metricMergesTraversed = Debug.metric("MergesTraversed");
 
     @Override
     protected void run(StructuredGraph graph) {
+        int initialNodes = graph.getNodeCount();
         new CullFrameStates(graph.start(), new State(null)).apply();
+        metricNodesRemoved.add(initialNodes - graph.getNodeCount());
     }
 
     public static class State implements MergeableState<State> {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java	Fri Mar 01 17:06:08 2013 +0100
@@ -29,271 +29,218 @@
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.graph.*;
+import com.oracle.graal.phases.graph.ReentrantNodeIterator.LoopInfo;
+import com.oracle.graal.phases.graph.ReentrantNodeIterator.NodeIteratorClosure;
 
 public class FloatingReadPhase extends Phase {
 
-    private IdentityHashMap<LoopBeginNode, List<MemoryMap>> loopEndStatesMap;
-
-    private static class LoopState {
-
-        public LoopBeginNode loopBegin;
-        public MemoryMap state;
-        public IdentityHashMap<PhiNode, Object> loopPhiLocations = new IdentityHashMap<>();
-        public ValueNode loopEntryAnyLocation;
-
-        public LoopState(LoopBeginNode loopBegin, MemoryMap state, ValueNode loopEntryAnyLocation) {
-            this.loopBegin = loopBegin;
-            this.state = state;
-            this.loopEntryAnyLocation = loopEntryAnyLocation;
-        }
-
-        @Override
-        public String toString() {
-            return "State@" + loopBegin;
-        }
-    }
-
-    private class MemoryMap implements MergeableState<MemoryMap> {
+    private static class MemoryMap {
 
         private IdentityHashMap<Object, ValueNode> lastMemorySnapshot;
-        private LinkedList<LoopState> loops;
 
         public MemoryMap(MemoryMap memoryMap) {
             lastMemorySnapshot = new IdentityHashMap<>(memoryMap.lastMemorySnapshot);
-            loops = new LinkedList<>(memoryMap.loops);
+        }
+
+        public MemoryMap(StartNode start) {
+            this();
+            lastMemorySnapshot.put(LocationNode.ANY_LOCATION, start);
         }
 
         public MemoryMap() {
             lastMemorySnapshot = new IdentityHashMap<>();
-            loops = new LinkedList<>();
+        }
+
+        private ValueNode getLastLocationAccess(Object locationIdentity) {
+            ValueNode lastLocationAccess;
+            if (locationIdentity == LocationNode.FINAL_LOCATION) {
+                return null;
+            } else {
+                lastLocationAccess = lastMemorySnapshot.get(locationIdentity);
+                if (lastLocationAccess == null) {
+                    lastLocationAccess = lastMemorySnapshot.get(LocationNode.ANY_LOCATION);
+                    assert lastLocationAccess != null;
+                }
+                return lastLocationAccess;
+            }
         }
 
         @Override
         public String toString() {
-            return "Map=" + lastMemorySnapshot.toString() + " Loops=" + loops.toString();
-        }
-
-        @SuppressWarnings("unchecked")
-        @Override
-        public boolean merge(MergeNode merge, List<MemoryMap> withStates) {
-            if (withStates.size() == 0) {
-                return true;
-            }
-
-            int minLoops = loops.size();
-            for (MemoryMap other : withStates) {
-                int otherLoops = other.loops.size();
-                if (otherLoops < minLoops) {
-                    minLoops = otherLoops;
-                }
-            }
-            while (loops.size() > minLoops) {
-                loops.pop();
-            }
-            for (MemoryMap other : withStates) {
-                while (other.loops.size() > minLoops) {
-                    other.loops.pop();
-                }
-            }
-
-            Set<Object> keys = new HashSet<>();
-            for (Object key : lastMemorySnapshot.keySet()) {
-                keys.add(key);
-            }
-            for (MemoryMap other : withStates) {
-                assert other.loops.size() == loops.size();
-                assert other.loops.size() < 1 || other.loops.peek().loopBegin == loops.peek().loopBegin;
-                for (Object key : other.lastMemorySnapshot.keySet()) {
-                    keys.add(key);
-                }
-            }
-            IdentityHashMap<Object, ValueNode> newMemorySnapshot = (IdentityHashMap<Object, ValueNode>) lastMemorySnapshot.clone();
-
-            for (Object key : keys) {
-                ValueNode merged = lastMemorySnapshot.get(key);
-                if (merged == null) {
-                    merged = lastMemorySnapshot.get(LocationNode.ANY_LOCATION);
-                }
-                int mergedStatesCount = 1;
-                boolean isPhi = false;
-                for (MemoryMap other : withStates) {
-                    ValueNode otherValue = other.lastMemorySnapshot.get(key);
-                    if (otherValue == null) {
-                        otherValue = other.lastMemorySnapshot.get(LocationNode.ANY_LOCATION);
-                    }
-                    if (isPhi) {
-                        ((PhiNode) merged).addInput(otherValue);
-                    } else if (merged != otherValue) {
-                        PhiNode phi = merge.graph().add(new PhiNode(PhiType.Memory, merge));
-                        for (int j = 0; j < mergedStatesCount; j++) {
-                            phi.addInput(merged);
-                        }
-                        phi.addInput(otherValue);
-                        merged = phi;
-                        isPhi = true;
-                        newMemorySnapshot.put(key, phi);
-                    }
-                    mergedStatesCount++;
-                }
-            }
-
-            lastMemorySnapshot = newMemorySnapshot;
-            return true;
-        }
-
-        @Override
-        public void loopBegin(LoopBeginNode loopBegin) {
-            LoopState loopState = new LoopState(loopBegin, this, lastMemorySnapshot.get(LocationNode.ANY_LOCATION));
-            for (Map.Entry<Object, ValueNode> entry : lastMemorySnapshot.entrySet()) {
-                PhiNode phi = loopBegin.graph().add(new PhiNode(PhiType.Memory, loopBegin));
-                phi.addInput(entry.getValue());
-                entry.setValue(phi);
-                loopState.loopPhiLocations.put(phi, entry.getKey());
-            }
-            loops.push(loopState);
-        }
-
-        @Override
-        public void loopEnds(LoopBeginNode loopBegin, List<MemoryMap> loopEndStates) {
-            loopEndStatesMap.put(loopBegin, loopEndStates);
-            tryFinishLoopPhis(this, loopBegin);
-        }
-
-        @Override
-        public void afterSplit(BeginNode node) {
-            // nothing
-        }
-
-        @Override
-        public MemoryMap clone() {
-            return new MemoryMap(this);
+            return "Map=" + lastMemorySnapshot.toString();
         }
     }
 
+    private final Map<LoopBeginNode, Set<Object>> modifiedInLoops = new IdentityHashMap<>();
+
     @Override
     protected void run(StructuredGraph graph) {
-        loopEndStatesMap = new IdentityHashMap<>();
-        new PostOrderNodeIterator<MemoryMap>(graph.start(), new MemoryMap()) {
-
-            @Override
-            protected void node(FixedNode node) {
-                processNode(node, state);
-            }
-        }.apply();
-    }
-
-    private void processNode(FixedNode node, MemoryMap state) {
-        if (node instanceof ReadNode) {
-            processRead((ReadNode) node, state);
-        } else if (node instanceof WriteNode) {
-            processWrite((WriteNode) node, state);
-        } else if (node instanceof MemoryCheckpoint) {
-            processCheckpoint((MemoryCheckpoint) node, state);
-        } else if (node instanceof LoopExitNode) {
-            processLoopExit((LoopExitNode) node, state);
-        }
-    }
-
-    private static void processCheckpoint(MemoryCheckpoint checkpoint, MemoryMap state) {
-        processAnyLocationWrite((ValueNode) checkpoint, state);
+        ReentrantNodeIterator.apply(new CollectMemoryCheckpointsClosure(), graph.start(), new HashSet<>(), null);
+        ReentrantNodeIterator.apply(new FloatingReadClosure(), graph.start(), new MemoryMap(graph.start()), null);
     }
 
-    private static void processWrite(WriteNode writeNode, MemoryMap state) {
-        if (writeNode.location().locationIdentity() == LocationNode.ANY_LOCATION) {
-            processAnyLocationWrite(writeNode, state);
+    private class CollectMemoryCheckpointsClosure extends NodeIteratorClosure<Set<Object>> {
+
+        @Override
+        protected void processNode(FixedNode node, Set<Object> currentState) {
+            if (node instanceof MemoryCheckpoint) {
+                currentState.add(((MemoryCheckpoint) node).getLocationIdentity());
+            }
         }
-        state.lastMemorySnapshot.put(writeNode.location().locationIdentity(), writeNode);
-    }
 
-    private static void processAnyLocationWrite(ValueNode modifiying, MemoryMap state) {
-        for (Map.Entry<Object, ValueNode> entry : state.lastMemorySnapshot.entrySet()) {
-            entry.setValue(modifiying);
+        @Override
+        protected Set<Object> merge(MergeNode merge, List<Set<Object>> states) {
+            Set<Object> result = new HashSet<>();
+            for (Set<Object> other : states) {
+                result.addAll(other);
+            }
+            return result;
         }
-        state.lastMemorySnapshot.put(LocationNode.ANY_LOCATION, modifiying);
-        state.loops.clear();
-    }
 
-    private void processRead(ReadNode readNode, MemoryMap state) {
-        StructuredGraph graph = (StructuredGraph) readNode.graph();
-        assert readNode.getNullCheck() == false;
-        Object locationIdentity = readNode.location().locationIdentity();
-        ValueNode lastLocationAccess = getLastLocationAccessForRead(state, locationIdentity);
-        FloatingReadNode floatingRead = graph.unique(new FloatingReadNode(readNode.object(), readNode.location(), lastLocationAccess, readNode.stamp(), readNode.dependencies()));
-        floatingRead.setNullCheck(readNode.getNullCheck());
-        ValueAnchorNode anchor = null;
-        for (GuardNode guard : readNode.dependencies().filter(GuardNode.class)) {
-            if (anchor == null) {
-                anchor = graph.add(new ValueAnchorNode());
+        @Override
+        protected Set<Object> afterSplit(BeginNode node, Set<Object> oldState) {
+            return new HashSet<>(oldState);
+        }
+
+        @Override
+        protected Map<LoopExitNode, Set<Object>> processLoop(LoopBeginNode loop, Set<Object> initialState) {
+            LoopInfo<Set<Object>> loopInfo = ReentrantNodeIterator.processLoop(this, loop, new HashSet<>());
+            Set<Object> modifiedLocations = new HashSet<>();
+            for (Set<Object> end : loopInfo.endStates.values()) {
+                modifiedLocations.addAll(end);
             }
-            anchor.addAnchoredNode(guard);
+            for (Set<Object> exit : loopInfo.exitStates.values()) {
+                exit.addAll(modifiedLocations);
+                exit.addAll(initialState);
+            }
+            assert !modifiedLocations.contains(LocationNode.FINAL_LOCATION);
+            modifiedInLoops.put(loop, modifiedLocations);
+            return loopInfo.exitStates;
         }
-        if (anchor != null) {
-            graph.addAfterFixed(readNode, anchor);
-        }
-        graph.replaceFixedWithFloating(readNode, floatingRead);
+
     }
 
-    private ValueNode getLastLocationAccessForRead(MemoryMap state, Object locationIdentity) {
-        ValueNode lastLocationAccess;
-        if (locationIdentity == LocationNode.FINAL_LOCATION) {
-            lastLocationAccess = null;
-        } else {
-            lastLocationAccess = state.lastMemorySnapshot.get(locationIdentity);
-            if (lastLocationAccess == null) {
-                LoopState lastLoop = state.loops.peek();
-                if (lastLoop == null) {
-                    lastLocationAccess = state.lastMemorySnapshot.get(LocationNode.ANY_LOCATION);
-                } else {
-                    ValueNode phiInit;
-                    if (state.loops.size() > 1) {
-                        phiInit = getLastLocationAccessForRead(state.loops.get(1).state, locationIdentity);
-                    } else {
-                        phiInit = lastLoop.loopEntryAnyLocation;
+    private class FloatingReadClosure extends NodeIteratorClosure<MemoryMap> {
+
+        @Override
+        protected void processNode(FixedNode node, MemoryMap state) {
+            if (node instanceof ReadNode) {
+                processRead((ReadNode) node, state);
+            } else if (node instanceof MemoryCheckpoint) {
+                processCheckpoint((MemoryCheckpoint) node, state);
+            }
+        }
+
+        private void processCheckpoint(MemoryCheckpoint checkpoint, MemoryMap state) {
+            if (checkpoint.getLocationIdentity() == LocationNode.ANY_LOCATION) {
+                state.lastMemorySnapshot.clear();
+            }
+            state.lastMemorySnapshot.put(checkpoint.getLocationIdentity(), (ValueNode) checkpoint);
+        }
+
+        private void processRead(ReadNode readNode, MemoryMap state) {
+            StructuredGraph graph = (StructuredGraph) readNode.graph();
+            assert readNode.getNullCheck() == false;
+            Object locationIdentity = readNode.location().locationIdentity();
+            if (locationIdentity != LocationNode.UNKNOWN_LOCATION) {
+                ValueNode lastLocationAccess = state.getLastLocationAccess(locationIdentity);
+                FloatingReadNode floatingRead = graph.unique(new FloatingReadNode(readNode.object(), readNode.location(), lastLocationAccess, readNode.stamp(), readNode.dependencies()));
+                floatingRead.setNullCheck(readNode.getNullCheck());
+                ValueAnchorNode anchor = null;
+                for (GuardNode guard : readNode.dependencies().filter(GuardNode.class)) {
+                    if (anchor == null) {
+                        anchor = graph.add(new ValueAnchorNode());
+                        graph.addAfterFixed(readNode, anchor);
                     }
-                    PhiNode phi = lastLoop.loopBegin.graph().add(new PhiNode(PhiType.Memory, lastLoop.loopBegin));
-                    phi.addInput(phiInit);
-                    lastLoop.state.lastMemorySnapshot.put(locationIdentity, phi);
-                    lastLoop.loopPhiLocations.put(phi, locationIdentity);
-                    tryFinishLoopPhis(lastLoop.state, lastLoop.loopBegin);
-                    lastLocationAccess = phi;
+                    anchor.addAnchoredNode(guard);
                 }
-                state.lastMemorySnapshot.put(locationIdentity, lastLocationAccess);
+                graph.replaceFixedWithFloating(readNode, floatingRead);
             }
         }
-        return lastLocationAccess;
-    }
+
+        @Override
+        protected MemoryMap merge(MergeNode merge, List<MemoryMap> states) {
+            MemoryMap newState = new MemoryMap();
 
-    private static void processLoopExit(LoopExitNode exit, MemoryMap state) {
-        for (Map.Entry<Object, ValueNode> entry : state.lastMemorySnapshot.entrySet()) {
-            entry.setValue(exit.graph().unique(new ValueProxyNode(entry.getValue(), exit, PhiType.Memory)));
-        }
-        if (!state.loops.isEmpty()) {
-            state.loops.pop();
-        }
-    }
+            Set<Object> keys = new HashSet<>();
+            for (MemoryMap other : states) {
+                keys.addAll(other.lastMemorySnapshot.keySet());
+            }
+            assert !keys.contains(LocationNode.FINAL_LOCATION);
 
-    private void tryFinishLoopPhis(MemoryMap loopMemory, LoopBeginNode loopBegin) {
-        List<MemoryMap> loopEndStates = loopEndStatesMap.get(loopBegin);
-        if (loopEndStates == null) {
-            return;
-        }
-        LoopState loopState = loopMemory.loops.get(0);
-        int i = 0;
-        while (loopState.loopBegin != loopBegin) {
-            loopState = loopMemory.loops.get(++i);
+            for (Object key : keys) {
+                int mergedStatesCount = 0;
+                boolean isPhi = false;
+                ValueNode merged = null;
+                for (MemoryMap state : states) {
+                    ValueNode last = state.getLastLocationAccess(key);
+                    if (isPhi) {
+                        ((PhiNode) merged).addInput(last);
+                    } else {
+                        if (merged == last) {
+                            // nothing to do
+                        } else if (merged == null) {
+                            merged = last;
+                        } else {
+                            PhiNode phi = merge.graph().add(new PhiNode(PhiType.Memory, merge));
+                            for (int j = 0; j < mergedStatesCount; j++) {
+                                phi.addInput(merged);
+                            }
+                            phi.addInput(last);
+                            merged = phi;
+                            isPhi = true;
+                        }
+                    }
+                    mergedStatesCount++;
+                }
+                newState.lastMemorySnapshot.put(key, merged);
+            }
+            return newState;
         }
-        for (PhiNode phi : loopBegin.phis()) {
-            if (phi.type() == PhiType.Memory && phi.valueCount() == 1) {
-                Object location = loopState.loopPhiLocations.get(phi);
-                assert location != null : "unknown location for " + phi;
-                for (MemoryMap endState : loopEndStates) {
-                    ValueNode otherNode = endState.lastMemorySnapshot.get(location);
-                    if (otherNode == null) {
-                        otherNode = endState.lastMemorySnapshot.get(LocationNode.ANY_LOCATION);
-                    }
-                    phi.addInput(otherNode);
+
+        @Override
+        protected MemoryMap afterSplit(BeginNode node, MemoryMap oldState) {
+            return new MemoryMap(oldState);
+        }
+
+        @Override
+        protected Map<LoopExitNode, MemoryMap> processLoop(LoopBeginNode loop, MemoryMap initialState) {
+            Set<Object> modifiedLocations = modifiedInLoops.get(loop);
+            if (modifiedLocations.contains(LocationNode.ANY_LOCATION)) {
+                // create phis for all locations if ANY is modified in the loop
+                modifiedLocations = new HashSet<>(modifiedLocations);
+                modifiedLocations.addAll(initialState.lastMemorySnapshot.keySet());
+            }
+
+            Map<Object, PhiNode> phis = new HashMap<>();
+            for (Object location : modifiedLocations) {
+                PhiNode phi = loop.graph().add(new PhiNode(PhiType.Memory, loop));
+                phi.addInput(initialState.getLastLocationAccess(location));
+                phis.put(location, phi);
+                initialState.lastMemorySnapshot.put(location, phi);
+            }
+
+            LoopInfo<MemoryMap> loopInfo = ReentrantNodeIterator.processLoop(this, loop, initialState);
+
+            for (Map.Entry<LoopEndNode, MemoryMap> entry : loopInfo.endStates.entrySet()) {
+                int endIndex = loop.phiPredecessorIndex(entry.getKey());
+                for (Map.Entry<Object, PhiNode> phiEntry : phis.entrySet()) {
+                    Object key = phiEntry.getKey();
+                    PhiNode phi = phiEntry.getValue();
+                    phi.initializeValueAt(endIndex, entry.getValue().getLastLocationAccess(key));
                 }
             }
+            for (Map.Entry<LoopExitNode, MemoryMap> entry : loopInfo.exitStates.entrySet()) {
+                LoopExitNode exit = entry.getKey();
+                MemoryMap state = entry.getValue();
+                for (Object location : modifiedLocations) {
+                    ValueNode lastAccessAtExit = state.lastMemorySnapshot.get(location);
+                    if (lastAccessAtExit != null) {
+                        state.lastMemorySnapshot.put(location, loop.graph().add(new ProxyNode(lastAccessAtExit, exit, PhiType.Memory)));
+                    }
+                }
+            }
+            return loopInfo.exitStates;
         }
     }
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java	Fri Mar 01 17:06:08 2013 +0100
@@ -24,6 +24,7 @@
 
 import java.lang.reflect.*;
 import java.util.*;
+import java.util.concurrent.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
@@ -127,26 +128,32 @@
                 return cachedGraph;
             }
         }
-        StructuredGraph newGraph = new StructuredGraph(method);
-        if (plan != null) {
-            plan.runPhases(PhasePosition.AFTER_PARSING, newGraph);
-        }
-        assert newGraph.start().next() != null : "graph needs to be populated during PhasePosition.AFTER_PARSING";
+        final StructuredGraph newGraph = new StructuredGraph(method);
+        return Debug.scope("InlineGraph", newGraph, new Callable<StructuredGraph>() {
+
+            @Override
+            public StructuredGraph call() throws Exception {
+                if (plan != null) {
+                    plan.runPhases(PhasePosition.AFTER_PARSING, newGraph);
+                }
+                assert newGraph.start().next() != null : "graph needs to be populated during PhasePosition.AFTER_PARSING";
 
-        if (GraalOptions.ProbabilityAnalysis) {
-            new DeadCodeEliminationPhase().apply(newGraph);
-            new ComputeProbabilityPhase().apply(newGraph);
-        }
-        if (GraalOptions.OptCanonicalizer) {
-            new CanonicalizerPhase(runtime, assumptions).apply(newGraph);
-        }
-        if (GraalOptions.CullFrameStates) {
-            new CullFrameStatesPhase().apply(newGraph);
-        }
-        if (GraalOptions.CacheGraphs && cache != null) {
-            cache.put(newGraph);
-        }
-        return newGraph;
+                if (GraalOptions.ProbabilityAnalysis) {
+                    new DeadCodeEliminationPhase().apply(newGraph);
+                    new ComputeProbabilityPhase().apply(newGraph);
+                }
+                if (GraalOptions.OptCanonicalizer) {
+                    new CanonicalizerPhase(runtime, assumptions).apply(newGraph);
+                }
+                if (GraalOptions.CullFrameStates) {
+                    new CullFrameStatesPhase().apply(newGraph);
+                }
+                if (GraalOptions.CacheGraphs && cache != null) {
+                    cache.put(newGraph);
+                }
+                return newGraph;
+            }
+        });
     }
 
     private interface InliningDecision {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Fri Mar 01 17:06:08 2013 +0100
@@ -1122,7 +1122,7 @@
                 } else {
                     // only handle the outermost frame states
                     if (frameState.outerFrameState() == null) {
-                        assert frameState.method() == inlineGraph.method();
+                        assert frameState.bci == FrameState.INVALID_FRAMESTATE_BCI || frameState.method() == inlineGraph.method();
                         if (outerFrameState == null) {
                             outerFrameState = stateAfter.duplicateModified(invoke.bci(), stateAfter.rethrowException(), invoke.node().kind());
                             outerFrameState.setDuringCall(true);
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ReadEliminationPhase.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ReadEliminationPhase.java	Fri Mar 01 17:06:08 2013 +0100
@@ -59,8 +59,8 @@
         if (visited.isMarked(lastLocationAccess)) {
             return true; // dataflow loops must come from Phis assume them ok until proven wrong
         }
-        if (lastLocationAccess instanceof ValueProxyNode) {
-            return isWrites(n, ((ValueProxyNode) lastLocationAccess).value(), visited);
+        if (lastLocationAccess instanceof ProxyNode) {
+            return isWrites(n, ((ProxyNode) lastLocationAccess).value(), visited);
         }
         if (lastLocationAccess instanceof WriteNode) {
             WriteNode other = (WriteNode) lastLocationAccess;
@@ -83,10 +83,10 @@
         if (exisiting != null) {
             return exisiting;
         }
-        if (lastLocationAccess instanceof ValueProxyNode) {
-            ValueProxyNode proxy = (ValueProxyNode) lastLocationAccess;
+        if (lastLocationAccess instanceof ProxyNode) {
+            ProxyNode proxy = (ProxyNode) lastLocationAccess;
             ValueNode value = getValue(n, proxy.value(), nodeMap);
-            return lastLocationAccess.graph().add(new ValueProxyNode(value, proxy.proxyPoint(), PhiType.Value));
+            return lastLocationAccess.graph().add(new ProxyNode(value, proxy.proxyPoint(), PhiType.Value));
         }
         if (lastLocationAccess instanceof WriteNode) {
             return ((WriteNode) lastLocationAccess).value();
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/RemoveValueProxyPhase.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/RemoveValueProxyPhase.java	Fri Mar 01 17:06:08 2013 +0100
@@ -23,14 +23,17 @@
 package com.oracle.graal.phases.common;
 
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.PhiNode.*;
 import com.oracle.graal.phases.*;
 
 public class RemoveValueProxyPhase extends Phase {
 
     @Override
     protected void run(StructuredGraph graph) {
-        for (ValueProxyNode vpn : graph.getNodes(ValueProxyNode.class)) {
-            graph.replaceFloating(vpn, vpn.value());
+        for (ProxyNode vpn : graph.getNodes(ProxyNode.class)) {
+            if (vpn.type() == PhiType.Value) {
+                graph.replaceFloating(vpn, vpn.value());
+            }
         }
         for (LoopExitNode exit : graph.getNodes(LoopExitNode.class)) {
             FrameState stateAfter = exit.stateAfter();
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Fri Mar 01 17:06:08 2013 +0100
@@ -150,7 +150,7 @@
     public static boolean ExitVMOnException                  = true;
 
     // Code generator settings
-    public static boolean CheckCastElimination               = true;
+    public static boolean ConditionalElimination             = true;
     public static boolean CullFrameStates                    = ____;
     public static boolean UseProfilingInformation            = true;
            static boolean RemoveNeverExecutedCode            = true;
@@ -168,6 +168,8 @@
     public static boolean CanOmitFrame                       = true;
     public static int     SafepointPollOffset                = 256;
 
+    public static boolean MemoryAwareScheduling              = true;
+
     // Translating tableswitch instructions
     public static int     MinimumJumpTableSize               = 5;
     public static int     RangeTestsSwitchDensity            = 5;
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantBlockIterator.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantBlockIterator.java	Fri Mar 01 17:06:08 2013 +0100
@@ -29,54 +29,49 @@
 
 public final class ReentrantBlockIterator {
 
-    public abstract static class MergeableBlockState<T> {
+    public static class LoopInfo<StateT> {
 
-        public abstract T cloneState();
+        public final List<StateT> endStates = new ArrayList<>();
+        public final List<StateT> exitStates = new ArrayList<>();
     }
 
-    public static class LoopInfo<T extends MergeableBlockState<T>> {
+    public abstract static class BlockIteratorClosure<StateT> {
 
-        public final List<T> endStates = new ArrayList<>();
-        public final List<T> exitStates = new ArrayList<>();
-    }
-
-    public abstract static class BlockIteratorClosure<T extends MergeableBlockState<T>> {
+        protected abstract void processBlock(Block block, StateT currentState);
 
-        protected abstract void processBlock(Block block, T currentState);
-
-        protected abstract T merge(MergeNode merge, List<T> states);
+        protected abstract StateT merge(MergeNode merge, List<StateT> states);
 
-        protected abstract T afterSplit(FixedNode node, T oldState);
+        protected abstract StateT afterSplit(FixedNode node, StateT oldState);
 
-        protected abstract List<T> processLoop(Loop loop, T initialState);
+        protected abstract List<StateT> processLoop(Loop loop, StateT initialState);
     }
 
     private ReentrantBlockIterator() {
         // no instances allowed
     }
 
-    public static <T extends MergeableBlockState<T>> LoopInfo<T> processLoop(BlockIteratorClosure<T> closure, Loop loop, T initialState) {
-        IdentityHashMap<FixedNode, T> blockEndStates = apply(closure, loop.header, initialState, new HashSet<>(loop.blocks));
+    public static <StateT> LoopInfo<StateT> processLoop(BlockIteratorClosure<StateT> closure, Loop loop, StateT initialState) {
+        IdentityHashMap<FixedNode, StateT> blockEndStates = apply(closure, loop.header, initialState, new HashSet<>(loop.blocks));
 
-        LoopInfo<T> info = new LoopInfo<>();
+        LoopInfo<StateT> info = new LoopInfo<>();
         List<Block> predecessors = loop.header.getPredecessors();
         for (int i = 1; i < predecessors.size(); i++) {
             info.endStates.add(blockEndStates.get(predecessors.get(i).getEndNode()));
         }
         for (Block loopExit : loop.exits) {
             assert loopExit.getPredecessorCount() == 1;
-            T exitState = blockEndStates.get(loopExit.getFirstPredecessor().getEndNode());
+            StateT exitState = blockEndStates.get(loopExit.getFirstPredecessor().getEndNode());
             assert exitState != null;
             info.exitStates.add(exitState);
         }
         return info;
     }
 
-    public static <T extends MergeableBlockState<T>> IdentityHashMap<FixedNode, T> apply(BlockIteratorClosure<T> closure, Block start, T initialState, Set<Block> boundary) {
+    public static <StateT> IdentityHashMap<FixedNode, StateT> apply(BlockIteratorClosure<StateT> closure, Block start, StateT initialState, Set<Block> boundary) {
         Deque<Block> blockQueue = new ArrayDeque<>();
-        IdentityHashMap<FixedNode, T> blockEndStates = new IdentityHashMap<>();
+        IdentityHashMap<FixedNode, StateT> blockEndStates = new IdentityHashMap<>();
 
-        T state = initialState;
+        StateT state = initialState;
         Block current = start;
 
         do {
@@ -98,7 +93,7 @@
                             LoopBeginNode loopBegin = loop.loopBegin();
                             assert successor.getBeginNode() == loopBegin;
 
-                            List<T> exitStates = closure.processLoop(loop, state);
+                            List<StateT> exitStates = closure.processLoop(loop, state);
 
                             int i = 0;
                             assert loop.exits.size() == exitStates.size();
@@ -123,8 +118,8 @@
                                 blockEndStates.put(end, state);
                                 MergeNode merge = end.merge();
                                 boolean endsVisited = true;
-                                for (int i = 0; i < merge.forwardEndCount(); i++) {
-                                    if (!blockEndStates.containsKey(merge.forwardEndAt(i))) {
+                                for (EndNode forwardEnd : merge.forwardEnds()) {
+                                    if (!blockEndStates.containsKey(forwardEnd)) {
                                         endsVisited = false;
                                         break;
                                     }
@@ -157,9 +152,9 @@
                     current = blockQueue.removeFirst();
                     if (current.getPredecessors().size() > 1) {
                         MergeNode merge = (MergeNode) current.getBeginNode();
-                        ArrayList<T> states = new ArrayList<>(merge.forwardEndCount());
+                        ArrayList<StateT> states = new ArrayList<>(merge.forwardEndCount());
                         for (int i = 0; i < merge.forwardEndCount(); i++) {
-                            T other = blockEndStates.get(merge.forwardEndAt(i));
+                            StateT other = blockEndStates.get(merge.forwardEndAt(i));
                             assert other != null;
                             states.add(other);
                         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantNodeIterator.java	Fri Mar 01 17:06:08 2013 +0100
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.graph;
+
+import java.util.*;
+
+import com.oracle.graal.graph.NodeClass.NodeClassIterator;
+import com.oracle.graal.nodes.*;
+
+public final class ReentrantNodeIterator {
+
+    public static class LoopInfo<StateT> {
+
+        public final Map<LoopEndNode, StateT> endStates = new IdentityHashMap<>(4);
+        public final Map<LoopExitNode, StateT> exitStates = new IdentityHashMap<>(2);
+    }
+
+    public abstract static class NodeIteratorClosure<StateT> {
+
+        protected abstract void processNode(FixedNode node, StateT currentState);
+
+        protected abstract StateT merge(MergeNode merge, List<StateT> states);
+
+        protected abstract StateT afterSplit(BeginNode node, StateT oldState);
+
+        protected abstract Map<LoopExitNode, StateT> processLoop(LoopBeginNode loop, StateT initialState);
+    }
+
+    private ReentrantNodeIterator() {
+        // no instances allowed
+    }
+
+    public static <StateT> LoopInfo<StateT> processLoop(NodeIteratorClosure<StateT> closure, LoopBeginNode loop, StateT initialState) {
+        HashSet<FixedNode> boundary = new HashSet<>();
+        for (LoopExitNode exit : loop.loopExits()) {
+            boundary.add(exit);
+        }
+        Map<FixedNode, StateT> blockEndStates = apply(closure, loop, initialState, boundary);
+
+        LoopInfo<StateT> info = new LoopInfo<>();
+        for (LoopEndNode end : loop.loopEnds()) {
+            assert blockEndStates.containsKey(end) : "no end state for " + end;
+            info.endStates.put(end, blockEndStates.get(end));
+        }
+        for (LoopExitNode exit : loop.loopExits()) {
+            assert blockEndStates.containsKey(exit) : "no exit state for " + exit;
+            info.exitStates.put(exit, blockEndStates.get(exit));
+        }
+        return info;
+    }
+
+    public static <StateT> Map<FixedNode, StateT> apply(NodeIteratorClosure<StateT> closure, FixedNode start, StateT initialState, Set<FixedNode> boundary) {
+        Deque<BeginNode> nodeQueue = new ArrayDeque<>();
+        IdentityHashMap<FixedNode, StateT> blockEndStates = new IdentityHashMap<>();
+
+        StateT state = initialState;
+        FixedNode current = start;
+        do {
+            while (current instanceof FixedWithNextNode) {
+                if (boundary != null && boundary.contains(current)) {
+                    blockEndStates.put(current, state);
+                    current = null;
+                } else {
+                    FixedNode next = ((FixedWithNextNode) current).next();
+                    closure.processNode(current, state);
+                    current = next;
+                }
+            }
+
+            if (current != null) {
+                closure.processNode(current, state);
+
+                NodeClassIterator successors = current.successors().iterator();
+                if (!successors.hasNext()) {
+                    if (current instanceof LoopEndNode) {
+                        blockEndStates.put(current, state);
+                    } else if (current instanceof EndNode) {
+                        // add the end node and see if the merge is ready for processing
+                        MergeNode merge = ((EndNode) current).merge();
+                        if (merge instanceof LoopBeginNode) {
+                            Map<LoopExitNode, StateT> loopExitState = closure.processLoop((LoopBeginNode) merge, state);
+                            for (Map.Entry<LoopExitNode, StateT> entry : loopExitState.entrySet()) {
+                                blockEndStates.put(entry.getKey(), entry.getValue());
+                                nodeQueue.add(entry.getKey());
+                            }
+                        } else {
+                            assert !blockEndStates.containsKey(current);
+                            blockEndStates.put(current, state);
+                            boolean endsVisited = true;
+                            for (EndNode forwardEnd : merge.forwardEnds()) {
+                                if (!blockEndStates.containsKey(forwardEnd)) {
+                                    endsVisited = false;
+                                    break;
+                                }
+                            }
+                            if (endsVisited) {
+                                ArrayList<StateT> states = new ArrayList<>(merge.forwardEndCount());
+                                for (int i = 0; i < merge.forwardEndCount(); i++) {
+                                    EndNode forwardEnd = merge.forwardEndAt(i);
+                                    assert blockEndStates.containsKey(forwardEnd);
+                                    StateT other = blockEndStates.get(forwardEnd);
+                                    states.add(other);
+                                }
+                                state = closure.merge(merge, states);
+                                current = merge;
+                                continue;
+                            }
+                        }
+                    }
+                } else {
+                    FixedNode firstSuccessor = (FixedNode) successors.next();
+                    if (!successors.hasNext()) {
+                        current = firstSuccessor;
+                        continue;
+                    } else {
+                        while (successors.hasNext()) {
+                            BeginNode successor = (BeginNode) successors.next();
+                            blockEndStates.put(successor, closure.afterSplit(successor, state));
+                            nodeQueue.add(successor);
+                        }
+                        state = closure.afterSplit((BeginNode) firstSuccessor, state);
+                        current = firstSuccessor;
+                        continue;
+                    }
+                }
+            }
+
+            // get next queued block
+            if (nodeQueue.isEmpty()) {
+                return blockEndStates;
+            } else {
+                current = nodeQueue.removeFirst();
+                state = blockEndStates.get(current);
+                assert !(current instanceof MergeNode) && current instanceof BeginNode;
+            }
+        } while (true);
+    }
+}
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Fri Mar 01 17:06:08 2013 +0100
@@ -28,12 +28,102 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Node.Verbosity;
 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.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;
 
-public class SchedulePhase extends Phase {
+public final class SchedulePhase extends Phase {
+
+    public static enum SchedulingStrategy {
+        EARLIEST, LATEST, LATEST_OUT_OF_LOOPS
+    }
+
+    /**
+     * This closure iterates over all nodes of a scheduled graph (it expects a
+     * {@link SchedulingStrategy#EARLIEST} schedule) and keeps a list of "actuve" reads. Whenever it
+     * encounters a read, it adds it to the active reads. Whenever it encounters a memory
+     * checkpoint, it adds all reads that need to be committed before this checkpoint to the
+     * "phantom" usages and inputs, so that the read is scheduled before the checkpoint afterwards.
+     * 
+     * At merges, the intersection of all sets of active reads is calculated. A read that was
+     * committed within one predecessor branch cannot be scheduled after the merge anyway.
+     * 
+     * Similarly for loops, all reads that are killed somewhere within the loop are removed from the
+     * exits' active reads, since they cannot be scheduled after the exit anyway.
+     */
+    private class MemoryScheduleClosure extends BlockIteratorClosure<HashSet<FloatingReadNode>> {
+
+        @Override
+        protected void processBlock(Block block, HashSet<FloatingReadNode> currentState) {
+            for (Node node : getBlockToNodesMap().get(block)) {
+                if (node instanceof FloatingReadNode) {
+                    currentState.add((FloatingReadNode) node);
+                } else if (node instanceof MemoryCheckpoint) {
+                    Object identity = ((MemoryCheckpoint) node).getLocationIdentity();
+                    for (Iterator<FloatingReadNode> iter = currentState.iterator(); iter.hasNext();) {
+                        FloatingReadNode read = iter.next();
+                        FixedNode fixed = (FixedNode) node;
+                        if (identity == LocationNode.ANY_LOCATION || read.location().locationIdentity() == identity) {
+                            addPhantomReference(read, fixed);
+                        }
+                    }
+                }
+            }
+        }
+
+        public void addPhantomReference(FloatingReadNode read, FixedNode fixed) {
+            List<FixedNode> usageList = phantomUsages.get(read);
+            if (usageList == null) {
+                phantomUsages.put(read, usageList = new ArrayList<>());
+            }
+            usageList.add(fixed);
+            List<FloatingNode> inputList = phantomInputs.get(fixed);
+            if (inputList == null) {
+                phantomInputs.put(fixed, inputList = new ArrayList<>());
+            }
+            inputList.add(read);
+        }
+
+        @Override
+        protected HashSet<FloatingReadNode> merge(MergeNode merge, List<HashSet<FloatingReadNode>> states) {
+            HashSet<FloatingReadNode> state = new HashSet<>(states.get(0));
+            for (int i = 1; i < states.size(); i++) {
+                state.retainAll(states.get(i));
+            }
+            return state;
+        }
+
+        @Override
+        protected HashSet<FloatingReadNode> afterSplit(FixedNode node, HashSet<FloatingReadNode> oldState) {
+            return new HashSet<>(oldState);
+        }
+
+        @Override
+        protected List<HashSet<FloatingReadNode>> processLoop(Loop loop, HashSet<FloatingReadNode> state) {
+            LoopInfo<HashSet<FloatingReadNode>> info = ReentrantBlockIterator.processLoop(this, loop, new HashSet<>(state));
+
+            List<HashSet<FloatingReadNode>> loopEndStates = info.endStates;
+
+            // collect all reads that were killed in some branch within the loop
+            Set<FloatingReadNode> killedReads = new HashSet<>(state);
+            Set<FloatingReadNode> survivingReads = new HashSet<>(loopEndStates.get(0));
+            for (int i = 1; i < loopEndStates.size(); i++) {
+                survivingReads.retainAll(loopEndStates.get(i));
+            }
+            killedReads.removeAll(survivingReads);
+
+            // reads that were killed within the loop cannot be scheduled after the loop anyway
+            for (HashSet<FloatingReadNode> exitState : info.exitStates) {
+                exitState.removeAll(killedReads);
+            }
+            return info.exitStates;
+        }
+    }
 
     private ControlFlowGraph cfg;
     private NodeMap<Block> earliestCache;
@@ -42,6 +132,8 @@
      * Map from blocks to the nodes in each block.
      */
     private BlockMap<List<ScheduledNode>> blockToNodesMap;
+    private final Map<FloatingNode, List<FixedNode>> phantomUsages = new IdentityHashMap<>();
+    private final Map<FixedNode, List<FloatingNode>> phantomInputs = new IdentityHashMap<>();
 
     public SchedulePhase() {
         super("Schedule");
@@ -49,12 +141,26 @@
 
     @Override
     protected void run(StructuredGraph graph) {
+        SchedulingStrategy strategy = GraalOptions.OptScheduleOutOfLoops ? SchedulingStrategy.LATEST_OUT_OF_LOOPS : SchedulingStrategy.LATEST;
+
         cfg = ControlFlowGraph.compute(graph, true, true, true, false);
         earliestCache = graph.createNodeMap();
         blockToNodesMap = new BlockMap<>(cfg);
 
-        assignBlockToNodes(graph);
-        sortNodesWithinBlocks(graph);
+        if (GraalOptions.MemoryAwareScheduling && graph.getNodes(FloatingReadNode.class).isNotEmpty()) {
+
+            assignBlockToNodes(graph, SchedulingStrategy.EARLIEST);
+            sortNodesWithinBlocks(graph, SchedulingStrategy.EARLIEST);
+
+            MemoryScheduleClosure closure = new MemoryScheduleClosure();
+            ReentrantBlockIterator.apply(closure, getCFG().getStartBlock(), new HashSet<FloatingReadNode>(), null);
+
+            cfg.clearNodeToBlock();
+            blockToNodesMap = new BlockMap<>(cfg);
+        }
+
+        assignBlockToNodes(graph, strategy);
+        sortNodesWithinBlocks(graph, strategy);
     }
 
     /**
@@ -94,7 +200,7 @@
         return blockToNodesMap.get(block);
     }
 
-    private void assignBlockToNodes(StructuredGraph graph) {
+    private void assignBlockToNodes(StructuredGraph graph, SchedulingStrategy strategy) {
         for (Block block : cfg.getBlocks()) {
             List<ScheduledNode> nodes = new ArrayList<>();
             assert blockToNodesMap.get(block) == null;
@@ -106,7 +212,7 @@
 
         for (Node n : graph.getNodes()) {
             if (n instanceof ScheduledNode) {
-                assignBlockToNode((ScheduledNode) n);
+                assignBlockToNode((ScheduledNode) n, strategy);
             }
         }
     }
@@ -115,7 +221,7 @@
      * Assigns a block to the given node. This method expects that PhiNodes and FixedNodes are
      * already assigned to a block.
      */
-    private void assignBlockToNode(ScheduledNode node) {
+    private void assignBlockToNode(ScheduledNode node, SchedulingStrategy strategy) {
         assert !node.isDeleted();
 
         Block prevBlock = cfg.getNodeToBlock().get(node);
@@ -126,17 +232,26 @@
         // ControlFlowGraph.identifyBlocks
         assert !(node instanceof PhiNode) : node;
         assert !(node instanceof FixedNode) : node;
-        // if in CFG, schedule at the latest position possible in the outermost loop possible
-        Block latestBlock = latestBlock(node);
+
         Block block;
-        if (latestBlock == null) {
-            block = earliestBlock(node);
-        } else if (GraalOptions.OptScheduleOutOfLoops && !(node instanceof VirtualObjectNode)) {
-            Block earliestBlock = earliestBlock(node);
-            block = scheduleOutOfLoops(node, latestBlock, earliestBlock);
-            assert earliestBlock.dominates(block) : "Graph can not be scheduled : inconsistent for " + node + " (" + earliestBlock + " needs to dominate " + block + ")";
-        } else {
-            block = latestBlock;
+        switch (strategy) {
+            case EARLIEST:
+                block = earliestBlock(node);
+                break;
+            case LATEST:
+            case LATEST_OUT_OF_LOOPS:
+                block = latestBlock(node, strategy);
+                if (block == null) {
+                    block = earliestBlock(node);
+                } else if (strategy == SchedulingStrategy.LATEST_OUT_OF_LOOPS && !(node instanceof VirtualObjectNode)) {
+                    // schedule at the latest position possible in the outermost loop possible
+                    Block earliestBlock = earliestBlock(node);
+                    block = scheduleOutOfLoops(node, block, earliestBlock);
+                    assert earliestBlock.dominates(block) : "Graph can not be scheduled : inconsistent for " + node + " (" + earliestBlock + " needs to dominate " + block + ")";
+                }
+                break;
+            default:
+                throw new GraalInternalError("unknown scheduling strategy");
         }
         cfg.getNodeToBlock().set(node, block);
         blockToNodesMap.get(block).add(node);
@@ -145,17 +260,27 @@
     /**
      * 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
      */
-    private Block latestBlock(ScheduledNode node) {
+    private Block latestBlock(ScheduledNode node, SchedulingStrategy strategy) {
         CommonDominatorBlockClosure cdbc = new CommonDominatorBlockClosure(null);
         for (Node succ : node.successors().nonNull()) {
             assert cfg.getNodeToBlock().get(succ) != null;
             cdbc.apply(cfg.getNodeToBlock().get(succ));
         }
-        ensureScheduledUsages(node);
+        ensureScheduledUsages(node, strategy);
         for (Node usage : node.usages()) {
-            blocksForUsage(node, usage, cdbc);
+            blocksForUsage(node, usage, cdbc, strategy);
         }
+        List<FixedNode> usages = phantomUsages.get(node);
+        if (usages != null) {
+            for (FixedNode usage : usages) {
+                assert cfg.getNodeToBlock().get(usage) != null;
+                cdbc.apply(cfg.getNodeToBlock().get(usage));
+            }
+        }
+
         return cdbc.block;
     }
 
@@ -204,7 +329,12 @@
         assert node.predecessor() == null;
         for (Node input : node.inputs().nonNull()) {
             assert input instanceof ValueNode;
-            Block inputEarliest = earliestBlock(input);
+            Block inputEarliest;
+            if (input instanceof InvokeWithExceptionNode) {
+                inputEarliest = cfg.getNodeToBlock().get(((InvokeWithExceptionNode) input).next());
+            } else {
+                inputEarliest = earliestBlock(input);
+            }
             if (!dominators.get(inputEarliest.getId())) {
                 earliest = inputEarliest;
                 do {
@@ -242,7 +372,7 @@
      * @param usage the usage whose blocks need to be considered
      * @param closure the closure that will be called for each block
      */
-    private void blocksForUsage(ScheduledNode node, Node usage, BlockClosure closure) {
+    private void blocksForUsage(ScheduledNode node, Node usage, BlockClosure closure, SchedulingStrategy strategy) {
         assert !(node instanceof PhiNode);
 
         if (usage instanceof PhiNode) {
@@ -274,7 +404,7 @@
                 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.
-                    blocksForUsage(node, unscheduledUsage, closure);
+                    blocksForUsage(node, unscheduledUsage, closure, strategy);
                 } else if (unscheduledUsage instanceof MergeNode) {
                     // Only FrameStates can be connected to MergeNodes.
                     assert usage instanceof FrameState;
@@ -288,20 +418,20 @@
                     assert usage instanceof FrameState;
                     assert unscheduledUsage instanceof StateSplit;
                     // Otherwise: Put the input into the same block as the usage.
-                    assignBlockToNode((ScheduledNode) unscheduledUsage);
+                    assignBlockToNode((ScheduledNode) unscheduledUsage, strategy);
                     closure.apply(cfg.getNodeToBlock().get(unscheduledUsage));
                 }
             }
         } else {
             // All other types of usages: Put the input into the same block as the usage.
-            assignBlockToNode((ScheduledNode) usage);
+            assignBlockToNode((ScheduledNode) usage, strategy);
             closure.apply(cfg.getNodeToBlock().get(usage));
         }
     }
 
-    private void ensureScheduledUsages(Node node) {
+    private void ensureScheduledUsages(Node node, SchedulingStrategy strategy) {
         for (Node usage : node.usages().filter(ScheduledNode.class)) {
-            assignBlockToNode((ScheduledNode) usage);
+            assignBlockToNode((ScheduledNode) usage, strategy);
         }
         // now true usages are ready
     }
@@ -316,27 +446,43 @@
         return ControlFlowGraph.commonDominator(a, b);
     }
 
-    private void sortNodesWithinBlocks(StructuredGraph graph) {
+    private void sortNodesWithinBlocks(StructuredGraph graph, SchedulingStrategy strategy) {
         NodeBitMap visited = graph.createNodeBitMap();
         for (Block b : cfg.getBlocks()) {
-            sortNodesWithinBlock(b, visited);
+            sortNodesWithinBlock(b, visited, strategy);
         }
     }
 
+    private void sortNodesWithinBlock(Block b, NodeBitMap visited, SchedulingStrategy strategy) {
+        assert !visited.isMarked(b.getBeginNode()) && cfg.blockFor(b.getBeginNode()) == b;
+        assert !visited.isMarked(b.getEndNode()) && cfg.blockFor(b.getEndNode()) == b;
+
+        List<ScheduledNode> sortedInstructions;
+        switch (strategy) {
+            case EARLIEST:
+                sortedInstructions = sortNodesWithinBlockEarliest(b, visited);
+                break;
+            case LATEST:
+            case LATEST_OUT_OF_LOOPS:
+                sortedInstructions = sortNodesWithinBlockLatest(b, visited);
+                break;
+            default:
+                throw new GraalInternalError("unknown scheduling strategy");
+        }
+        blockToNodesMap.put(b, sortedInstructions);
+    }
+
     /**
      * 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 void sortNodesWithinBlock(Block b, NodeBitMap visited) {
+    private List<ScheduledNode> sortNodesWithinBlockLatest(Block b, NodeBitMap visited) {
         List<ScheduledNode> instructions = blockToNodesMap.get(b);
-        List<ScheduledNode> sortedInstructions = new ArrayList<>(instructions.size() + 2);
-
-        assert !visited.isMarked(b.getBeginNode()) && cfg.blockFor(b.getBeginNode()) == b;
-        assert !visited.isMarked(b.getEndNode()) && cfg.blockFor(b.getEndNode()) == b;
+        List<ScheduledNode> sortedInstructions = new ArrayList<>(blockToNodesMap.get(b).size() + 2);
 
         for (ScheduledNode i : instructions) {
-            addToSorting(b, i, sortedInstructions, visited);
+            addToLatestSorting(b, i, sortedInstructions, visited);
         }
 
         // Make sure that last node gets really last (i.e. when a frame state successor hangs off
@@ -363,25 +509,25 @@
                 sortedInstructions.add(b.getEndNode());
             }
         }
-        blockToNodesMap.put(b, sortedInstructions);
+        return sortedInstructions;
     }
 
-    private void addUnscheduledToSorting(Block b, VirtualState state, List<ScheduledNode> sortedInstructions, NodeBitMap visited) {
+    private void addUnscheduledToLatestSorting(Block b, VirtualState state, List<ScheduledNode> sortedInstructions, NodeBitMap visited) {
         if (state != null) {
             // UnscheduledNodes should never be marked as visited.
             assert !visited.isMarked(state);
 
             for (Node input : state.inputs()) {
                 if (input instanceof VirtualState) {
-                    addUnscheduledToSorting(b, (VirtualState) input, sortedInstructions, visited);
+                    addUnscheduledToLatestSorting(b, (VirtualState) input, sortedInstructions, visited);
                 } else {
-                    addToSorting(b, (ScheduledNode) input, sortedInstructions, visited);
+                    addToLatestSorting(b, (ScheduledNode) input, sortedInstructions, visited);
                 }
             }
         }
     }
 
-    private void addToSorting(Block b, ScheduledNode i, List<ScheduledNode> sortedInstructions, NodeBitMap visited) {
+    private void addToLatestSorting(Block b, ScheduledNode i, List<ScheduledNode> sortedInstructions, NodeBitMap visited) {
         if (i == null || visited.isMarked(i) || cfg.getNodeToBlock().get(i) != b || i instanceof PhiNode || i instanceof LocalNode) {
             return;
         }
@@ -396,17 +542,74 @@
                 assert state == null;
                 state = (FrameState) input;
             } else {
-                addToSorting(b, (ScheduledNode) input, sortedInstructions, visited);
+                addToLatestSorting(b, (ScheduledNode) input, sortedInstructions, visited);
+            }
+        }
+        List<FloatingNode> inputs = phantomInputs.get(i);
+        if (inputs != null) {
+            for (FloatingNode input : inputs) {
+                addToLatestSorting(b, input, sortedInstructions, visited);
             }
         }
 
-        addToSorting(b, (ScheduledNode) i.predecessor(), sortedInstructions, visited);
+        addToLatestSorting(b, (ScheduledNode) i.predecessor(), sortedInstructions, visited);
         visited.mark(i);
-        addUnscheduledToSorting(b, state, sortedInstructions, visited);
+        addUnscheduledToLatestSorting(b, state, sortedInstructions, visited);
         assert write == null || !visited.isMarked(write);
-        addToSorting(b, write, sortedInstructions, visited);
+        addToLatestSorting(b, write, sortedInstructions, visited);
 
         // Now predecessors and inputs are scheduled => we can add this node.
         sortedInstructions.add(i);
     }
+
+    /**
+     * Sorts the nodes within a block by adding the nodes to a list in a post-order iteration over
+     * all usages. The resulting list is reversed to create an earliest-possible scheduling of
+     * nodes.
+     */
+    private List<ScheduledNode> sortNodesWithinBlockEarliest(Block b, NodeBitMap visited) {
+        List<ScheduledNode> sortedInstructions = new ArrayList<>(blockToNodesMap.get(b).size() + 2);
+        addToEarliestSorting(b, b.getEndNode(), sortedInstructions, visited);
+        Collections.reverse(sortedInstructions);
+        return sortedInstructions;
+    }
+
+    private void addToEarliestSorting(Block b, ScheduledNode i, List<ScheduledNode> sortedInstructions, NodeBitMap visited) {
+        if (i == null || visited.isMarked(i) || cfg.getNodeToBlock().get(i) != b || i instanceof PhiNode || i instanceof LocalNode) {
+            return;
+        }
+
+        visited.mark(i);
+        for (Node usage : i.usages()) {
+            if (usage instanceof VirtualState) {
+                // only fixed nodes can have VirtualState -> no need to schedule them
+            } else {
+                if (i instanceof LoopExitNode && usage instanceof ProxyNode) {
+                    // value proxies should be scheduled before the loopexit, not after
+                } else {
+                    addToEarliestSorting(b, (ScheduledNode) usage, sortedInstructions, visited);
+                }
+            }
+        }
+
+        if (i instanceof BeginNode) {
+            ArrayList<ProxyNode> proxies = (i instanceof LoopExitNode) ? new ArrayList<ProxyNode>() : null;
+            for (ScheduledNode inBlock : blockToNodesMap.get(b)) {
+                if (!visited.isMarked(inBlock)) {
+                    if (inBlock instanceof ProxyNode) {
+                        proxies.add((ProxyNode) inBlock);
+                    } else {
+                        addToEarliestSorting(b, inBlock, sortedInstructions, visited);
+                    }
+                }
+            }
+            sortedInstructions.add(i);
+            if (proxies != null) {
+                sortedInstructions.addAll(proxies);
+            }
+        } else {
+            sortedInstructions.add(i);
+            addToEarliestSorting(b, (ScheduledNode) i.predecessor(), sortedInstructions, visited);
+        }
+    }
 }
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/GraphPrinterDumpHandler.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/GraphPrinterDumpHandler.java	Fri Mar 01 17:06:08 2013 +0100
@@ -33,6 +33,7 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.schedule.*;
 
 /**
  * Observes compilation events and uses {@link IdealGraphPrinter} to generate a graph representation
@@ -153,13 +154,14 @@
                 // Save inline context for next dump.
                 previousInlineContext = inlineContext;
 
+                final SchedulePhase predefinedSchedule = getPredefinedSchedule();
                 Debug.sandbox("PrintingGraph", new Runnable() {
 
                     @Override
                     public void run() {
                         // Finally, output the graph.
                         try {
-                            printer.print(graph, message, null);
+                            printer.print(graph, message, predefinedSchedule);
                         } catch (IOException e) {
                             failuresCount++;
                             printer = null;
@@ -191,6 +193,16 @@
         return result;
     }
 
+    private static SchedulePhase getPredefinedSchedule() {
+        SchedulePhase result = null;
+        for (Object o : Debug.context()) {
+            if (o instanceof SchedulePhase) {
+                result = (SchedulePhase) o;
+            }
+        }
+        return result;
+    }
+
     private void openScope(String name, boolean showThread) {
         String prefix = showThread ? Thread.currentThread().getName() + ":" : "";
         try {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/PointerTest.java	Fri Mar 01 17:06:08 2013 +0100
@@ -0,0 +1,399 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.snippets;
+
+import java.lang.reflect.*;
+
+import org.junit.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.runtime.*;
+import com.oracle.graal.compiler.test.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.snippets.Snippet.SnippetInliningPolicy;
+import com.oracle.graal.word.*;
+
+/**
+ * Tests for the {@link Pointer} read and write operations.
+ */
+public class PointerTest extends GraalCompilerTest implements SnippetsInterface {
+
+    private static final Object ID = new Object();
+    private static final Kind[] KINDS = new Kind[]{Kind.Byte, Kind.Char, Kind.Short, Kind.Int, Kind.Long, Kind.Float, Kind.Double, Kind.Object};
+    private final TargetDescription target;
+    private final SnippetInstaller installer;
+
+    public PointerTest() {
+        target = Graal.getRequiredCapability(CodeCacheProvider.class).getTarget();
+        installer = new SnippetInstaller(runtime, new Assumptions(false), target);
+    }
+
+    private static final ThreadLocal<SnippetInliningPolicy> inliningPolicy = new ThreadLocal<>();
+
+    @Override
+    protected StructuredGraph parse(Method m) {
+        ResolvedJavaMethod resolvedMethod = runtime.lookupJavaMethod(m);
+        return installer.makeGraph(resolvedMethod, inliningPolicy.get());
+    }
+
+    @Test
+    public void test_read1() {
+        for (Kind kind : KINDS) {
+            assertRead(parse("read" + kind.name() + "1"), kind, false, ID);
+        }
+    }
+
+    @Test
+    public void test_read2() {
+        for (Kind kind : KINDS) {
+            assertRead(parse("read" + kind.name() + "2"), kind, true, ID);
+        }
+    }
+
+    @Test
+    public void test_read3() {
+        for (Kind kind : KINDS) {
+            assertRead(parse("read" + kind.name() + "3"), kind, false, LocationNode.UNKNOWN_LOCATION);
+        }
+    }
+
+    @Test
+    public void test_write1() {
+        for (Kind kind : KINDS) {
+            assertWrite(parse("write" + kind.name() + "1"), kind, false, ID);
+        }
+    }
+
+    @Test
+    public void test_write2() {
+        for (Kind kind : KINDS) {
+            assertWrite(parse("write" + kind.name() + "2"), kind, true, ID);
+        }
+    }
+
+    @Test
+    public void test_write3() {
+        for (Kind kind : KINDS) {
+            assertWrite(parse("write" + kind.name() + "3"), kind, false, LocationNode.ANY_LOCATION);
+        }
+    }
+
+    private void assertRead(StructuredGraph graph, Kind kind, boolean indexConvert, Object locationIdentity) {
+        ReadNode read = (ReadNode) graph.start().next();
+        Assert.assertEquals(kind.getStackKind(), read.kind());
+
+        UnsafeCastNode cast = (UnsafeCastNode) read.object();
+        Assert.assertEquals(graph.getLocal(0), cast.object());
+        Assert.assertEquals(target.wordKind, cast.kind());
+
+        IndexedLocationNode location = (IndexedLocationNode) read.location();
+        Assert.assertEquals(kind, location.getValueKind());
+        Assert.assertEquals(locationIdentity, location.locationIdentity());
+        Assert.assertEquals(1, location.indexScaling());
+
+        if (indexConvert) {
+            ConvertNode convert = (ConvertNode) location.index();
+            Assert.assertEquals(ConvertNode.Op.I2L, convert.opcode);
+            Assert.assertEquals(graph.getLocal(1), convert.value());
+        } else {
+            Assert.assertEquals(graph.getLocal(1), location.index());
+        }
+
+        ReturnNode ret = (ReturnNode) read.next();
+        Assert.assertEquals(read, ret.result());
+    }
+
+    private void assertWrite(StructuredGraph graph, Kind kind, boolean indexConvert, Object locationIdentity) {
+        WriteNode write = (WriteNode) graph.start().next();
+        Assert.assertEquals(graph.getLocal(2), write.value());
+        Assert.assertEquals(Kind.Void, write.kind());
+        Assert.assertEquals(FrameState.INVALID_FRAMESTATE_BCI, write.stateAfter().bci);
+
+        UnsafeCastNode cast = (UnsafeCastNode) write.object();
+        Assert.assertEquals(graph.getLocal(0), cast.object());
+        Assert.assertEquals(target.wordKind, cast.kind());
+
+        IndexedLocationNode location = (IndexedLocationNode) write.location();
+        Assert.assertEquals(kind, location.getValueKind());
+        Assert.assertEquals(locationIdentity, location.locationIdentity());
+        Assert.assertEquals(1, location.indexScaling());
+
+        if (indexConvert) {
+            ConvertNode convert = (ConvertNode) location.index();
+            Assert.assertEquals(ConvertNode.Op.I2L, convert.opcode);
+            Assert.assertEquals(graph.getLocal(1), convert.value());
+        } else {
+            Assert.assertEquals(graph.getLocal(1), location.index());
+        }
+
+        AbstractStateSplit stateSplit = (AbstractStateSplit) write.next();
+        Assert.assertEquals(FrameState.AFTER_BCI, stateSplit.stateAfter().bci);
+
+        ReturnNode ret = (ReturnNode) stateSplit.next();
+        Assert.assertEquals(null, ret.result());
+    }
+
+    @Snippet
+    public static byte readByte1(Object o, int offset) {
+        return Word.fromObject(o).readByte(offset, ID);
+    }
+
+    @Snippet
+    public static byte readByte2(Object o, int offset) {
+        return Word.fromObject(o).readByte(Word.signed(offset), ID);
+    }
+
+    @Snippet
+    public static byte readByte3(Object o, int offset) {
+        return Word.fromObject(o).readByte(offset);
+    }
+
+    @Snippet
+    public static void writeByte1(Object o, int offset, byte value) {
+        Word.fromObject(o).writeByte(offset, value, ID);
+    }
+
+    @Snippet
+    public static void writeByte2(Object o, int offset, byte value) {
+        Word.fromObject(o).writeByte(Word.signed(offset), value, ID);
+    }
+
+    @Snippet
+    public static void writeByte3(Object o, int offset, byte value) {
+        Word.fromObject(o).writeByte(offset, value);
+    }
+
+    @Snippet
+    public static char readChar1(Object o, int offset) {
+        return Word.fromObject(o).readChar(offset, ID);
+    }
+
+    @Snippet
+    public static char readChar2(Object o, int offset) {
+        return Word.fromObject(o).readChar(Word.signed(offset), ID);
+    }
+
+    @Snippet
+    public static char readChar3(Object o, int offset) {
+        return Word.fromObject(o).readChar(offset);
+    }
+
+    @Snippet
+    public static void writeChar1(Object o, int offset, char value) {
+        Word.fromObject(o).writeChar(offset, value, ID);
+    }
+
+    @Snippet
+    public static void writeChar2(Object o, int offset, char value) {
+        Word.fromObject(o).writeChar(Word.signed(offset), value, ID);
+    }
+
+    @Snippet
+    public static void writeChar3(Object o, int offset, char value) {
+        Word.fromObject(o).writeChar(offset, value);
+    }
+
+    @Snippet
+    public static short readShort1(Object o, int offset) {
+        return Word.fromObject(o).readShort(offset, ID);
+    }
+
+    @Snippet
+    public static short readShort2(Object o, int offset) {
+        return Word.fromObject(o).readShort(Word.signed(offset), ID);
+    }
+
+    @Snippet
+    public static short readShort3(Object o, int offset) {
+        return Word.fromObject(o).readShort(offset);
+    }
+
+    @Snippet
+    public static void writeShort1(Object o, int offset, short value) {
+        Word.fromObject(o).writeShort(offset, value, ID);
+    }
+
+    @Snippet
+    public static void writeShort2(Object o, int offset, short value) {
+        Word.fromObject(o).writeShort(Word.signed(offset), value, ID);
+    }
+
+    @Snippet
+    public static void writeShort3(Object o, int offset, short value) {
+        Word.fromObject(o).writeShort(offset, value);
+    }
+
+    @Snippet
+    public static int readInt1(Object o, int offset) {
+        return Word.fromObject(o).readInt(offset, ID);
+    }
+
+    @Snippet
+    public static int readInt2(Object o, int offset) {
+        return Word.fromObject(o).readInt(Word.signed(offset), ID);
+    }
+
+    @Snippet
+    public static int readInt3(Object o, int offset) {
+        return Word.fromObject(o).readInt(offset);
+    }
+
+    @Snippet
+    public static void writeInt1(Object o, int offset, int value) {
+        Word.fromObject(o).writeInt(offset, value, ID);
+    }
+
+    @Snippet
+    public static void writeInt2(Object o, int offset, int value) {
+        Word.fromObject(o).writeInt(Word.signed(offset), value, ID);
+    }
+
+    @Snippet
+    public static void writeInt3(Object o, int offset, int value) {
+        Word.fromObject(o).writeInt(offset, value);
+    }
+
+    @Snippet
+    public static long readLong1(Object o, int offset) {
+        return Word.fromObject(o).readLong(offset, ID);
+    }
+
+    @Snippet
+    public static long readLong2(Object o, int offset) {
+        return Word.fromObject(o).readLong(Word.signed(offset), ID);
+    }
+
+    @Snippet
+    public static long readLong3(Object o, int offset) {
+        return Word.fromObject(o).readLong(offset);
+    }
+
+    @Snippet
+    public static void writeLong1(Object o, int offset, long value) {
+        Word.fromObject(o).writeLong(offset, value, ID);
+    }
+
+    @Snippet
+    public static void writeLong2(Object o, int offset, long value) {
+        Word.fromObject(o).writeLong(Word.signed(offset), value, ID);
+    }
+
+    @Snippet
+    public static void writeLong3(Object o, int offset, long value) {
+        Word.fromObject(o).writeLong(offset, value);
+    }
+
+    @Snippet
+    public static float readFloat1(Object o, int offset) {
+        return Word.fromObject(o).readFloat(offset, ID);
+    }
+
+    @Snippet
+    public static float readFloat2(Object o, int offset) {
+        return Word.fromObject(o).readFloat(Word.signed(offset), ID);
+    }
+
+    @Snippet
+    public static float readFloat3(Object o, int offset) {
+        return Word.fromObject(o).readFloat(offset);
+    }
+
+    @Snippet
+    public static void writeFloat1(Object o, int offset, float value) {
+        Word.fromObject(o).writeFloat(offset, value, ID);
+    }
+
+    @Snippet
+    public static void writeFloat2(Object o, int offset, float value) {
+        Word.fromObject(o).writeFloat(Word.signed(offset), value, ID);
+    }
+
+    @Snippet
+    public static void writeFloat3(Object o, int offset, float value) {
+        Word.fromObject(o).writeFloat(offset, value);
+    }
+
+    @Snippet
+    public static double readDouble1(Object o, int offset) {
+        return Word.fromObject(o).readDouble(offset, ID);
+    }
+
+    @Snippet
+    public static double readDouble2(Object o, int offset) {
+        return Word.fromObject(o).readDouble(Word.signed(offset), ID);
+    }
+
+    @Snippet
+    public static double readDouble3(Object o, int offset) {
+        return Word.fromObject(o).readDouble(offset);
+    }
+
+    @Snippet
+    public static void writeDouble1(Object o, int offset, double value) {
+        Word.fromObject(o).writeDouble(offset, value, ID);
+    }
+
+    @Snippet
+    public static void writeDouble2(Object o, int offset, double value) {
+        Word.fromObject(o).writeDouble(Word.signed(offset), value, ID);
+    }
+
+    @Snippet
+    public static void writeDouble3(Object o, int offset, double value) {
+        Word.fromObject(o).writeDouble(offset, value);
+    }
+
+    @Snippet
+    public static Object readObject1(Object o, int offset) {
+        return Word.fromObject(o).readObject(offset, ID);
+    }
+
+    @Snippet
+    public static Object readObject2(Object o, int offset) {
+        return Word.fromObject(o).readObject(Word.signed(offset), ID);
+    }
+
+    @Snippet
+    public static Object readObject3(Object o, int offset) {
+        return Word.fromObject(o).readObject(offset);
+    }
+
+    @Snippet
+    public static void writeObject1(Object o, int offset, Object value) {
+        Word.fromObject(o).writeObject(offset, value, ID);
+    }
+
+    @Snippet
+    public static void writeObject2(Object o, int offset, Object value) {
+        Word.fromObject(o).writeObject(Word.signed(offset), value, ID);
+    }
+
+    @Snippet
+    public static void writeObject3(Object o, int offset, Object value) {
+        Word.fromObject(o).writeObject(offset, value);
+    }
+
+}
--- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/WordTest.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/WordTest.java	Fri Mar 01 17:06:08 2013 +0100
@@ -51,7 +51,7 @@
     @Override
     protected StructuredGraph parse(Method m) {
         ResolvedJavaMethod resolvedMethod = runtime.lookupJavaMethod(m);
-        return installer.makeGraph(resolvedMethod, inliningPolicy.get(), false);
+        return installer.makeGraph(resolvedMethod, inliningPolicy.get());
     }
 
     @Test
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/InstanceOfSnippetsTemplates.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/InstanceOfSnippetsTemplates.java	Fri Mar 01 17:06:08 2013 +0100
@@ -223,11 +223,15 @@
             usage.replaceFirstInput(instanceOf, instantiation.asCondition(trueValue));
         }
 
+        private boolean usageFollowsInstantiation() {
+            return instantiation.result != null && instantiation.result.merge().next() == usage;
+        }
+
         @Override
         public void replace(ValueNode oldNode, ValueNode newNode) {
             assert newNode instanceof PhiNode;
             assert oldNode == instanceOf;
-            if (sameBlock && solitaryUsage) {
+            if (sameBlock && solitaryUsage && usageFollowsInstantiation()) {
                 removeIntermediateMaterialization(newNode);
             } else {
                 newNode.inferStamp();
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetFrameStateCleanupPhase.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetFrameStateCleanupPhase.java	Fri Mar 01 17:06:08 2013 +0100
@@ -22,30 +22,98 @@
  */
 package com.oracle.graal.snippets;
 
-import com.oracle.graal.graph.*;
+import java.util.*;
+
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.graph.*;
+import com.oracle.graal.phases.graph.ReentrantNodeIterator.LoopInfo;
+import com.oracle.graal.phases.graph.ReentrantNodeIterator.NodeIteratorClosure;
 
 /**
  * Removes frame states from {@linkplain StateSplit#hasSideEffect() non-side-effecting} nodes in a
  * snippet.
+ * 
+ * The frame states of side-effecting nodes are replaced with
+ * {@linkplain FrameState#INVALID_FRAMESTATE_BCI invalid} frame states. Loops that contain invalid
+ * frame states are also assigned an invalid frame state.
+ * 
+ * The invalid frame states ensure that no deoptimization to a snippet frame state will happen.
  */
 public class SnippetFrameStateCleanupPhase extends Phase {
 
     @Override
     protected void run(StructuredGraph graph) {
-        for (Node node : graph.getNodes().filterInterface(StateSplit.class)) {
-            StateSplit stateSplit = (StateSplit) node;
-            FrameState frameState = stateSplit.stateAfter();
-            if (!stateSplit.hasSideEffect()) {
+        ReentrantNodeIterator.apply(new SnippetFrameStateCleanupClosure(), graph.start(), new CleanupState(false), null);
+    }
+
+    private static class CleanupState {
+
+        public boolean containsFrameState;
+
+        public CleanupState(boolean containsFrameState) {
+            this.containsFrameState = containsFrameState;
+        }
+    }
+
+    /**
+     * A proper (loop-aware) iteration over the graph is used to detect loops that contain invalid
+     * frame states, so that they can be marked with an invalid frame state.
+     */
+    private static class SnippetFrameStateCleanupClosure extends NodeIteratorClosure<CleanupState> {
+
+        @Override
+        protected void processNode(FixedNode node, CleanupState currentState) {
+            if (node instanceof StateSplit) {
+                StateSplit stateSplit = (StateSplit) node;
+                FrameState frameState = stateSplit.stateAfter();
                 if (frameState != null) {
-                    stateSplit.setStateAfter(null);
+                    if (stateSplit.hasSideEffect()) {
+                        currentState.containsFrameState = true;
+                        stateSplit.setStateAfter(node.graph().add(new FrameState(FrameState.INVALID_FRAMESTATE_BCI)));
+                    } else {
+                        stateSplit.setStateAfter(null);
+                    }
                     if (frameState.usages().isEmpty()) {
                         GraphUtil.killWithUnusedFloatingInputs(frameState);
                     }
                 }
             }
         }
+
+        @Override
+        protected CleanupState merge(MergeNode merge, List<CleanupState> states) {
+            for (CleanupState state : states) {
+                if (state.containsFrameState) {
+                    return new CleanupState(true);
+                }
+            }
+            return new CleanupState(false);
+        }
+
+        @Override
+        protected CleanupState afterSplit(BeginNode node, CleanupState oldState) {
+            return new CleanupState(oldState.containsFrameState);
+        }
+
+        @Override
+        protected Map<LoopExitNode, CleanupState> processLoop(LoopBeginNode loop, CleanupState initialState) {
+            LoopInfo<CleanupState> info = ReentrantNodeIterator.processLoop(this, loop, new CleanupState(false));
+            boolean containsFrameState = false;
+            for (CleanupState state : info.endStates.values()) {
+                containsFrameState |= state.containsFrameState;
+            }
+            if (containsFrameState) {
+                loop.setStateAfter(loop.graph().add(new FrameState(FrameState.INVALID_FRAMESTATE_BCI)));
+            }
+            if (containsFrameState || initialState.containsFrameState) {
+                for (CleanupState state : info.exitStates.values()) {
+                    state.containsFrameState = true;
+                }
+            }
+            return info.exitStates;
+        }
+
     }
 }
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetInstaller.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetInstaller.java	Fri Mar 01 17:06:08 2013 +0100
@@ -89,7 +89,7 @@
                 }
                 ResolvedJavaMethod snippet = runtime.lookupJavaMethod(method);
                 assert snippet.getCompilerStorage().get(Graph.class) == null : method;
-                StructuredGraph graph = makeGraph(snippet, inliningPolicy(snippet), false);
+                StructuredGraph graph = makeGraph(snippet, inliningPolicy(snippet));
                 // System.out.println("snippet: " + graph);
                 snippet.getCompilerStorage().put(Graph.class, graph);
             }
@@ -152,9 +152,8 @@
         substitute = runtime.lookupJavaMethod(substituteMethod);
         original = runtime.lookupJavaMethod(originalMethod);
         try {
-            // System.out.println("substitution: " + MetaUtil.format("%H.%n(%p)", original) +
-            // " --> " + MetaUtil.format("%H.%n(%p)", substitute));
-            StructuredGraph graph = makeGraph(substitute, inliningPolicy(substitute), true);
+            Debug.log("substitution: " + MetaUtil.format("%H.%n(%p)", original) + " --> " + MetaUtil.format("%H.%n(%p)", substitute));
+            StructuredGraph graph = makeGraph(substitute, inliningPolicy(substitute));
             Object oldValue = original.getCompilerStorage().put(Graph.class, graph);
             assert oldValue == null;
         } finally {
@@ -192,7 +191,7 @@
         }
     }
 
-    public StructuredGraph makeGraph(final ResolvedJavaMethod method, final SnippetInliningPolicy policy, final boolean isSubstitution) {
+    public StructuredGraph makeGraph(final ResolvedJavaMethod method, final SnippetInliningPolicy policy) {
         return Debug.scope("BuildSnippetGraph", new Object[]{method}, new Callable<StructuredGraph>() {
 
             @Override
@@ -201,12 +200,8 @@
 
                 new SnippetIntrinsificationPhase(runtime, pool, SnippetTemplate.hasConstantParameter(method)).apply(graph);
 
-                if (isSubstitution && !substituteCallsOriginal) {
-                    // TODO (ds) remove the constraint of only processing substitutions
-                    // once issues with the arraycopy snippets have been resolved
-                    new SnippetFrameStateCleanupPhase().apply(graph);
-                    new DeadCodeEliminationPhase().apply(graph);
-                }
+                new SnippetFrameStateCleanupPhase().apply(graph);
+                new DeadCodeEliminationPhase().apply(graph);
 
                 new InsertStateAfterPlaceholderPhase().apply(graph);
 
@@ -221,7 +216,6 @@
         StructuredGraph graph = graphCache.get(method);
         if (graph == null) {
             graph = buildGraph(method, policy == null ? inliningPolicy(method) : policy);
-            // System.out.println("built " + graph);
             graphCache.put(method, graph);
         }
         return graph;
@@ -248,10 +242,6 @@
                 new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.NONE).apply(originalGraph);
                 InliningUtil.inline(invoke, originalGraph, true);
 
-                // TODO the inlined frame states still show the call from the substitute to the
-                // original.
-                // If this poses a problem, a phase should added to fix up these frame states.
-
                 Debug.dump(graph, "after inlining %s", callee);
                 if (GraalOptions.OptCanonicalizer) {
                     new CanonicalizerPhase(runtime, assumptions).apply(graph);
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetIntrinsificationPhase.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetIntrinsificationPhase.java	Fri Mar 01 17:06:08 2013 +0100
@@ -364,7 +364,7 @@
         if (newInstance instanceof ValueNode && (((ValueNode) newInstance).kind() != Kind.Object || ((ValueNode) newInstance).stamp() == StampFactory.forNodeIntrinsic())) {
             StructuredGraph graph = (StructuredGraph) newInstance.graph();
             for (CheckCastNode checkCastNode : newInstance.usages().filter(CheckCastNode.class).snapshot()) {
-                for (ValueProxyNode vpn : checkCastNode.usages().filter(ValueProxyNode.class).snapshot()) {
+                for (ProxyNode vpn : checkCastNode.usages().filter(ProxyNode.class).snapshot()) {
                     graph.replaceFloating(vpn, checkCastNode);
                 }
                 for (Node checkCastUsage : checkCastNode.usages().snapshot()) {
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/DirectReadNode.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/DirectReadNode.java	Fri Mar 01 17:06:08 2013 +0100
@@ -45,7 +45,7 @@
 
     @Override
     public void generate(LIRGeneratorTool gen) {
-        gen.setResult(this, gen.emitLoad(gen.makeAddress(readKind, gen.operand(address)), false));
+        gen.setResult(this, gen.emitLoad(readKind, gen.operand(address), 0, Value.ILLEGAL, 0, false));
     }
 
     @NodeIntrinsic
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/DirectStoreNode.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/DirectStoreNode.java	Fri Mar 01 17:06:08 2013 +0100
@@ -48,7 +48,7 @@
     @Override
     public void generate(LIRGeneratorTool gen) {
         Value v = gen.operand(value);
-        gen.emitStore(gen.makeAddress(kind, gen.operand(address)), v, false);
+        gen.emitStore(kind, gen.operand(address), 0, Value.ILLEGAL, 0, v, false);
     }
 
     /*
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/MacroNode.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/MacroNode.java	Fri Mar 01 17:06:08 2013 +0100
@@ -30,6 +30,7 @@
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.phases.common.*;
 
 public class MacroNode extends AbstractStateSplit implements Lowerable {
 
@@ -47,14 +48,32 @@
         this.returnType = invoke.methodCallTarget().returnType();
     }
 
+    public int getBci() {
+        return bci;
+    }
+
+    public ResolvedJavaMethod getTargetMethod() {
+        return targetMethod;
+    }
+
+    @SuppressWarnings("unused")
+    protected StructuredGraph getSnippetGraph(LoweringTool tool) {
+        return null;
+    }
+
     @Override
     public void lower(LoweringTool tool) {
-        replaceWithInvoke();
+        StructuredGraph snippetGraph = getSnippetGraph(tool);
+
+        InvokeNode invoke = replaceWithInvoke();
+
+        if (snippetGraph != null) {
+            InliningUtil.inline(invoke, snippetGraph, false);
+        }
     }
 
-    public InvokeNode replaceWithInvoke() {
+    private InvokeNode replaceWithInvoke() {
         InvokeNode invoke = createInvoke();
-
         ((StructuredGraph) graph()).replaceFixedWithFixed(this, invoke);
         return invoke;
     }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/BlockState.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/BlockState.java	Fri Mar 01 17:06:08 2013 +0100
@@ -32,10 +32,9 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.Virtualizable.EscapeState;
 import com.oracle.graal.nodes.virtual.*;
-import com.oracle.graal.phases.graph.ReentrantBlockIterator.MergeableBlockState;
 import com.oracle.graal.virtual.nodes.*;
 
-class BlockState extends MergeableBlockState<BlockState> {
+class BlockState {
 
     private final HashMap<VirtualObjectNode, ObjectState> objectStates = new HashMap<>();
     private final HashMap<ValueNode, VirtualObjectNode> objectAliases = new HashMap<>();
@@ -70,7 +69,6 @@
         return object == null ? null : getObjectState(object);
     }
 
-    @Override
     public BlockState cloneState() {
         return new BlockState(this);
     }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Fri Mar 01 17:06:08 2013 +0100
@@ -457,9 +457,9 @@
     }
 
     private void processLoopExit(LoopExitNode exitNode, BlockState initialState, BlockState exitState) {
-        HashMap<VirtualObjectNode, ValueProxyNode> proxies = new HashMap<>();
+        HashMap<VirtualObjectNode, ProxyNode> proxies = new HashMap<>();
 
-        for (ValueProxyNode proxy : exitNode.proxies()) {
+        for (ProxyNode proxy : exitNode.proxies()) {
             ObjectState obj = exitState.getObjectState(proxy.value());
             if (obj != null) {
                 proxies.put(obj.virtual, proxy);
@@ -473,7 +473,7 @@
                     ObjectState valueObj = exitState.getObjectState(value);
                     if (valueObj == null) {
                         if ((value instanceof PhiNode && ((PhiNode) value).merge() == exitNode.loopBegin()) || initialObj == null || !initialObj.isVirtual() || initialObj.getEntry(i) != value) {
-                            ValueProxyNode proxy = new ValueProxyNode(value, exitNode, PhiType.Value);
+                            ProxyNode proxy = new ProxyNode(value, exitNode, PhiType.Value);
                             obj.setEntry(i, proxy);
                             effects.addFloatingNode(proxy);
                         }
@@ -481,9 +481,9 @@
                 }
             } else {
                 if (initialObj == null || initialObj.isVirtual()) {
-                    ValueProxyNode proxy = proxies.get(obj.virtual);
+                    ProxyNode proxy = proxies.get(obj.virtual);
                     if (proxy == null) {
-                        proxy = new ValueProxyNode(obj.getMaterializedValue(), exitNode, PhiType.Value);
+                        proxy = new ProxyNode(obj.getMaterializedValue(), exitNode, PhiType.Value);
                         effects.addFloatingNode(proxy);
                     } else {
                         effects.replaceFirstInput(proxy, proxy.value(), obj.getMaterializedValue());
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/Pointer.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/Pointer.java	Fri Mar 01 17:06:08 2013 +0100
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.word;
 
+import com.oracle.graal.nodes.extended.*;
+
 public interface Pointer extends Unsigned {
 
     /**
@@ -42,6 +44,438 @@
      * knows that the highest-order bit of the unsigned value is never used).
      * 
      * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    byte readByte(WordBase offset, Object locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    char readChar(WordBase offset, Object locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    short readShort(WordBase offset, Object locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    int readInt(WordBase offset, Object locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    long readLong(WordBase offset, Object locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    float readFloat(WordBase offset, Object locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    double readDouble(WordBase offset, Object locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    Word readWord(WordBase offset, Object locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    Object readObject(WordBase offset, Object locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * 
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    byte readByte(int offset, Object locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * 
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    char readChar(int offset, Object locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * 
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    short readShort(int offset, Object locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * 
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    int readInt(int offset, Object locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * 
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    long readLong(int offset, Object locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * 
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    float readFloat(int offset, Object locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * 
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    double readDouble(int offset, Object locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * 
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    Word readWord(int offset, Object locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * 
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    Object readObject(int offset, Object locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    void writeByte(WordBase offset, byte val, Object locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    void writeChar(WordBase offset, char val, Object locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    void writeShort(WordBase offset, short val, Object locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    void writeInt(WordBase offset, int val, Object locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    void writeLong(WordBase offset, long val, Object locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    void writeFloat(WordBase offset, float val, Object locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    void writeDouble(WordBase offset, double val, Object locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    void writeWord(WordBase offset, WordBase val, Object locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    void writeObject(WordBase offset, Object val, Object locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * 
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    void writeByte(int offset, byte val, Object locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * 
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    void writeChar(int offset, char val, Object locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * 
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    void writeShort(int offset, short val, Object locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * 
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    void writeInt(int offset, int val, Object locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * 
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    void writeLong(int offset, long val, Object locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * 
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    void writeFloat(int offset, float val, Object locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * 
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    void writeDouble(int offset, double val, Object locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * 
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    void writeWord(int offset, WordBase val, Object locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * 
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    void writeObject(int offset, Object val, Object locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param offset the signed offset for the memory access
      * @return the result of the memory access
      */
     byte readByte(WordBase offset);
@@ -232,150 +666,6 @@
     Object readObject(int offset);
 
     /**
-     * Reads the constant memory at address {@code (this + offset)}. Both the base address and
-     * offset are in bytes.
-     * <p>
-     * The caller guarantees that the memory content is final, i.e., never changing. The compiler
-     * can therefore eliminate memory accesses more aggressively.
-     * <p>
-     * The offset is always treated as a {@link Signed} value. However, the static type is
-     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
-     * knows that the highest-order bit of the unsigned value is never used).
-     * 
-     * @param offset the signed offset for the memory access
-     * @return the result of the memory access
-     */
-    byte readFinalByte(WordBase offset);
-
-    /**
-     * Reads the constant memory at address {@code (this + offset)}. Both the base address and
-     * offset are in bytes.
-     * <p>
-     * The caller guarantees that the memory content is final, i.e., never changing. The compiler
-     * can therefore eliminate memory accesses more aggressively.
-     * <p>
-     * The offset is always treated as a {@link Signed} value. However, the static type is
-     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
-     * knows that the highest-order bit of the unsigned value is never used).
-     * 
-     * @param offset the signed offset for the memory access
-     * @return the result of the memory access
-     */
-    char readFinalChar(WordBase offset);
-
-    /**
-     * Reads the constant memory at address {@code (this + offset)}. Both the base address and
-     * offset are in bytes.
-     * <p>
-     * The caller guarantees that the memory content is final, i.e., never changing. The compiler
-     * can therefore eliminate memory accesses more aggressively.
-     * <p>
-     * The offset is always treated as a {@link Signed} value. However, the static type is
-     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
-     * knows that the highest-order bit of the unsigned value is never used).
-     * 
-     * @param offset the signed offset for the memory access
-     * @return the result of the memory access
-     */
-    short readFinalShort(WordBase offset);
-
-    /**
-     * Reads the constant memory at address {@code (this + offset)}. Both the base address and
-     * offset are in bytes.
-     * <p>
-     * The caller guarantees that the memory content is final, i.e., never changing. The compiler
-     * can therefore eliminate memory accesses more aggressively.
-     * <p>
-     * The offset is always treated as a {@link Signed} value. However, the static type is
-     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
-     * knows that the highest-order bit of the unsigned value is never used).
-     * 
-     * @param offset the signed offset for the memory access
-     * @return the result of the memory access
-     */
-    int readFinalInt(WordBase offset);
-
-    /**
-     * Reads the constant memory at address {@code (this + offset)}. Both the base address and
-     * offset are in bytes.
-     * <p>
-     * The caller guarantees that the memory content is final, i.e., never changing. The compiler
-     * can therefore eliminate memory accesses more aggressively.
-     * <p>
-     * The offset is always treated as a {@link Signed} value. However, the static type is
-     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
-     * knows that the highest-order bit of the unsigned value is never used).
-     * 
-     * @param offset the signed offset for the memory access
-     * @return the result of the memory access
-     */
-    long readFinalLong(WordBase offset);
-
-    /**
-     * Reads the constant memory at address {@code (this + offset)}. Both the base address and
-     * offset are in bytes.
-     * <p>
-     * The caller guarantees that the memory content is final, i.e., never changing. The compiler
-     * can therefore eliminate memory accesses more aggressively.
-     * <p>
-     * The offset is always treated as a {@link Signed} value. However, the static type is
-     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
-     * knows that the highest-order bit of the unsigned value is never used).
-     * 
-     * @param offset the signed offset for the memory access
-     * @return the result of the memory access
-     */
-    float readFinalFloat(WordBase offset);
-
-    /**
-     * Reads the constant memory at address {@code (this + offset)}. Both the base address and
-     * offset are in bytes.
-     * <p>
-     * The caller guarantees that the memory content is final, i.e., never changing. The compiler
-     * can therefore eliminate memory accesses more aggressively.
-     * <p>
-     * The offset is always treated as a {@link Signed} value. However, the static type is
-     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
-     * knows that the highest-order bit of the unsigned value is never used).
-     * 
-     * @param offset the signed offset for the memory access
-     * @return the result of the memory access
-     */
-    double readFinalDouble(WordBase offset);
-
-    /**
-     * Reads the constant memory at address {@code (this + offset)}. Both the base address and
-     * offset are in bytes.
-     * <p>
-     * The caller guarantees that the memory content is final, i.e., never changing. The compiler
-     * can therefore eliminate memory accesses more aggressively.
-     * <p>
-     * The offset is always treated as a {@link Signed} value. However, the static type is
-     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
-     * knows that the highest-order bit of the unsigned value is never used).
-     * 
-     * @param offset the signed offset for the memory access
-     * @return the result of the memory access
-     */
-    Word readFinalWord(WordBase offset);
-
-    /**
-     * Reads the constant memory at address {@code (this + offset)}. Both the base address and
-     * offset are in bytes.
-     * <p>
-     * The caller guarantees that the memory content is final, i.e., never changing. The compiler
-     * can therefore eliminate memory accesses more aggressively.
-     * <p>
-     * The offset is always treated as a {@link Signed} value. However, the static type is
-     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
-     * knows that the highest-order bit of the unsigned value is never used).
-     * 
-     * @param offset the signed offset for the memory access
-     * @return the result of the memory access
-     */
-    Object readFinalObject(WordBase offset);
-
-    /**
      * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
      * bytes.
      * <p>
@@ -412,7 +702,7 @@
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      */
-    void writeShort(WordBase offset, Short val);
+    void writeShort(WordBase offset, short val);
 
     /**
      * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/Word.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/Word.java	Fri Mar 01 17:06:08 2013 +0100
@@ -58,7 +58,6 @@
          COMPARISON,
          NOT,
          READ,
-         READ_FINAL,
          WRITE,
          ZERO,
          FROM_UNSIGNED,
@@ -598,6 +597,218 @@
 
     @Override
     @Operation(opcode = Opcode.READ)
+    public byte readByte(WordBase offset, Object locationIdentity) {
+        return unsafe.getByte(add((Word) offset).unbox());
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ)
+    public char readChar(WordBase offset, Object locationIdentity) {
+        return unsafe.getChar(add((Word) offset).unbox());
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ)
+    public short readShort(WordBase offset, Object locationIdentity) {
+        return unsafe.getShort(add((Word) offset).unbox());
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ)
+    public int readInt(WordBase offset, Object locationIdentity) {
+        return unsafe.getInt(add((Word) offset).unbox());
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ)
+    public long readLong(WordBase offset, Object locationIdentity) {
+        return unsafe.getLong(add((Word) offset).unbox());
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ)
+    public float readFloat(WordBase offset, Object locationIdentity) {
+        return unsafe.getFloat(add((Word) offset).unbox());
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ)
+    public double readDouble(WordBase offset, Object locationIdentity) {
+        return unsafe.getDouble(add((Word) offset).unbox());
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ)
+    public Word readWord(WordBase offset, Object locationIdentity) {
+        return box(unsafe.getAddress(add((Word) offset).unbox()));
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ)
+    public native Object readObject(WordBase offset, Object locationIdentity);
+
+    @Override
+    @Operation(opcode = Opcode.READ)
+    public byte readByte(int offset, Object locationIdentity) {
+        return readByte(signed(offset), locationIdentity);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ)
+    public char readChar(int offset, Object locationIdentity) {
+        return readChar(signed(offset), locationIdentity);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ)
+    public short readShort(int offset, Object locationIdentity) {
+        return readShort(signed(offset), locationIdentity);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ)
+    public int readInt(int offset, Object locationIdentity) {
+        return readInt(signed(offset), locationIdentity);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ)
+    public long readLong(int offset, Object locationIdentity) {
+        return readLong(signed(offset), locationIdentity);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ)
+    public float readFloat(int offset, Object locationIdentity) {
+        return readFloat(signed(offset), locationIdentity);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ)
+    public double readDouble(int offset, Object locationIdentity) {
+        return readDouble(signed(offset), locationIdentity);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ)
+    public Word readWord(int offset, Object locationIdentity) {
+        return readWord(signed(offset), locationIdentity);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ)
+    public Object readObject(int offset, Object locationIdentity) {
+        return readObject(signed(offset), locationIdentity);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE)
+    public void writeByte(WordBase offset, byte val, Object locationIdentity) {
+        unsafe.putByte(add((Word) offset).unbox(), val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE)
+    public void writeChar(WordBase offset, char val, Object locationIdentity) {
+        unsafe.putChar(add((Word) offset).unbox(), val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE)
+    public void writeShort(WordBase offset, short val, Object locationIdentity) {
+        unsafe.putShort(add((Word) offset).unbox(), val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE)
+    public void writeInt(WordBase offset, int val, Object locationIdentity) {
+        unsafe.putInt(add((Word) offset).unbox(), val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE)
+    public void writeLong(WordBase offset, long val, Object locationIdentity) {
+        unsafe.putLong(add((Word) offset).unbox(), val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE)
+    public void writeFloat(WordBase offset, float val, Object locationIdentity) {
+        unsafe.putFloat(add((Word) offset).unbox(), val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE)
+    public void writeDouble(WordBase offset, double val, Object locationIdentity) {
+        unsafe.putDouble(add((Word) offset).unbox(), val);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE)
+    public void writeWord(WordBase offset, WordBase val, Object locationIdentity) {
+        unsafe.putAddress(add((Word) offset).unbox(), ((Word) val).unbox());
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE)
+    public native void writeObject(WordBase offset, Object val, Object locationIdentity);
+
+    @Override
+    @Operation(opcode = Opcode.WRITE)
+    public void writeByte(int offset, byte val, Object locationIdentity) {
+        writeByte(signed(offset), val, locationIdentity);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE)
+    public void writeChar(int offset, char val, Object locationIdentity) {
+        writeChar(signed(offset), val, locationIdentity);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE)
+    public void writeShort(int offset, short val, Object locationIdentity) {
+        writeShort(signed(offset), val, locationIdentity);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE)
+    public void writeInt(int offset, int val, Object locationIdentity) {
+        writeInt(signed(offset), val, locationIdentity);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE)
+    public void writeLong(int offset, long val, Object locationIdentity) {
+        writeLong(signed(offset), val, locationIdentity);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE)
+    public void writeFloat(int offset, float val, Object locationIdentity) {
+        writeFloat(signed(offset), val, locationIdentity);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE)
+    public void writeDouble(int offset, double val, Object locationIdentity) {
+        writeDouble(signed(offset), val, locationIdentity);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE)
+    public void writeWord(int offset, WordBase val, Object locationIdentity) {
+        writeWord(signed(offset), val, locationIdentity);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.WRITE)
+    public void writeObject(int offset, Object val, Object locationIdentity) {
+        writeObject(signed(offset), val, locationIdentity);
+    }
+
+    @Override
+    @Operation(opcode = Opcode.READ)
     public byte readByte(WordBase offset) {
         return unsafe.getByte(add((Word) offset).unbox());
     }
@@ -703,60 +914,6 @@
     }
 
     @Override
-    @Operation(opcode = Opcode.READ_FINAL)
-    public byte readFinalByte(WordBase offset) {
-        return readByte(offset);
-    }
-
-    @Override
-    @Operation(opcode = Opcode.READ_FINAL)
-    public char readFinalChar(WordBase offset) {
-        return readChar(offset);
-    }
-
-    @Override
-    @Operation(opcode = Opcode.READ_FINAL)
-    public short readFinalShort(WordBase offset) {
-        return readShort(offset);
-    }
-
-    @Override
-    @Operation(opcode = Opcode.READ_FINAL)
-    public int readFinalInt(WordBase offset) {
-        return readInt(offset);
-    }
-
-    @Override
-    @Operation(opcode = Opcode.READ_FINAL)
-    public long readFinalLong(WordBase offset) {
-        return readLong(offset);
-    }
-
-    @Override
-    @Operation(opcode = Opcode.READ_FINAL)
-    public float readFinalFloat(WordBase offset) {
-        return readFloat(offset);
-    }
-
-    @Override
-    @Operation(opcode = Opcode.READ_FINAL)
-    public double readFinalDouble(WordBase offset) {
-        return readDouble(offset);
-    }
-
-    @Override
-    @Operation(opcode = Opcode.READ_FINAL)
-    public Word readFinalWord(WordBase offset) {
-        return readWord(offset);
-    }
-
-    @Override
-    @Operation(opcode = Opcode.READ_FINAL)
-    public Object readFinalObject(WordBase offset) {
-        return readObject(offset);
-    }
-
-    @Override
     @Operation(opcode = Opcode.WRITE)
     public void writeByte(WordBase offset, byte val) {
         unsafe.putByte(add((Word) offset).unbox(), val);
@@ -770,7 +927,7 @@
 
     @Override
     @Operation(opcode = Opcode.WRITE)
-    public void writeShort(WordBase offset, Short val) {
+    public void writeShort(WordBase offset, short val) {
         unsafe.putShort(add((Word) offset).unbox(), val);
     }
 
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java	Fri Mar 01 17:05:14 2013 +0100
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java	Fri Mar 01 17:06:08 2013 +0100
@@ -138,18 +138,17 @@
                         break;
 
                     case READ:
-                        assert arguments.size() == 2;
-                        replace(invoke, readOp(graph, arguments.get(0), arguments.get(1), invoke, LocationNode.ANY_LOCATION));
-                        break;
-
-                    case READ_FINAL:
-                        assert arguments.size() == 2;
-                        replace(invoke, readOp(graph, arguments.get(0), arguments.get(1), invoke, LocationNode.FINAL_LOCATION));
+                        assert arguments.size() == 2 || arguments.size() == 3;
+                        Kind readKind = asKind(callTargetNode.returnType());
+                        Object readLocation = arguments.size() == 2 ? LocationNode.UNKNOWN_LOCATION : arguments.get(2).asConstant().asObject();
+                        replace(invoke, readOp(graph, arguments.get(0), arguments.get(1), invoke, readKind, readLocation));
                         break;
 
                     case WRITE:
-                        assert arguments.size() == 3;
-                        replace(invoke, writeOp(graph, arguments.get(0), arguments.get(1), arguments.get(2), invoke, LocationNode.ANY_LOCATION));
+                        assert arguments.size() == 3 || arguments.size() == 4;
+                        Kind writeKind = asKind(targetMethod.getSignature().getParameterType(1, targetMethod.getDeclaringClass()));
+                        Object writeLocation = arguments.size() == 3 ? LocationNode.ANY_LOCATION : arguments.get(3).asConstant().asObject();
+                        replace(invoke, writeOp(graph, arguments.get(0), arguments.get(1), arguments.get(2), invoke, writeKind, writeLocation));
                         break;
 
                     case ZERO:
@@ -259,8 +258,8 @@
         return op;
     }
 
-    private static ValueNode readOp(StructuredGraph graph, ValueNode base, ValueNode offset, Invoke invoke, Object locationIdentity) {
-        IndexedLocationNode location = IndexedLocationNode.create(locationIdentity, invoke.node().kind(), 0, offset, graph, 1);
+    private static ValueNode readOp(StructuredGraph graph, ValueNode base, ValueNode offset, Invoke invoke, Kind readKind, Object locationIdentity) {
+        IndexedLocationNode location = IndexedLocationNode.create(locationIdentity, readKind, 0, offset, graph, 1);
         ReadNode read = graph.add(new ReadNode(base, location, invoke.node().stamp()));
         graph.addBeforeFixed(invoke.node(), read);
         // The read must not float outside its block otherwise it may float above an explicit zero
@@ -269,9 +268,10 @@
         return read;
     }
 
-    private static ValueNode writeOp(StructuredGraph graph, ValueNode base, ValueNode offset, ValueNode value, Invoke invoke, Object locationIdentity) {
-        IndexedLocationNode location = IndexedLocationNode.create(locationIdentity, value.kind(), 0, offset, graph, 1);
+    private static ValueNode writeOp(StructuredGraph graph, ValueNode base, ValueNode offset, ValueNode value, Invoke invoke, Kind writeKind, Object locationIdentity) {
+        IndexedLocationNode location = IndexedLocationNode.create(locationIdentity, writeKind, 0, offset, graph, 1);
         WriteNode write = graph.add(new WriteNode(base, value, location));
+        write.setStateAfter(invoke.stateAfter());
         graph.addBeforeFixed(invoke.node(), write);
         return write;
     }
@@ -324,6 +324,14 @@
         return false;
     }
 
+    public Kind asKind(JavaType type) {
+        if (type instanceof ResolvedJavaType) {
+            return isWord((ResolvedJavaType) type) ? wordKind : type.getKind();
+        } else {
+            return Kind.Object;
+        }
+    }
+
     private void changeToWord(ValueNode valueNode) {
         if (valueNode.isConstant() && valueNode.asConstant().getKind() == Kind.Object) {
             WordBase value = (WordBase) valueNode.asConstant().asObject();