changeset 13153:ae0001b445c0

Common base interface for nodes in the memory graph.
author Roland Schatz <roland.schatz@oracle.com>
date Mon, 25 Nov 2013 17:10:22 +0100
parents 640516a8ca6b
children 1e22792abdbc
files graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DirectCompareAndSwapNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EndLockScopeNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/StubForeignCallNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractMemoryCheckpoint.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/KillingBeginNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryMapNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryPhiNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryProxyNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StartNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNodeUtil.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ArrayRangeWriteNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatableAccessNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MembarNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryAccess.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryCheckpoint.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoweredCompareAndSwapNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MemoryProxy.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ReadEliminationPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java
diffstat 34 files changed, 319 insertions(+), 104 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java	Mon Nov 25 17:06:00 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java	Mon Nov 25 17:10:22 2013 +0100
@@ -37,7 +37,7 @@
  * is locked (ensuring the GC sees and updates the object) so it must come after any null pointer
  * check on the object.
  */
-public final class BeginLockScopeNode extends AbstractStateSplit implements LIRGenLowerable, MonitorEnter, MemoryCheckpoint.Single {
+public final class BeginLockScopeNode extends AbstractMemoryCheckpoint implements LIRGenLowerable, MonitorEnter, MemoryCheckpoint.Single {
 
     private int lockDepth;
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DirectCompareAndSwapNode.java	Mon Nov 25 17:06:00 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DirectCompareAndSwapNode.java	Mon Nov 25 17:10:22 2013 +0100
@@ -95,4 +95,12 @@
      */
     @NodeIntrinsic
     public static native Word compareAndSwap(Object object, long offset, Word expectedValue, Word newValue, @ConstantNodeParameter LocationIdentity locationIdentity);
+
+    public MemoryCheckpoint asMemoryCheckpoint() {
+        return this;
+    }
+
+    public MemoryPhiNode asMemoryPhi() {
+        return null;
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EndLockScopeNode.java	Mon Nov 25 17:06:00 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EndLockScopeNode.java	Mon Nov 25 17:10:22 2013 +0100
@@ -33,7 +33,7 @@
  * Intrinsic for closing a {@linkplain BeginLockScopeNode scope} binding a stack-based lock with an
  * object.
  */
-public final class EndLockScopeNode extends AbstractStateSplit implements LIRGenLowerable, MonitorExit, MemoryCheckpoint.Single {
+public final class EndLockScopeNode extends AbstractMemoryCheckpoint implements LIRGenLowerable, MonitorExit, MemoryCheckpoint.Single {
 
     public EndLockScopeNode() {
         super(StampFactory.forVoid());
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/StubForeignCallNode.java	Mon Nov 25 17:06:00 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/StubForeignCallNode.java	Mon Nov 25 17:10:22 2013 +0100
@@ -83,4 +83,12 @@
         }
         return super.toString(verbosity);
     }
+
+    public MemoryCheckpoint asMemoryCheckpoint() {
+        return this;
+    }
+
+    public MemoryPhiNode asMemoryPhi() {
+        return null;
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractMemoryCheckpoint.java	Mon Nov 25 17:10:22 2013 +0100
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes;
+
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.type.*;
+
+/**
+ * Provides an implementation of {@link StateSplit}.
+ */
+public abstract class AbstractMemoryCheckpoint extends AbstractStateSplit implements MemoryCheckpoint {
+
+    protected AbstractMemoryCheckpoint(Stamp stamp) {
+        super(stamp);
+    }
+
+    protected AbstractMemoryCheckpoint(Stamp stamp, FrameState stateAfter) {
+        super(stamp, stateAfter);
+    }
+
+    public MemoryCheckpoint asMemoryCheckpoint() {
+        return this;
+    }
+
+    public MemoryPhiNode asMemoryPhi() {
+        return null;
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java	Mon Nov 25 17:06:00 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java	Mon Nov 25 17:10:22 2013 +0100
@@ -35,7 +35,7 @@
  * The {@code InvokeNode} represents all kinds of method calls.
  */
 @NodeInfo(nameTemplate = "Invoke#{p#targetMethod/s}")
-public final class InvokeNode extends AbstractStateSplit implements Invoke, LIRLowerable, MemoryCheckpoint.Single {
+public final class InvokeNode extends AbstractMemoryCheckpoint implements Invoke, LIRLowerable, MemoryCheckpoint.Single {
 
     @Input private CallTargetNode callTarget;
     @Input private FrameState deoptState;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Mon Nov 25 17:06:00 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Mon Nov 25 17:10:22 2013 +0100
@@ -253,4 +253,12 @@
             return stateAfter();
         }
     }
+
+    public MemoryCheckpoint asMemoryCheckpoint() {
+        return this;
+    }
+
+    public MemoryPhiNode asMemoryPhi() {
+        return null;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/KillingBeginNode.java	Mon Nov 25 17:06:00 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/KillingBeginNode.java	Mon Nov 25 17:10:22 2013 +0100
@@ -46,4 +46,12 @@
     public LocationIdentity getLocationIdentity() {
         return locationIdentity;
     }
+
+    public MemoryCheckpoint asMemoryCheckpoint() {
+        return this;
+    }
+
+    public MemoryPhiNode asMemoryPhi() {
+        return null;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryMapNode.java	Mon Nov 25 17:06:00 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryMapNode.java	Mon Nov 25 17:10:22 2013 +0100
@@ -23,8 +23,8 @@
 package com.oracle.graal.nodes;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.type.*;
 
 public abstract class MemoryMapNode extends FloatingNode {
@@ -33,5 +33,5 @@
         super(StampFactory.forVoid());
     }
 
-    public abstract Node getLastLocationAccess(LocationIdentity locationIdentity);
+    public abstract MemoryNode getLastLocationAccess(LocationIdentity locationIdentity);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryPhiNode.java	Mon Nov 25 17:06:00 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryPhiNode.java	Mon Nov 25 17:10:22 2013 +0100
@@ -23,11 +23,12 @@
 package com.oracle.graal.nodes;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.extended.*;
 
 /**
  * The {@code PhiNode} represents the merging of dataflow in the memory graph.
  */
-public class MemoryPhiNode extends PhiNode {
+public class MemoryPhiNode extends PhiNode implements MemoryNode {
 
     private final LocationIdentity identity;
 
@@ -39,4 +40,12 @@
     public LocationIdentity getLocationIdentity() {
         return identity;
     }
+
+    public MemoryCheckpoint asMemoryCheckpoint() {
+        return null;
+    }
+
+    public MemoryPhiNode asMemoryPhi() {
+        return this;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryProxyNode.java	Mon Nov 25 17:06:00 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryProxyNode.java	Mon Nov 25 17:10:22 2013 +0100
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.PhiNode.PhiType;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 
 public class MemoryProxyNode extends ProxyNode implements MemoryProxy, LIRLowerable {
@@ -32,6 +33,7 @@
 
     public MemoryProxyNode(ValueNode value, AbstractBeginNode exit, LocationIdentity identity) {
         super(value, exit, PhiType.Memory);
+        assert value instanceof MemoryNode;
         this.identity = identity;
     }
 
@@ -43,7 +45,25 @@
     public void generate(LIRGeneratorTool generator) {
     }
 
-    public static MemoryProxyNode forMemory(ValueNode value, AbstractBeginNode exit, LocationIdentity location, StructuredGraph graph) {
-        return graph.unique(new MemoryProxyNode(value, exit, location));
+    @Override
+    public boolean verify() {
+        assert value() instanceof MemoryNode;
+        return super.verify();
+    }
+
+    public static MemoryProxyNode forMemory(MemoryNode value, AbstractBeginNode exit, LocationIdentity location, StructuredGraph graph) {
+        return graph.unique(new MemoryProxyNode(ValueNodeUtil.asNode(value), exit, location));
+    }
+
+    public MemoryNode getOriginalMemoryNode() {
+        return (MemoryNode) value();
+    }
+
+    public MemoryCheckpoint asMemoryCheckpoint() {
+        return getOriginalMemoryNode().asMemoryCheckpoint();
+    }
+
+    public MemoryPhiNode asMemoryPhi() {
+        return getOriginalMemoryNode().asMemoryPhi();
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StartNode.java	Mon Nov 25 17:06:00 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StartNode.java	Mon Nov 25 17:10:22 2013 +0100
@@ -34,4 +34,12 @@
     public LocationIdentity getLocationIdentity() {
         return LocationIdentity.ANY_LOCATION;
     }
+
+    public MemoryCheckpoint asMemoryCheckpoint() {
+        return this;
+    }
+
+    public MemoryPhiNode asMemoryPhi() {
+        return null;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNodeUtil.java	Mon Nov 25 17:06:00 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNodeUtil.java	Mon Nov 25 17:10:22 2013 +0100
@@ -27,6 +27,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Node.Verbosity;
+import com.oracle.graal.nodes.extended.*;
 
 public class ValueNodeUtil {
 
@@ -95,4 +96,12 @@
     public static String valueString(ValueNode value) {
         return (value == null) ? "-" : ("" + value.kind().getTypeChar() + value.toString(Verbosity.Id));
     }
+
+    public static ValueNode asNode(MemoryNode node) {
+        if (node == null) {
+            return null;
+        } else {
+            return node.asNode();
+        }
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ArrayRangeWriteNode.java	Mon Nov 25 17:06:00 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ArrayRangeWriteNode.java	Mon Nov 25 17:10:22 2013 +0100
@@ -28,7 +28,7 @@
 /**
  * Base class for nodes that modify a range of an array.
  */
-public abstract class ArrayRangeWriteNode extends AbstractStateSplit {
+public abstract class ArrayRangeWriteNode extends AbstractMemoryCheckpoint {
 
     protected ArrayRangeWriteNode(Stamp stamp) {
         super(stamp);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatableAccessNode.java	Mon Nov 25 17:06:00 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatableAccessNode.java	Mon Nov 25 17:10:22 2013 +0100
@@ -43,7 +43,7 @@
         super(object, location, stamp, barrierType, compressible);
     }
 
-    public abstract FloatingAccessNode asFloatingNode(ValueNode lastLocationAccess);
+    public abstract FloatingAccessNode asFloatingNode(MemoryNode lastLocationAccess);
 
     /**
      * AccessNodes can float only if their location identities are not ANY_LOCATION. Furthermore, in
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java	Mon Nov 25 17:06:00 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java	Mon Nov 25 17:10:22 2013 +0100
@@ -26,7 +26,6 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.PhiNode.PhiType;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -36,27 +35,27 @@
  */
 public final class FloatingReadNode extends FloatingAccessNode implements IterableNodeType, LIRLowerable, Canonicalizable {
 
-    @Input private Node lastLocationAccess;
+    @Input private MemoryNode lastLocationAccess;
 
-    public FloatingReadNode(ValueNode object, LocationNode location, Node lastLocationAccess, Stamp stamp) {
+    public FloatingReadNode(ValueNode object, LocationNode location, MemoryNode lastLocationAccess, Stamp stamp) {
         this(object, location, lastLocationAccess, stamp, null, BarrierType.NONE, false);
     }
 
-    public FloatingReadNode(ValueNode object, LocationNode location, Node lastLocationAccess, Stamp stamp, GuardingNode guard) {
+    public FloatingReadNode(ValueNode object, LocationNode location, MemoryNode lastLocationAccess, Stamp stamp, GuardingNode guard) {
         this(object, location, lastLocationAccess, stamp, guard, BarrierType.NONE, false);
     }
 
-    public FloatingReadNode(ValueNode object, LocationNode location, Node lastLocationAccess, Stamp stamp, GuardingNode guard, BarrierType barrierType, boolean compressible) {
+    public FloatingReadNode(ValueNode object, LocationNode location, MemoryNode lastLocationAccess, Stamp stamp, GuardingNode guard, BarrierType barrierType, boolean compressible) {
         super(object, location, stamp, guard, barrierType, compressible);
         this.lastLocationAccess = lastLocationAccess;
     }
 
-    public Node getLastLocationAccess() {
+    public MemoryNode getLastLocationAccess() {
         return lastLocationAccess;
     }
 
-    public void setLastLocationAccess(Node newlla) {
-        updateUsages(lastLocationAccess, newlla);
+    public void setLastLocationAccess(MemoryNode newlla) {
+        updateUsages(ValueNodeUtil.asNode(lastLocationAccess), ValueNodeUtil.asNode(newlla));
         lastLocationAccess = newlla;
     }
 
@@ -76,22 +75,10 @@
         return graph().add(new ReadNode(object(), nullCheckLocation(), stamp(), getGuard(), getBarrierType(), isCompressible()));
     }
 
-    private static boolean isMemoryCheckPoint(Node n) {
-        return n instanceof MemoryCheckpoint.Single || n instanceof MemoryCheckpoint.Multi;
-    }
-
-    private static boolean isMemoryPhi(Node n) {
-        return n instanceof PhiNode && ((PhiNode) n).type() == PhiType.Memory;
-    }
-
-    private static boolean isMemoryProxy(Node n) {
-        return n instanceof ProxyNode && ((ProxyNode) n).type() == PhiType.Memory;
-    }
-
     @Override
     public boolean verify() {
-        Node lla = getLastLocationAccess();
-        assert lla == null || isMemoryCheckPoint(lla) || isMemoryPhi(lla) || isMemoryProxy(lla) : "lastLocationAccess of " + this + " should be a MemoryCheckpoint, but is " + lla;
+        MemoryNode lla = getLastLocationAccess();
+        assert lla == null || lla.asMemoryCheckpoint() != null || lla.asMemoryPhi() != null : "lastLocationAccess of " + this + " should be a MemoryCheckpoint, but is " + lla;
         return super.verify();
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java	Mon Nov 25 17:06:00 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java	Mon Nov 25 17:10:22 2013 +0100
@@ -33,7 +33,7 @@
  * Node for a {@linkplain ForeignCallDescriptor foreign} call.
  */
 @NodeInfo(nameTemplate = "ForeignCall#{p#descriptor/s}")
-public class ForeignCallNode extends AbstractStateSplit implements LIRLowerable, DeoptimizingNode, MemoryCheckpoint.Multi {
+public class ForeignCallNode extends AbstractMemoryCheckpoint implements LIRLowerable, DeoptimizingNode, MemoryCheckpoint.Multi {
 
     @Input private final NodeInputList<ValueNode> arguments;
     private final ForeignCallsProvider foreignCalls;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MembarNode.java	Mon Nov 25 17:06:00 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MembarNode.java	Mon Nov 25 17:10:22 2013 +0100
@@ -60,6 +60,14 @@
         generator.emitMembar(barriers);
     }
 
+    public MemoryCheckpoint asMemoryCheckpoint() {
+        return this;
+    }
+
+    public MemoryPhiNode asMemoryPhi() {
+        return null;
+    }
+
     @SuppressWarnings("unused")
     @NodeIntrinsic
     public static void memoryBarrier(@ConstantNodeParameter int barriers) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryAccess.java	Mon Nov 25 17:06:00 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryAccess.java	Mon Nov 25 17:10:22 2013 +0100
@@ -23,7 +23,6 @@
 package com.oracle.graal.nodes.extended;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
 
 /**
  * This interface marks nodes that access some memory location, and that have an edge to the last
@@ -33,7 +32,7 @@
 
     LocationIdentity getLocationIdentity();
 
-    Node getLastLocationAccess();
+    MemoryNode getLastLocationAccess();
 
-    void setLastLocationAccess(Node lla);
+    void setLastLocationAccess(MemoryNode lla);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryCheckpoint.java	Mon Nov 25 17:06:00 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryCheckpoint.java	Mon Nov 25 17:10:22 2013 +0100
@@ -31,7 +31,9 @@
  * represented by location identities (i.e. change a value at one or more locations that belong to
  * these location identities).
  */
-public interface MemoryCheckpoint {
+public interface MemoryCheckpoint extends MemoryNode {
+
+    FixedNode asNode();
 
     interface Single extends MemoryCheckpoint {
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryNode.java	Mon Nov 25 17:10:22 2013 +0100
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes.extended;
+
+import com.oracle.graal.nodes.*;
+
+/**
+ * This interface marks nodes that are part of the memory graph.
+ */
+public interface MemoryNode {
+
+    ValueNode asNode();
+
+    MemoryCheckpoint asMemoryCheckpoint();
+
+    MemoryPhiNode asMemoryPhi();
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java	Mon Nov 25 17:06:00 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java	Mon Nov 25 17:10:22 2013 +0100
@@ -64,7 +64,7 @@
     }
 
     @Override
-    public FloatingAccessNode asFloatingNode(ValueNode lastLocationAccess) {
+    public FloatingAccessNode asFloatingNode(MemoryNode lastLocationAccess) {
         return graph().unique(new FloatingReadNode(object(), location(), lastLocationAccess, stamp(), getGuard(), getBarrierType(), isCompressible()));
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java	Mon Nov 25 17:06:00 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java	Mon Nov 25 17:10:22 2013 +0100
@@ -111,6 +111,14 @@
         return stateAfter;
     }
 
+    public MemoryCheckpoint asMemoryCheckpoint() {
+        return this;
+    }
+
+    public MemoryPhiNode asMemoryPhi() {
+        return null;
+    }
+
     // specialized on value type until boxing/unboxing is sorted out in intrinsification
 
     @SuppressWarnings("unused")
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java	Mon Nov 25 17:06:00 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java	Mon Nov 25 17:10:22 2013 +0100
@@ -102,13 +102,14 @@
         return location().getLocationIdentity();
     }
 
-    public Node getLastLocationAccess() {
-        return lastLocationAccess;
+    public MemoryNode getLastLocationAccess() {
+        return (MemoryNode) lastLocationAccess;
     }
 
-    public void setLastLocationAccess(Node lla) {
-        updateUsages(lastLocationAccess, lla);
-        lastLocationAccess = lla;
+    public void setLastLocationAccess(MemoryNode lla) {
+        Node newLla = ValueNodeUtil.asNode(lla);
+        updateUsages(lastLocationAccess, newLla);
+        lastLocationAccess = newLla;
     }
 
     @Override
@@ -126,4 +127,12 @@
             }
         }
     }
+
+    public MemoryCheckpoint asMemoryCheckpoint() {
+        return this;
+    }
+
+    public MemoryPhiNode asMemoryPhi() {
+        return null;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java	Mon Nov 25 17:06:00 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java	Mon Nov 25 17:10:22 2013 +0100
@@ -33,7 +33,7 @@
  * The Java bytecode specification allows non-balanced locking. Graal does not handle such cases and
  * throws a {@link BailoutException} instead during graph building.
  */
-public abstract class AccessMonitorNode extends AbstractStateSplit implements MemoryCheckpoint {
+public abstract class AccessMonitorNode extends AbstractMemoryCheckpoint implements MemoryCheckpoint {
 
     @Input private ValueNode object;
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java	Mon Nov 25 17:06:00 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java	Mon Nov 25 17:10:22 2013 +0100
@@ -34,7 +34,7 @@
  * Represents an atomic compare-and-swap operation The result is a boolean that contains whether the
  * value matched the expected value.
  */
-public class CompareAndSwapNode extends AbstractStateSplit implements Lowerable, MemoryCheckpoint.Single {
+public class CompareAndSwapNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single {
 
     @Input private ValueNode object;
     @Input private ValueNode offset;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java	Mon Nov 25 17:06:00 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java	Mon Nov 25 17:10:22 2013 +0100
@@ -101,4 +101,12 @@
         assertTrue(stateAfter() != null || stamp() == StampFactory.forVoid(), "an exception handler needs a frame state");
         return super.verify();
     }
+
+    public MemoryCheckpoint asMemoryCheckpoint() {
+        return this;
+    }
+
+    public MemoryPhiNode asMemoryPhi() {
+        return null;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoweredCompareAndSwapNode.java	Mon Nov 25 17:06:00 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoweredCompareAndSwapNode.java	Mon Nov 25 17:10:22 2013 +0100
@@ -75,4 +75,12 @@
     public void generate(LIRGeneratorTool gen) {
         gen.visitCompareAndSwap(this, location().generateAddress(gen, gen.operand(object())));
     }
+
+    public MemoryCheckpoint asMemoryCheckpoint() {
+        return this;
+    }
+
+    public MemoryPhiNode asMemoryPhi() {
+        return null;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MemoryProxy.java	Mon Nov 25 17:06:00 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MemoryProxy.java	Mon Nov 25 17:10:22 2013 +0100
@@ -23,8 +23,11 @@
 package com.oracle.graal.nodes.spi;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.extended.*;
 
-public interface MemoryProxy extends ValueProxy {
+public interface MemoryProxy extends ValueProxy, MemoryNode {
 
     LocationIdentity getLocationIdentity();
+
+    MemoryNode getOriginalMemoryNode();
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java	Mon Nov 25 17:06:00 2013 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java	Mon Nov 25 17:10:22 2013 +0100
@@ -42,7 +42,7 @@
 
     public static class MemoryMapImpl extends MemoryMapNode {
 
-        private IdentityHashMap<LocationIdentity, ValueNode> lastMemorySnapshot;
+        private IdentityHashMap<LocationIdentity, MemoryNode> lastMemorySnapshot;
 
         public MemoryMapImpl(MemoryMapImpl memoryMap) {
             lastMemorySnapshot = new IdentityHashMap<>(memoryMap.lastMemorySnapshot);
@@ -58,8 +58,8 @@
         }
 
         @Override
-        public ValueNode getLastLocationAccess(LocationIdentity locationIdentity) {
-            ValueNode lastLocationAccess;
+        public MemoryNode getLastLocationAccess(LocationIdentity locationIdentity) {
+            MemoryNode lastLocationAccess;
             if (locationIdentity == FINAL_LOCATION) {
                 return null;
             } else {
@@ -197,7 +197,7 @@
         private static void processAccess(MemoryAccess access, MemoryMapImpl state) {
             LocationIdentity locationIdentity = access.getLocationIdentity();
             if (locationIdentity != LocationIdentity.ANY_LOCATION) {
-                ValueNode lastLocationAccess = state.getLastLocationAccess(locationIdentity);
+                MemoryNode lastLocationAccess = state.getLastLocationAccess(locationIdentity);
                 access.setLastLocationAccess(lastLocationAccess);
             }
         }
@@ -216,7 +216,7 @@
             if (identity == ANY_LOCATION) {
                 state.lastMemorySnapshot.clear();
             }
-            state.lastMemorySnapshot.put(identity, (ValueNode) checkpoint);
+            state.lastMemorySnapshot.put(identity, checkpoint);
         }
 
         private static void processFloatable(FloatableAccessNode accessNode, MemoryMapImpl state) {
@@ -224,7 +224,7 @@
             assert accessNode.getNullCheck() == false;
             LocationIdentity locationIdentity = accessNode.location().getLocationIdentity();
             if (accessNode.canFloat()) {
-                ValueNode lastLocationAccess = state.getLastLocationAccess(locationIdentity);
+                MemoryNode lastLocationAccess = state.getLastLocationAccess(locationIdentity);
                 FloatingAccessNode floatingNode = accessNode.asFloatingNode(lastLocationAccess);
                 floatingNode.setNullCheck(accessNode.getNullCheck());
                 ValueAnchorNode anchor = null;
@@ -250,11 +250,11 @@
             for (LocationIdentity key : keys) {
                 int mergedStatesCount = 0;
                 boolean isPhi = false;
-                ValueNode merged = null;
+                MemoryNode merged = null;
                 for (MemoryMapImpl state : states) {
-                    ValueNode last = state.getLastLocationAccess(key);
+                    MemoryNode last = state.getLastLocationAccess(key);
                     if (isPhi) {
-                        ((PhiNode) merged).addInput(last);
+                        merged.asMemoryPhi().addInput(ValueNodeUtil.asNode(last));
                     } else {
                         if (merged == last) {
                             // nothing to do
@@ -263,9 +263,9 @@
                         } else {
                             MemoryPhiNode phi = merge.graph().addWithoutUnique(new MemoryPhiNode(merge, key));
                             for (int j = 0; j < mergedStatesCount; j++) {
-                                phi.addInput(merged);
+                                phi.addInput(ValueNodeUtil.asNode(merged));
                             }
-                            phi.addInput(last);
+                            phi.addInput(ValueNodeUtil.asNode(last));
                             merged = phi;
                             isPhi = true;
                         }
@@ -289,7 +289,7 @@
                  * side it needs to choose by putting in the location identity on both successors.
                  */
                 InvokeWithExceptionNode invoke = (InvokeWithExceptionNode) node.predecessor();
-                result.lastMemorySnapshot.put(invoke.getLocationIdentity(), node);
+                result.lastMemorySnapshot.put(invoke.getLocationIdentity(), (MemoryCheckpoint) node);
             }
             return result;
         }
@@ -306,7 +306,7 @@
             Map<LocationIdentity, PhiNode> phis = new HashMap<>();
             for (LocationIdentity location : modifiedLocations) {
                 MemoryPhiNode phi = loop.graph().addWithoutUnique(new MemoryPhiNode(loop, location));
-                phi.addInput(initialState.getLastLocationAccess(location));
+                phi.addInput(ValueNodeUtil.asNode(initialState.getLastLocationAccess(location)));
                 phis.put(location, phi);
                 initialState.lastMemorySnapshot.put(location, phi);
             }
@@ -318,14 +318,14 @@
                 for (Map.Entry<LocationIdentity, PhiNode> phiEntry : phis.entrySet()) {
                     LocationIdentity key = phiEntry.getKey();
                     PhiNode phi = phiEntry.getValue();
-                    phi.initializeValueAt(endIndex, entry.getValue().getLastLocationAccess(key));
+                    phi.initializeValueAt(endIndex, ValueNodeUtil.asNode(entry.getValue().getLastLocationAccess(key)));
                 }
             }
             for (Map.Entry<LoopExitNode, MemoryMapImpl> entry : loopInfo.exitStates.entrySet()) {
                 LoopExitNode exit = entry.getKey();
                 MemoryMapImpl state = entry.getValue();
                 for (LocationIdentity location : modifiedLocations) {
-                    ValueNode lastAccessAtExit = state.lastMemorySnapshot.get(location);
+                    MemoryNode lastAccessAtExit = state.lastMemorySnapshot.get(location);
                     if (lastAccessAtExit != null) {
                         state.lastMemorySnapshot.put(location, MemoryProxyNode.forMemory(lastAccessAtExit, exit, location, loop.graph()));
                     }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ReadEliminationPhase.java	Mon Nov 25 17:06:00 2013 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ReadEliminationPhase.java	Mon Nov 25 17:10:22 2013 +0100
@@ -46,24 +46,24 @@
         return isWrites(n, n.getLastLocationAccess(), n.graph().createNodeBitMap());
     }
 
-    private static boolean isWrites(FloatingReadNode n, Node lastLocationAccess, NodeBitMap visited) {
+    private static boolean isWrites(FloatingReadNode n, MemoryNode lastLocationAccess, NodeBitMap visited) {
         if (lastLocationAccess == null) {
             return false;
         }
-        if (visited.isMarked(lastLocationAccess)) {
+        if (visited.isMarked(ValueNodeUtil.asNode(lastLocationAccess))) {
             return true; // dataflow loops must come from Phis assume them ok until proven wrong
         }
         if (lastLocationAccess instanceof ProxyNode) {
-            return isWrites(n, ((ProxyNode) lastLocationAccess).value(), visited);
+            return isWrites(n, (MemoryNode) ((ProxyNode) lastLocationAccess).value(), visited);
         }
         if (lastLocationAccess instanceof WriteNode) {
             WriteNode other = (WriteNode) lastLocationAccess;
             return other.object() == n.object() && other.location() == n.location();
         }
         if (lastLocationAccess instanceof PhiNode) {
-            visited.mark(lastLocationAccess);
+            visited.mark(ValueNodeUtil.asNode(lastLocationAccess));
             for (ValueNode value : ((PhiNode) lastLocationAccess).values()) {
-                if (!isWrites(n, value, visited)) {
+                if (!isWrites(n, (MemoryNode) value, visited)) {
                     return false;
                 }
             }
@@ -72,15 +72,15 @@
         return false;
     }
 
-    private static ValueNode getValue(FloatingReadNode n, Node lastLocationAccess, NodeMap<ValueNode> nodeMap) {
-        ValueNode exisiting = nodeMap.get(lastLocationAccess);
+    private static ValueNode getValue(FloatingReadNode n, MemoryNode lastLocationAccess, NodeMap<ValueNode> nodeMap) {
+        ValueNode exisiting = nodeMap.get(ValueNodeUtil.asNode(lastLocationAccess));
         if (exisiting != null) {
             return exisiting;
         }
-        if (lastLocationAccess instanceof ProxyNode) {
-            ProxyNode proxy = (ProxyNode) lastLocationAccess;
-            ValueNode value = getValue(n, proxy.value(), nodeMap);
-            return ProxyNode.forValue(value, proxy.proxyPoint(), (StructuredGraph) lastLocationAccess.graph());
+        if (lastLocationAccess instanceof MemoryProxyNode) {
+            MemoryProxyNode proxy = (MemoryProxyNode) lastLocationAccess;
+            ValueNode value = getValue(n, proxy.getOriginalMemoryNode(), nodeMap);
+            return ProxyNode.forValue(value, proxy.proxyPoint(), proxy.graph());
         }
         if (lastLocationAccess instanceof WriteNode) {
             return ((WriteNode) lastLocationAccess).value();
@@ -88,9 +88,9 @@
         if (lastLocationAccess instanceof PhiNode) {
             PhiNode phi = (PhiNode) lastLocationAccess;
             PhiNode newPhi = phi.graph().addWithoutUnique(new PhiNode(n.kind(), phi.merge()));
-            nodeMap.set(lastLocationAccess, newPhi);
+            nodeMap.set(phi, newPhi);
             for (ValueNode value : phi.values()) {
-                newPhi.addInput(getValue(n, value, nodeMap));
+                newPhi.addInput(getValue(n, (MemoryNode) value, nodeMap));
             }
             return newPhi;
         }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Mon Nov 25 17:06:00 2013 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Mon Nov 25 17:10:22 2013 +0100
@@ -400,8 +400,12 @@
         }
     }
 
-    private Block blockForFixedNode(Node n) {
-        Block b = cfg.getNodeToBlock().get(n);
+    private Block blockForMemoryNode(MemoryNode memory) {
+        MemoryNode current = memory;
+        while (current instanceof MemoryProxy) {
+            current = ((MemoryProxy) current).getOriginalMemoryNode();
+        }
+        Block b = cfg.getNodeToBlock().get(current.asNode());
         assert b != null : "all lastAccess locations should have a block assignment from CFG";
         return b;
     }
@@ -543,13 +547,11 @@
                 if (assertionEnabled()) {
                     if (scheduleRead) {
                         FloatingReadNode read = (FloatingReadNode) node;
-                        Node lastLocationAccess = read.getLastLocationAccess();
-                        Block upperBound = blockForFixedNode(lastLocationAccess);
-                        if (!blockForFixedNode(lastLocationAccess).dominates(block)) {
-                            assert false : String.format("out of loop movement voilated memory semantics for %s (location %s). moved to %s but upper bound is %s (earliest: %s, latest: %s)", read,
-                                            read.getLocationIdentity(), block, upperBound, earliestBlock, latest);
-                        }
-
+                        MemoryNode lastLocationAccess = read.getLastLocationAccess();
+                        Block upperBound = blockForMemoryNode(lastLocationAccess);
+                        assert upperBound.dominates(block) : String.format(
+                                        "out of loop movement voilated memory semantics for %s (location %s). moved to %s but upper bound is %s (earliest: %s, latest: %s)", read,
+                                        read.getLocationIdentity(), block, upperBound, earliestBlock, latest);
                     }
                 }
                 break;
@@ -596,7 +598,7 @@
         LocationIdentity locid = n.location().getLocationIdentity();
         assert locid != FINAL_LOCATION;
 
-        Block upperBoundBlock = blockForFixedNode(n.getLastLocationAccess());
+        Block upperBoundBlock = blockForMemoryNode(n.getLastLocationAccess());
         Block earliestBlock = earliestBlock(n);
         assert upperBoundBlock.dominates(earliestBlock) : "upper bound (" + upperBoundBlock + ") should dominate earliest (" + earliestBlock + ")";
 
@@ -627,7 +629,7 @@
                 if (currentBlock == upperBoundBlock) {
                     assert earliestBlock == upperBoundBlock;
                     // don't treat lastLocationAccess node as a kill for this read.
-                    closure = new NewMemoryScheduleClosure(n.getLastLocationAccess(), upperBoundBlock);
+                    closure = new NewMemoryScheduleClosure(ValueNodeUtil.asNode(n.getLastLocationAccess()), upperBoundBlock);
                 } else {
                     closure = new NewMemoryScheduleClosure();
                 }
@@ -643,7 +645,7 @@
             } else {
                 if (currentBlock == upperBoundBlock) {
                     assert earliestBlock == upperBoundBlock;
-                    KillSet ks = computeKillSet(upperBoundBlock, n.getLastLocationAccess());
+                    KillSet ks = computeKillSet(upperBoundBlock, ValueNodeUtil.asNode(n.getLastLocationAccess()));
                     if (ks.isKilled(locid)) {
                         return upperBoundBlock;
                     }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Mon Nov 25 17:06:00 2013 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Mon Nov 25 17:10:22 2013 +0100
@@ -854,25 +854,43 @@
      */
     public static final UsageReplacer DEFAULT_REPLACER = new UsageReplacer() {
 
+        private LocationIdentity getLocationIdentity(Node node) {
+            if (node instanceof MemoryAccess) {
+                return ((MemoryAccess) node).getLocationIdentity();
+            } else if (node instanceof MemoryProxy) {
+                return ((MemoryProxy) node).getLocationIdentity();
+            } else if (node instanceof MemoryPhiNode) {
+                return ((MemoryPhiNode) node).getLocationIdentity();
+            } else {
+                return null;
+            }
+        }
+
         @Override
         public void replace(ValueNode oldNode, ValueNode newNode, MemoryMapNode mmap) {
-            oldNode.replaceAtUsages(newNode);
-            if (mmap == null || newNode == null) {
-                return;
-            }
-            for (Node usage : newNode.usages().snapshot()) {
-                if (usage instanceof FloatingReadNode && ((FloatingReadNode) usage).getLastLocationAccess() == newNode) {
-                    assert newNode.graph().isAfterFloatingReadPhase();
+            if (mmap != null && newNode != null) {
+                for (Node usage : oldNode.usages().snapshot()) {
+                    LocationIdentity identity = getLocationIdentity(usage);
+                    if (identity != null && identity != LocationIdentity.FINAL_LOCATION) {
+                        // lastLocationAccess points into the snippet graph. find a proper
+                        // MemoryCheckPoint inside the snippet graph
+                        MemoryNode lastAccess = mmap.getLastLocationAccess(identity);
 
-                    // lastLocationAccess points into the snippet graph. find a proper
-                    // MemoryCheckPoint inside the snippet graph
-                    FloatingReadNode read = (FloatingReadNode) usage;
-                    Node lastAccess = mmap.getLastLocationAccess(read.location().getLocationIdentity());
-
-                    assert lastAccess != null : "no mapping found for lowerable node " + oldNode + ". (No node in the snippet kill the same location as the lowerable node?)";
-                    read.setLastLocationAccess(lastAccess);
+                        assert lastAccess != null : "no mapping found for lowerable node " + oldNode + ". (No node in the snippet kill the same location as the lowerable node?)";
+                        if (usage instanceof MemoryAccess) {
+                            MemoryAccess access = (MemoryAccess) usage;
+                            if (access.getLastLocationAccess() == oldNode) {
+                                assert newNode.graph().isAfterFloatingReadPhase();
+                                access.setLastLocationAccess(lastAccess);
+                            }
+                        } else {
+                            assert usage instanceof MemoryProxy || usage instanceof MemoryPhiNode;
+                            usage.replaceFirstInput(oldNode, lastAccess.asNode());
+                        }
+                    }
                 }
             }
+            oldNode.replaceAtUsages(newNode);
         }
     };
 
@@ -933,14 +951,14 @@
         }
 
         @Override
-        public Node getLastLocationAccess(LocationIdentity locationIdentity) {
+        public MemoryNode getLastLocationAccess(LocationIdentity locationIdentity) {
             assert memoryMap != null : "no memory map stored for this snippet graph (snippet doesn't have a ReturnNode?)";
-            Node lastLocationAccess = memoryMap.getLastLocationAccess(locationIdentity);
+            MemoryNode lastLocationAccess = memoryMap.getLastLocationAccess(locationIdentity);
             assert lastLocationAccess != null;
             if (lastLocationAccess instanceof StartNode) {
                 return replaceeStart;
             } else {
-                return duplicates.get(lastLocationAccess);
+                return (MemoryNode) duplicates.get(ValueNodeUtil.asNode(lastLocationAccess));
             }
         }
     }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Mon Nov 25 17:06:00 2013 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Mon Nov 25 17:10:22 2013 +0100
@@ -37,7 +37,7 @@
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
 
-public class MacroNode extends AbstractStateSplit implements Lowerable, MemoryCheckpoint.Single {
+public class MacroNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single {
 
     @Input protected final NodeInputList<ValueNode> arguments;