changeset 11926:e04a86167368

Add support for unsafe access in early read elimination.
author Thomas Wuerthinger <thomas.wuerthinger@oracle.com>
date Mon, 07 Oct 2013 02:40:08 +0200
parents fe71a5ed24c2
children 776e348d6c2e
files graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ObjectLocationIdentity.java graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaField.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeLoadMacroNode.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeLoadNode.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeStoreMacroNode.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeStoreNode.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/CompilerDirectivesSubstitutions.java graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationBlockState.java graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java
diffstat 11 files changed, 220 insertions(+), 268 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ObjectLocationIdentity.java	Mon Oct 07 01:25:49 2013 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ObjectLocationIdentity.java	Mon Oct 07 02:40:08 2013 +0200
@@ -22,31 +22,31 @@
  */
 package com.oracle.graal.api.meta;
 
+import java.util.*;
+
 /**
  * A {@link LocationIdentity} warpping an object.
  */
-public class ObjectLocationIdentity implements LocationIdentity {
+public final class ObjectLocationIdentity implements LocationIdentity {
+
+    private static IdentityHashMap<Object, LocationIdentity> map = new IdentityHashMap<>();
 
     private Object object;
 
-    public ObjectLocationIdentity(Object object) {
-        this.object = object;
+    public static LocationIdentity create(Object object) {
+        synchronized (map) {
+            if (map.containsKey(object)) {
+                return map.get(object);
+            } else {
+                ObjectLocationIdentity locationIdentity = new ObjectLocationIdentity(object);
+                map.put(object, locationIdentity);
+                return locationIdentity;
+            }
+        }
     }
 
-    @Override
-    public boolean equals(Object other) {
-        if (other == this) {
-            return true;
-        } else if (other instanceof ObjectLocationIdentity) {
-            ObjectLocationIdentity objectLocationIdentity = (ObjectLocationIdentity) other;
-            return objectLocationIdentity.object == object;
-        }
-        return false;
-    }
-
-    @Override
-    public int hashCode() {
-        return object.hashCode();
+    private ObjectLocationIdentity(Object object) {
+        this.object = object;
     }
 
     @Override
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaField.java	Mon Oct 07 01:25:49 2013 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaField.java	Mon Oct 07 02:40:08 2013 +0200
@@ -29,7 +29,7 @@
  * Represents a reference to a resolved Java field. Fields, like methods and types, are resolved
  * through {@link ConstantPool constant pools}.
  */
-public interface ResolvedJavaField extends JavaField {
+public interface ResolvedJavaField extends JavaField, LocationIdentity {
 
     /**
      * Returns the Java language modifiers for this field, as an integer. The {@link Modifier} class
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java	Mon Oct 07 01:25:49 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java	Mon Oct 07 02:40:08 2013 +0200
@@ -43,18 +43,6 @@
         super(object, location, stamp, guard, barrierType, compressible);
     }
 
-    public ReadNode(ValueNode object, int displacement, LocationIdentity locationIdentity, Kind kind) {
-        super(object, ConstantLocationNode.create(locationIdentity, kind, displacement, object.graph()), StampFactory.forKind(kind));
-    }
-
-    private ReadNode(ValueNode object, ValueNode location, ValueNode guard) {
-        /*
-         * Used by node intrinsics. Since the initial value for location is a parameter, i.e., a
-         * LocalNode, the constructor cannot use the declared type LocationNode.
-         */
-        super(object, location, StampFactory.forNodeIntrinsic(), (GuardingNode) guard, BarrierType.NONE, false);
-    }
-
     @Override
     public void generate(LIRGeneratorTool gen) {
         Value address = location().generateAddress(gen, gen.operand(object()));
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java	Mon Oct 07 01:25:49 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java	Mon Oct 07 02:40:08 2013 +0200
@@ -173,6 +173,8 @@
                     // Convert deopt to guards.
                     new ConvertDeoptimizeToGuardPhase().apply(graph);
 
+                    new EarlyReadEliminationPhase(canonicalizerPhase).apply(graph, context);
+
                     if (!inliningProgress) {
                         break;
                     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeLoadMacroNode.java	Mon Oct 07 02:40:08 2013 +0200
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.truffle.nodes.typesystem;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.truffle.nodes.asserts.*;
+import com.oracle.truffle.api.*;
+
+/**
+ * Macro node for method {@link CompilerDirectives#unsafeCast(Object, Class, boolean)}.
+ */
+public class CustomizedUnsafeLoadMacroNode extends NeverPartOfCompilationNode implements Canonicalizable {
+
+    private static final int ARGUMENT_COUNT = 4;
+    private static final int OBJECT_ARGUMENT_INDEX = 0;
+    private static final int OFFSET_ARGUMENT_INDEX = 1;
+    private static final int CONDITION_ARGUMENT_INDEX = 2;
+    private static final int LOCATION_ARGUMENT_INDEX = 3;
+
+    public CustomizedUnsafeLoadMacroNode(Invoke invoke) {
+        super(invoke, "The location argument could not be resolved to a constant.");
+        assert arguments.size() == ARGUMENT_COUNT;
+    }
+
+    @SuppressWarnings("unused")
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        ValueNode locationArgument = arguments.get(LOCATION_ARGUMENT_INDEX);
+        if (locationArgument.isConstant()) {
+            ValueNode objectArgument = arguments.get(OBJECT_ARGUMENT_INDEX);
+            ValueNode offsetArgument = arguments.get(OFFSET_ARGUMENT_INDEX);
+            ValueNode conditionArgument = arguments.get(CONDITION_ARGUMENT_INDEX);
+            Object locationIdentityObject = locationArgument.asConstant().asObject();
+            LocationIdentity locationIdentity;
+            if (locationIdentityObject == null) {
+                locationIdentity = LocationIdentity.ANY_LOCATION;
+            } else {
+                locationIdentity = ObjectLocationIdentity.create(locationIdentityObject);
+            }
+            return graph().add(new UnsafeLoadNode(objectArgument, offsetArgument, this.stamp().kind(), locationIdentity));
+        }
+        return this;
+    }
+}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeLoadNode.java	Mon Oct 07 01:25:49 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +0,0 @@
-/*
- * Copyright (c) 2012, 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.truffle.nodes.typesystem;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.spi.*;
-
-public final class CustomizedUnsafeLoadNode extends UnsafeLoadNode {
-
-    @Input private ValueNode condition;
-    @Input private ValueNode customLocationIdentity;
-
-    public CustomizedUnsafeLoadNode(ValueNode object, ValueNode offset, Kind accessKind, ValueNode condition, ValueNode customLocationIdentity) {
-        super(object, offset, accessKind);
-        this.condition = condition;
-        this.customLocationIdentity = customLocationIdentity;
-    }
-
-    public ValueNode getCondition() {
-        return condition;
-    }
-
-    public ValueNode getCustomLocationIdentity() {
-        return customLocationIdentity;
-    }
-
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        return this;
-    }
-
-    @Override
-    public void virtualize(VirtualizerTool tool) {
-        super.virtualize(tool);
-    }
-
-    @SuppressWarnings("unused")
-    @NodeIntrinsic
-    public static <T> T load(Object object, long offset, @ConstantNodeParameter Kind kind, boolean condition, Object locationIdentity) {
-        return UnsafeLoadNode.load(object, offset, kind);
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeStoreMacroNode.java	Mon Oct 07 02:40:08 2013 +0200
@@ -0,0 +1,67 @@
+/*
+ * 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.truffle.nodes.typesystem;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.truffle.nodes.asserts.*;
+import com.oracle.truffle.api.*;
+
+/**
+ * Macro node for method {@link CompilerDirectives#unsafeCast(Object, Class, boolean)}.
+ */
+public class CustomizedUnsafeStoreMacroNode extends NeverPartOfCompilationNode implements Canonicalizable {
+
+    private static final int ARGUMENT_COUNT = 4;
+    private static final int OBJECT_ARGUMENT_INDEX = 0;
+    private static final int OFFSET_ARGUMENT_INDEX = 1;
+    private static final int VALUE_ARGUMENT_INDEX = 2;
+    private static final int LOCATION_ARGUMENT_INDEX = 3;
+
+    public CustomizedUnsafeStoreMacroNode(Invoke invoke) {
+        super(invoke, "The location argument could not be resolved to a constant.");
+        assert arguments.size() == ARGUMENT_COUNT;
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        ValueNode locationArgument = arguments.get(LOCATION_ARGUMENT_INDEX);
+        if (locationArgument.isConstant()) {
+            ValueNode objectArgument = arguments.get(OBJECT_ARGUMENT_INDEX);
+            ValueNode offsetArgument = arguments.get(OFFSET_ARGUMENT_INDEX);
+            ValueNode valueArgument = arguments.get(VALUE_ARGUMENT_INDEX);
+            Object locationIdentityObject = locationArgument.asConstant().asObject();
+            LocationIdentity locationIdentity;
+            if (locationIdentityObject == null) {
+                locationIdentity = LocationIdentity.ANY_LOCATION;
+            } else {
+                locationIdentity = ObjectLocationIdentity.create(locationIdentityObject);
+            }
+            return graph().add(new UnsafeStoreNode(objectArgument, offsetArgument, valueArgument, valueArgument.stamp().kind(), locationIdentity));
+        }
+        return this;
+    }
+}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeStoreNode.java	Mon Oct 07 01:25:49 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,108 +0,0 @@
-/*
- * Copyright (c) 2012, 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.truffle.nodes.typesystem;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.spi.*;
-
-public final class CustomizedUnsafeStoreNode extends UnsafeStoreNode {
-
-    @Input private ValueNode customLocationIdentity;
-
-    public CustomizedUnsafeStoreNode(ValueNode object, ValueNode offset, ValueNode value, Kind accessKind, ValueNode customLocationIdentity) {
-        super(object, offset, value, accessKind);
-        this.customLocationIdentity = customLocationIdentity;
-    }
-
-    public ValueNode getCustomLocationIdentity() {
-        return customLocationIdentity;
-    }
-
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        return this;
-    }
-
-    @Override
-    public void virtualize(VirtualizerTool tool) {
-        super.virtualize(tool);
-    }
-
-    @SuppressWarnings("unused")
-    @NodeIntrinsic
-    public static void store(Object object, long offset, Object value, @ConstantNodeParameter Kind kind, Object customLocationIdentity) {
-        UnsafeStoreNode.store(object, offset, value, kind);
-    }
-
-    @SuppressWarnings("unused")
-    @NodeIntrinsic
-    public static void store(Object object, long offset, boolean value, @ConstantNodeParameter Kind kind, Object customLocationIdentity) {
-        UnsafeStoreNode.store(object, offset, value, kind);
-    }
-
-    @SuppressWarnings("unused")
-    @NodeIntrinsic
-    public static void store(Object object, long offset, byte value, @ConstantNodeParameter Kind kind, Object customLocationIdentity) {
-        UnsafeStoreNode.store(object, offset, value, kind);
-    }
-
-    @SuppressWarnings("unused")
-    @NodeIntrinsic
-    public static void store(Object object, long offset, char value, @ConstantNodeParameter Kind kind, Object customLocationIdentity) {
-        UnsafeStoreNode.store(object, offset, value, kind);
-    }
-
-    @SuppressWarnings("unused")
-    @NodeIntrinsic
-    public static void store(Object object, long offset, double value, @ConstantNodeParameter Kind kind, Object customLocationIdentity) {
-        UnsafeStoreNode.store(object, offset, value, kind);
-    }
-
-    @SuppressWarnings("unused")
-    @NodeIntrinsic
-    public static void store(Object object, long offset, float value, @ConstantNodeParameter Kind kind, Object customLocationIdentity) {
-        UnsafeStoreNode.store(object, offset, value, kind);
-    }
-
-    @SuppressWarnings("unused")
-    @NodeIntrinsic
-    public static void store(Object object, long offset, int value, @ConstantNodeParameter Kind kind, Object customLocationIdentity) {
-        UnsafeStoreNode.store(object, offset, value, kind);
-    }
-
-    @SuppressWarnings("unused")
-    @NodeIntrinsic
-    public static void store(Object object, long offset, long value, @ConstantNodeParameter Kind kind, Object customLocationIdentity) {
-        UnsafeStoreNode.store(object, offset, value, kind);
-    }
-
-    @SuppressWarnings("unused")
-    @NodeIntrinsic
-    public static void store(Object object, long offset, short value, @ConstantNodeParameter Kind kind, Object customLocationIdentity) {
-        UnsafeStoreNode.store(object, offset, value, kind);
-    }
-}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/CompilerDirectivesSubstitutions.java	Mon Oct 07 01:25:49 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/CompilerDirectivesSubstitutions.java	Mon Oct 07 02:40:08 2013 +0200
@@ -66,78 +66,48 @@
     @MacroSubstitution(macro = UnsafeTypeCastMacroNode.class, isStatic = true)
     public static native Object unsafeCast(Object value, Class clazz, boolean condition);
 
-    @MethodSubstitution
-    public static boolean unsafeGetBoolean(Object receiver, long offset, boolean condition, Object locationIdentity) {
-        return CustomizedUnsafeLoadNode.load(receiver, offset, Kind.Boolean, condition, locationIdentity);
-    }
+    @MacroSubstitution(macro = CustomizedUnsafeLoadMacroNode.class, isStatic = true)
+    public static native boolean unsafeGetBoolean(Object receiver, long offset, boolean condition, Object locationIdentity);
 
-    @MethodSubstitution
-    public static byte unsafeGetByte(Object receiver, long offset, boolean condition, Object locationIdentity) {
-        return CustomizedUnsafeLoadNode.load(receiver, offset, Kind.Byte, condition, locationIdentity);
-    }
+    @MacroSubstitution(macro = CustomizedUnsafeLoadMacroNode.class, isStatic = true)
+    public static native byte unsafeGetByte(Object receiver, long offset, boolean condition, Object locationIdentity);
 
-    @MethodSubstitution
-    public static short unsafeGetShort(Object receiver, long offset, boolean condition, Object locationIdentity) {
-        return CustomizedUnsafeLoadNode.load(receiver, offset, Kind.Short, condition, locationIdentity);
-    }
+    @MacroSubstitution(macro = CustomizedUnsafeLoadMacroNode.class, isStatic = true)
+    public static native short unsafeGetShort(Object receiver, long offset, boolean condition, Object locationIdentity);
 
-    @MethodSubstitution
-    public static int unsafeGetInt(Object receiver, long offset, boolean condition, Object locationIdentity) {
-        return CustomizedUnsafeLoadNode.load(receiver, offset, Kind.Int, condition, locationIdentity);
-    }
+    @MacroSubstitution(macro = CustomizedUnsafeLoadMacroNode.class, isStatic = true)
+    public static native int unsafeGetInt(Object receiver, long offset, boolean condition, Object locationIdentity);
 
-    @MethodSubstitution
-    public static float unsafeGetFloat(Object receiver, long offset, boolean condition, Object locationIdentity) {
-        return CustomizedUnsafeLoadNode.load(receiver, offset, Kind.Float, condition, locationIdentity);
-    }
+    @MacroSubstitution(macro = CustomizedUnsafeLoadMacroNode.class, isStatic = true)
+    public static native float unsafeGetFloat(Object receiver, long offset, boolean condition, Object locationIdentity);
 
-    @MethodSubstitution
-    public static double unsafeGetDouble(Object receiver, long offset, boolean condition, Object locationIdentity) {
-        return CustomizedUnsafeLoadNode.load(receiver, offset, Kind.Double, condition, locationIdentity);
-    }
+    @MacroSubstitution(macro = CustomizedUnsafeLoadMacroNode.class, isStatic = true)
+    public static native double unsafeGetDouble(Object receiver, long offset, boolean condition, Object locationIdentity);
 
-    @MethodSubstitution
-    public static Object unsafeGetObject(Object receiver, long offset, boolean condition, Object locationIdentity) {
-        return CustomizedUnsafeLoadNode.load(receiver, offset, Kind.Object, condition, locationIdentity);
-    }
+    @MacroSubstitution(macro = CustomizedUnsafeLoadMacroNode.class, isStatic = true)
+    public static native Object unsafeGetObject(Object receiver, long offset, boolean condition, Object locationIdentity);
 
-    @MethodSubstitution
-    public static void unsafePutBoolean(Object receiver, long offset, boolean value, Object locationIdentity) {
-        CustomizedUnsafeStoreNode.store(receiver, offset, value, Kind.Boolean, locationIdentity);
-    }
+    @MacroSubstitution(macro = CustomizedUnsafeStoreMacroNode.class, isStatic = true)
+    public static native void unsafePutBoolean(Object receiver, long offset, boolean value, Object locationIdentity);
 
-    @MethodSubstitution
-    public static void unsafePutByte(Object receiver, long offset, byte value, Object locationIdentity) {
-        CustomizedUnsafeStoreNode.store(receiver, offset, value, Kind.Byte, locationIdentity);
-    }
+    @MacroSubstitution(macro = CustomizedUnsafeStoreMacroNode.class, isStatic = true)
+    public static native void unsafePutByte(Object receiver, long offset, byte value, Object locationIdentity);
 
-    @MethodSubstitution
-    public static void unsafePutShort(Object receiver, long offset, short value, Object locationIdentity) {
-        CustomizedUnsafeStoreNode.store(receiver, offset, value, Kind.Short, locationIdentity);
-    }
+    @MacroSubstitution(macro = CustomizedUnsafeStoreMacroNode.class, isStatic = true)
+    public static native void unsafePutShort(Object receiver, long offset, short value, Object locationIdentity);
 
-    @MethodSubstitution
-    public static void unsafePutInt(Object receiver, long offset, int value, Object locationIdentity) {
-        CustomizedUnsafeStoreNode.store(receiver, offset, value, Kind.Int, locationIdentity);
-    }
+    @MacroSubstitution(macro = CustomizedUnsafeStoreMacroNode.class, isStatic = true)
+    public static native void unsafePutInt(Object receiver, long offset, int value, Object locationIdentity);
 
-    @MethodSubstitution
-    public static void unsafePutLong(Object receiver, long offset, long value, Object locationIdentity) {
-        CustomizedUnsafeStoreNode.store(receiver, offset, value, Kind.Long, locationIdentity);
-    }
+    @MacroSubstitution(macro = CustomizedUnsafeStoreMacroNode.class, isStatic = true)
+    public static native void unsafePutLong(Object receiver, long offset, long value, Object locationIdentity);
 
-    @MethodSubstitution
-    public static void unsafePutFloat(Object receiver, long offset, float value, Object locationIdentity) {
-        CustomizedUnsafeStoreNode.store(receiver, offset, value, Kind.Float, locationIdentity);
-    }
+    @MacroSubstitution(macro = CustomizedUnsafeStoreMacroNode.class, isStatic = true)
+    public static native void unsafePutFloat(Object receiver, long offset, float value, Object locationIdentity);
 
-    @MethodSubstitution
-    public static void unsafePutDouble(Object receiver, long offset, double value, Object locationIdentity) {
-        CustomizedUnsafeStoreNode.store(receiver, offset, value, Kind.Double, locationIdentity);
-    }
+    @MacroSubstitution(macro = CustomizedUnsafeStoreMacroNode.class, isStatic = true)
+    public static native void unsafePutDouble(Object receiver, long offset, double value, Object locationIdentity);
 
-    @MethodSubstitution
-    public static void unsafePutObject(Object receiver, long offset, Object value, Object locationIdentity) {
-        CustomizedUnsafeStoreNode.store(receiver, offset, value, Kind.Object, locationIdentity);
-    }
+    @MacroSubstitution(macro = CustomizedUnsafeStoreMacroNode.class, isStatic = true)
+    public static native void unsafePutObject(Object receiver, long offset, Object value, Object locationIdentity);
 }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationBlockState.java	Mon Oct 07 01:25:49 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationBlockState.java	Mon Oct 07 02:40:08 2013 +0200
@@ -64,14 +64,14 @@
         public abstract boolean conflicts(LocationIdentity other);
     }
 
-    static class LoadCacheEntry extends CacheEntry<ResolvedJavaField> {
+    static class LoadCacheEntry extends CacheEntry<LocationIdentity> {
 
-        public LoadCacheEntry(ValueNode object, ResolvedJavaField identity) {
+        public LoadCacheEntry(ValueNode object, LocationIdentity identity) {
             super(object, identity);
         }
 
         @Override
-        public CacheEntry<ResolvedJavaField> duplicateWithObject(ValueNode newObject) {
+        public CacheEntry<LocationIdentity> duplicateWithObject(ValueNode newObject) {
             return new LoadCacheEntry(newObject, identity);
         }
 
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java	Mon Oct 07 01:25:49 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java	Mon Oct 07 02:40:08 2013 +0200
@@ -81,7 +81,7 @@
                     effects.deleteFixedNode(store);
                     deleted = true;
                 }
-                state.killReadCache((LocationIdentity) store.field());
+                state.killReadCache(store.field());
                 state.addCacheEntry(identifier, value);
             } else {
                 processIdentity(state, ANY_LOCATION);
@@ -100,6 +100,20 @@
                     state.addCacheEntry(identifier, read);
                 }
             }
+        } else if (node instanceof UnsafeLoadNode) {
+            UnsafeLoadNode load = (UnsafeLoadNode) node;
+            if (load.offset().isConstant() && load.getLocationIdentity() != LocationIdentity.ANY_LOCATION) {
+                ValueNode object = GraphUtil.unproxify(load.object());
+                LoadCacheEntry identifier = new LoadCacheEntry(object, load.getLocationIdentity());
+                ValueNode cachedValue = state.getCacheEntry(identifier);
+                if (cachedValue != null) {
+                    effects.replaceAtUsages(load, cachedValue);
+                    addScalarAlias(load, cachedValue);
+                    deleted = true;
+                } else {
+                    state.addCacheEntry(identifier, load);
+                }
+            }
         } else if (node instanceof WriteNode) {
             WriteNode write = (WriteNode) node;
             if (write.location() instanceof ConstantLocationNode) {
@@ -117,6 +131,23 @@
             } else {
                 processIdentity(state, write.location().getLocationIdentity());
             }
+        } else if (node instanceof UnsafeStoreNode) {
+            UnsafeStoreNode write = (UnsafeStoreNode) node;
+            if (write.offset().isConstant() && write.getLocationIdentity() != LocationIdentity.ANY_LOCATION) {
+                ValueNode object = GraphUtil.unproxify(write.object());
+                LoadCacheEntry identifier = new LoadCacheEntry(object, write.getLocationIdentity());
+                ValueNode cachedValue = state.getCacheEntry(identifier);
+
+                ValueNode value = getScalarAlias(write.value());
+                if (GraphUtil.unproxify(value) == GraphUtil.unproxify(cachedValue)) {
+                    effects.deleteFixedNode(write);
+                    deleted = true;
+                }
+                processIdentity(state, write.getLocationIdentity());
+                state.addCacheEntry(identifier, value);
+            } else {
+                processIdentity(state, write.getLocationIdentity());
+            }
         } else if (node instanceof MemoryCheckpoint.Single) {
             LocationIdentity identity = ((MemoryCheckpoint.Single) node).getLocationIdentity();
             processIdentity(state, identity);