changeset 10655:2abf1c8b062a

Merge.
author Thomas Wuerthinger <thomas.wuerthinger@oracle.com>
date Mon, 08 Jul 2013 21:12:41 +0200
parents d71c56c67921 (diff) 678cdd287d60 (current diff)
children a7d50a27982c
files graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java
diffstat 21 files changed, 216 insertions(+), 253 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Mon Jul 08 17:32:05 2013 +0200
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Mon Jul 08 21:12:41 2013 +0200
@@ -241,6 +241,13 @@
     }
 
     @Override
+    protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) {
+        AllocatableValue targetAddress = AMD64.rax.asValue();
+        emitMove(targetAddress, operand(callTarget.computedAddress()));
+        append(new AMD64Call.IndirectCallOp(callTarget.target(), result, parameters, temps, targetAddress, callState));
+    }
+
+    @Override
     public void emitOverflowCheckBranch(LabelRef destination, boolean negated) {
         append(new BranchOp(negated ? ConditionFlag.NoOverflow : ConditionFlag.Overflow, destination));
     }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Mon Jul 08 17:32:05 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Mon Jul 08 21:12:41 2013 +0200
@@ -38,6 +38,7 @@
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.bridge.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.hotspot.stubs.*;
@@ -341,11 +342,15 @@
 
     @Override
     protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) {
-        AllocatableValue metaspaceMethod = AMD64.rbx.asValue();
-        emitMove(metaspaceMethod, operand(((HotSpotIndirectCallTargetNode) callTarget).metaspaceMethod()));
-        AllocatableValue targetAddress = AMD64.rax.asValue();
-        emitMove(targetAddress, operand(callTarget.computedAddress()));
-        append(new AMD64IndirectCallOp(callTarget.target(), result, parameters, temps, metaspaceMethod, targetAddress, callState));
+        if (callTarget instanceof HotSpotIndirectCallTargetNode) {
+            AllocatableValue metaspaceMethod = AMD64.rbx.asValue();
+            emitMove(metaspaceMethod, operand(((HotSpotIndirectCallTargetNode) callTarget).metaspaceMethod()));
+            AllocatableValue targetAddress = AMD64.rax.asValue();
+            emitMove(targetAddress, operand(callTarget.computedAddress()));
+            append(new AMD64IndirectCallOp(callTarget.target(), result, parameters, temps, metaspaceMethod, targetAddress, callState));
+        } else {
+            super.emitIndirectCall(callTarget, result, parameters, temps, callState);
+        }
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java	Mon Jul 08 17:32:05 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java	Mon Jul 08 21:12:41 2013 +0200
@@ -184,5 +184,5 @@
      * stub that does the necessary argument shuffling and a tail call via an indirect jump to the
      * verified entry point of the given native method.
      */
-    private static native Object executeCompiledMethodIntrinsic(Object arg1, Object arg2, Object arg3, HotSpotInstalledCode hotspotInstalledCode);
+    public static native Object executeCompiledMethodIntrinsic(Object arg1, Object arg2, Object arg3, HotSpotInstalledCode hotspotInstalledCode) throws InvalidInstalledCodeException;
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotNmethod.java	Mon Jul 08 17:32:05 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotNmethod.java	Mon Jul 08 21:12:41 2013 +0200
@@ -29,6 +29,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
+import com.oracle.graal.hotspot.bridge.*;
 
 /**
  * Implementation of {@link InstalledCode} for code installed as an nmethod. The nmethod stores a
@@ -100,7 +101,11 @@
         assert method.getSignature().getParameterKind(0) == Kind.Object;
         assert method.getSignature().getParameterKind(1) == Kind.Object;
         assert !Modifier.isStatic(method.getModifiers()) || method.getSignature().getParameterKind(2) == Kind.Object;
-        return graalRuntime().getCompilerToVM().executeCompiledMethod(arg1, arg2, arg3, this);
+        return executeHelper(arg1, arg2, arg3, this);
+    }
+
+    private static Object executeHelper(Object arg1, Object arg2, Object arg3, HotSpotInstalledCode hotspotInstalledCode) throws InvalidInstalledCodeException {
+        return CompilerToVMImpl.executeCompiledMethodIntrinsic(arg1, arg2, arg3, hotspotInstalledCode);
     }
 
     private boolean checkArgs(Object... args) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotNmethodExecuteNode.java	Mon Jul 08 17:32:05 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotNmethodExecuteNode.java	Mon Jul 08 21:12:41 2013 +0200
@@ -22,95 +22,45 @@
  */
 package com.oracle.graal.hotspot.nodes;
 
-import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
-
-import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.code.CallingConvention.Type;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.hotspot.replacements.*;
+import com.oracle.graal.hotspot.*;
 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.common.*;
-
-public class HotSpotNmethodExecuteNode extends AbstractCallNode implements Lowerable, MemoryCheckpoint.Single {
-
-    @Input private ValueNode code;
-    private final Class[] signature;
+import com.oracle.graal.replacements.nodes.*;
 
-    public HotSpotNmethodExecuteNode(Kind kind, Class[] signature, ValueNode code, ValueNode arg1, ValueNode arg2, ValueNode arg3) {
-        super(StampFactory.forKind(kind), new ValueNode[]{arg1, arg2, arg3});
-        this.code = code;
-        this.signature = signature;
-    }
+public class HotSpotNmethodExecuteNode extends MacroNode implements Lowerable {
 
-    @Override
-    public LocationIdentity getLocationIdentity() {
-        return LocationIdentity.ANY_LOCATION;
+    public HotSpotNmethodExecuteNode(Invoke invoke) {
+        super(invoke);
     }
 
     @Override
     public void lower(LoweringTool tool, LoweringType loweringType) {
-        if (code.isConstant() && code.asConstant().asObject() instanceof HotSpotNmethod) {
-            HotSpotNmethod nmethod = (HotSpotNmethod) code.asConstant().asObject();
-            InvokeNode invoke = replaceWithInvoke(tool.getRuntime());
-            StructuredGraph graph = (StructuredGraph) nmethod.getGraph();
-            if (graph != null) {
-                InliningUtil.inline(invoke, graph, false);
+        if (loweringType == LoweringType.AFTER_GUARDS) {
+
+            ValueNode hotspotNmethod = arguments.get(3);
+
+            ReadNode readNode = graph().add(new ReadNode(hotspotNmethod, 16, LocationIdentity.ANY_LOCATION, Kind.Long));
+            graph().addBeforeFixed(this, readNode);
+            readNode.setNullCheck(true);
+
+            int verifiedEntryOffset = HotSpotGraalRuntime.graalRuntime().getConfig().nmethodEntryOffset;
+            ReadNode readAddressNode = graph().add(new ReadNode(readNode, verifiedEntryOffset, LocationIdentity.ANY_LOCATION, Kind.Long));
+            graph().addBeforeFixed(this, readAddressNode);
+            readAddressNode.setNullCheck(true);
+
+            JavaType[] signatureTypes = new JavaType[getTargetMethod().getSignature().getParameterCount(false)];
+            for (int i = 0; i < signatureTypes.length; ++i) {
+                signatureTypes[i] = getTargetMethod().getSignature().getParameterType(i, getTargetMethod().getDeclaringClass());
             }
-        } else {
-            replaceWithInvoke(tool.getRuntime());
+
+            IndirectCallTargetNode callTarget = graph().add(new IndirectCallTargetNode(readAddressNode, arguments, StampFactory.object(), signatureTypes, super.getTargetMethod(), Type.JavaCall));
+            InvokeNode invoke = graph().add(new InvokeNode(callTarget, super.getBci()));
+            invoke.setStateAfter(stateAfter());
+            graph().replaceFixedWithFixed(this, invoke);
         }
     }
-
-    protected InvokeNode replaceWithInvoke(MetaAccessProvider tool) {
-        ResolvedJavaMethod method = null;
-        ResolvedJavaField methodField = null;
-        ResolvedJavaField metaspaceMethodField = null;
-        ResolvedJavaField codeBlobField = null;
-        try {
-            method = tool.lookupJavaMethod(HotSpotNmethodExecuteNode.class.getMethod("placeholder", Object.class, Object.class, Object.class));
-            methodField = tool.lookupJavaField(HotSpotNmethod.class.getDeclaredField("method"));
-            codeBlobField = tool.lookupJavaField(HotSpotInstalledCode.class.getDeclaredField("codeBlob"));
-            metaspaceMethodField = tool.lookupJavaField(HotSpotResolvedJavaMethod.class.getDeclaredField("metaspaceMethod"));
-        } catch (NoSuchMethodException | SecurityException | NoSuchFieldException e) {
-            throw new IllegalStateException(e);
-        }
-        ResolvedJavaType[] signatureTypes = new ResolvedJavaType[signature.length];
-        for (int i = 0; i < signature.length; i++) {
-            signatureTypes[i] = tool.lookupJavaType(signature[i]);
-        }
-        final int verifiedEntryPointOffset = HotSpotReplacementsUtil.verifiedEntryPointOffset();
-
-        LoadFieldNode loadCodeBlob = graph().add(new LoadFieldNode(code, codeBlobField));
-        UnsafeLoadNode load = graph().add(new UnsafeLoadNode(loadCodeBlob, verifiedEntryPointOffset, ConstantNode.forLong(0, graph()), graalRuntime().getTarget().wordKind));
-
-        LoadFieldNode loadMethod = graph().add(new LoadFieldNode(code, methodField));
-        LoadFieldNode loadmetaspaceMethod = graph().add(new LoadFieldNode(loadMethod, metaspaceMethodField));
-
-        HotSpotIndirectCallTargetNode callTarget = graph().add(
-                        new HotSpotIndirectCallTargetNode(loadmetaspaceMethod, load, arguments(), stamp(), signatureTypes, method, CallingConvention.Type.JavaCall));
-
-        InvokeNode invoke = graph().add(new InvokeNode(callTarget, 0));
-
-        invoke.setStateAfter(stateAfter());
-        graph().replaceFixedWithFixed(this, invoke);
-
-        graph().addBeforeFixed(invoke, loadmetaspaceMethod);
-        graph().addBeforeFixed(loadmetaspaceMethod, loadMethod);
-        graph().addBeforeFixed(invoke, load);
-        graph().addBeforeFixed(load, loadCodeBlob);
-
-        return invoke;
-    }
-
-    public static Object placeholder(@SuppressWarnings("unused") Object a1, @SuppressWarnings("unused") Object a2, @SuppressWarnings("unused") Object a3) {
-        return 1;
-    }
-
-    @NodeIntrinsic
-    public static native <T> T call(@ConstantNodeParameter Kind kind, @ConstantNodeParameter Class[] signature, Object code, Object arg1, Object arg2, Object arg3);
-
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotNmethodSubstitutions.java	Mon Jul 08 17:32:05 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotNmethodSubstitutions.java	Mon Jul 08 21:12:41 2013 +0200
@@ -22,19 +22,17 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.replacements.Snippet.Fold;
 
 @ClassSubstitution(HotSpotNmethod.class)
 public class HotSpotNmethodSubstitutions {
 
-    @MethodSubstitution(isStatic = false)
-    public static Object execute(HotSpotInstalledCode code, final Object arg1, final Object arg2, final Object arg3) {
-        return HotSpotNmethodExecuteNode.call(Kind.Object, getSignature(), code, arg1, arg2, arg3);
-    }
+    @MacroSubstitution(macro = HotSpotNmethodExecuteNode.class, isStatic = true)
+    public static native Object executeHelper(final Object arg1, final Object arg2, final Object arg3, HotSpotInstalledCode code);
 
     @Fold
     private static Class[] getSignature() {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java	Mon Jul 08 17:32:05 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java	Mon Jul 08 21:12:41 2013 +0200
@@ -25,6 +25,7 @@
 import com.oracle.graal.api.code.*;
 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.spi.*;
 import com.oracle.graal.nodes.type.*;
@@ -45,6 +46,10 @@
         return object;
     }
 
+    public GuardingPiNode(ValueNode object) {
+        this(object, object.graph().unique(new IsNullNode(object)), true, DeoptimizationReason.NullCheckException, DeoptimizationAction.None, object.stamp().join(StampFactory.objectNonNull()));
+    }
+
     public GuardingPiNode(ValueNode object, ValueNode condition, boolean negateCondition, DeoptimizationReason reason, DeoptimizationAction action, Stamp stamp) {
         super(object.stamp().join(stamp));
         assert stamp() != null;
@@ -83,6 +88,9 @@
     }
 
     @NodeIntrinsic
+    public static native <T> T guardingNonNull(T object);
+
+    @NodeIntrinsic
     public static native Object guardingPi(Object object, LogicNode condition, @ConstantNodeParameter boolean negateCondition, @ConstantNodeParameter DeoptimizationReason reason,
                     @ConstantNodeParameter DeoptimizationAction action, @ConstantNodeParameter Stamp stamp);
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java	Mon Jul 08 17:32:05 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java	Mon Jul 08 21:12:41 2013 +0200
@@ -42,7 +42,7 @@
         super(object, location, stamp, guard, barrierType, compress);
     }
 
-    private ReadNode(ValueNode object, int displacement, LocationIdentity locationIdentity, Kind kind) {
+    public ReadNode(ValueNode object, int displacement, LocationIdentity locationIdentity, Kind kind) {
         super(object, ConstantLocationNode.create(locationIdentity, kind, displacement, object.graph()), StampFactory.forKind(kind));
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeAccessNode.java	Mon Jul 08 17:32:05 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeAccessNode.java	Mon Jul 08 21:12:41 2013 +0200
@@ -24,9 +24,10 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
-public abstract class UnsafeAccessNode extends FixedWithNextNode {
+public abstract class UnsafeAccessNode extends FixedWithNextNode implements Canonicalizable {
 
     @Input private ValueNode object;
     @Input private ValueNode offset;
@@ -57,4 +58,39 @@
     public Kind accessKind() {
         return accessKind;
     }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool) {
+        if (offset().isConstant()) {
+            long constantOffset = offset().asConstant().asLong();
+
+            // Try to canonicalize to a field access.
+            if (object().stamp() instanceof ObjectStamp) {
+                // TODO (gd) remove that once UnsafeAccess only have an object base
+                ObjectStamp receiverStamp = object().objectStamp();
+                ResolvedJavaType receiverType = receiverStamp.type();
+                if (receiverType != null) {
+                    ResolvedJavaField field = receiverType.findInstanceFieldWithOffset(displacement() + constantOffset);
+                    // No need for checking that the receiver is non-null. The field access includes
+                    // the null check and if a field is found, the offset is so small that this is
+                    // never a valid access of an arbitrary address.
+                    if (field != null && field.getKind() == this.accessKind()) {
+                        return cloneAsFieldAccess(field);
+                    }
+                }
+            }
+
+            if (constantOffset != 0 && Integer.MAX_VALUE - displacement() >= constantOffset) {
+                int intDisplacement = (int) (constantOffset + displacement());
+                if (constantOffset == intDisplacement) {
+                    return cloneWithZeroOffset(intDisplacement);
+                }
+            }
+        }
+        return this;
+    }
+
+    protected abstract ValueNode cloneAsFieldAccess(ResolvedJavaField field);
+
+    protected abstract ValueNode cloneWithZeroOffset(int intDisplacement);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java	Mon Jul 08 17:32:05 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java	Mon Jul 08 21:12:41 2013 +0200
@@ -25,7 +25,6 @@
 import static com.oracle.graal.graph.UnsafeAccess.*;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
@@ -35,7 +34,7 @@
  * Load of a value from a location specified as an offset relative to an object. No null check is
  * performed before the load.
  */
-public class UnsafeLoadNode extends UnsafeAccessNode implements Lowerable, Virtualizable, Canonicalizable {
+public class UnsafeLoadNode extends UnsafeAccessNode implements Lowerable, Virtualizable {
 
     public UnsafeLoadNode(ValueNode object, int displacement, ValueNode offset, boolean nonNull) {
         this(nonNull ? StampFactory.objectNonNull() : StampFactory.object(), object, displacement, offset, Kind.Object);
@@ -70,29 +69,13 @@
     }
 
     @Override
-    public ValueNode canonical(CanonicalizerTool tool) {
-        if (offset().isConstant()) {
-            long constantOffset = offset().asConstant().asLong();
-            if (constantOffset != 0) {
-                int intDisplacement = (int) (constantOffset + displacement());
-                if (constantOffset == intDisplacement) {
-                    Graph graph = this.graph();
-                    return graph.add(new UnsafeLoadNode(this.stamp(), object(), intDisplacement, graph.unique(ConstantNode.forInt(0, graph)), accessKind()));
-                }
-            } else if (object().stamp() instanceof ObjectStamp) { // TODO (gd) remove that once
-                                                                  // UnsafeAccess only have an
-                                                                  // object base
-                ObjectStamp receiverStamp = object().objectStamp();
-                ResolvedJavaType receiverType = receiverStamp.type();
-                if (receiverStamp.nonNull() && receiverType != null) {
-                    ResolvedJavaField field = receiverType.findInstanceFieldWithOffset(displacement());
-                    if (field != null) {
-                        return this.graph().add(new LoadFieldNode(object(), field));
-                    }
-                }
-            }
-        }
-        return this;
+    protected ValueNode cloneAsFieldAccess(ResolvedJavaField field) {
+        return this.graph().add(new LoadFieldNode(object(), field));
+    }
+
+    @Override
+    protected ValueNode cloneWithZeroOffset(int intDisplacement) {
+        return graph().add(new UnsafeLoadNode(this.stamp(), object(), intDisplacement, graph().unique(ConstantNode.forInt(0, graph())), accessKind()));
     }
 
     @SuppressWarnings("unchecked")
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java	Mon Jul 08 17:32:05 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java	Mon Jul 08 21:12:41 2013 +0200
@@ -34,7 +34,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, MemoryCheckpoint.Single {
+public class UnsafeStoreNode extends UnsafeAccessNode implements StateSplit, Lowerable, Virtualizable, MemoryCheckpoint.Single {
 
     @Input private ValueNode value;
     @Input(notDataflow = true) private FrameState stateAfter;
@@ -94,32 +94,17 @@
     }
 
     @Override
-    public ValueNode canonical(CanonicalizerTool tool) {
-        if (offset().isConstant()) {
-            long constantOffset = offset().asConstant().asLong();
-            if (constantOffset != 0) {
-                int intDisplacement = (int) (constantOffset + displacement());
-                if (constantOffset == intDisplacement) {
-                    UnsafeStoreNode unsafeStoreNode = graph().add(new UnsafeStoreNode(stamp(), object(), intDisplacement, ConstantNode.forInt(0, graph()), value(), accessKind()));
-                    unsafeStoreNode.setStateAfter(stateAfter());
-                    return unsafeStoreNode;
-                }
-            } else if (object().stamp() instanceof ObjectStamp) { // TODO (gd) remove that once
-                                                                  // UnsafeAccess only have an
-                                                                  // object base
-                ObjectStamp receiverStamp = object().objectStamp();
-                if (receiverStamp.nonNull()) {
-                    ResolvedJavaType receiverType = receiverStamp.type();
-                    ResolvedJavaField field = receiverType.findInstanceFieldWithOffset(displacement());
-                    if (field != null) {
-                        StoreFieldNode storeFieldNode = graph().add(new StoreFieldNode(object(), field, value()));
-                        storeFieldNode.setStateAfter(stateAfter());
-                        return storeFieldNode;
-                    }
-                }
-            }
-        }
-        return this;
+    protected ValueNode cloneAsFieldAccess(ResolvedJavaField field) {
+        StoreFieldNode storeFieldNode = graph().add(new StoreFieldNode(object(), field, value()));
+        storeFieldNode.setStateAfter(stateAfter());
+        return storeFieldNode;
+    }
+
+    @Override
+    protected ValueNode cloneWithZeroOffset(int intDisplacement) {
+        UnsafeStoreNode unsafeStoreNode = graph().add(new UnsafeStoreNode(stamp(), object(), intDisplacement, ConstantNode.forInt(0, graph()), value(), accessKind()));
+        unsafeStoreNode.setStateAfter(stateAfter());
+        return unsafeStoreNode;
     }
 
     // specialized on value type until boxing/unboxing is sorted out in intrinsification
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Mon Jul 08 17:32:05 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Mon Jul 08 21:12:41 2013 +0200
@@ -331,27 +331,7 @@
                 assert inlineable instanceof InlineableMacroNode;
 
                 Class<? extends FixedWithNextNode> macroNodeClass = ((InlineableMacroNode) inlineable).getMacroNodeClass();
-                if (((MethodCallTargetNode) invoke.callTarget()).targetMethod() != concrete) {
-                    assert ((MethodCallTargetNode) invoke.callTarget()).invokeKind() != InvokeKind.Static;
-                    InliningUtil.replaceInvokeCallTarget(invoke, graph, InvokeKind.Special, concrete);
-                }
-
-                FixedWithNextNode macroNode;
-                try {
-                    macroNode = macroNodeClass.getConstructor(Invoke.class).newInstance(invoke);
-                } catch (ReflectiveOperationException | IllegalArgumentException | SecurityException e) {
-                    throw new GraalInternalError(e).addContext(invoke.asNode()).addContext("macroSubstitution", macroNodeClass);
-                }
-
-                CallTargetNode callTarget = invoke.callTarget();
-                if (invoke instanceof InvokeNode) {
-                    graph.replaceFixedWithFixed((InvokeNode) invoke, graph.add(macroNode));
-                } else {
-                    InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke;
-                    invokeWithException.killExceptionEdge();
-                    graph.replaceSplitWithFixed(invokeWithException, graph.add(macroNode), invokeWithException.next());
-                }
-                GraphUtil.killWithUnusedFloatingInputs(callTarget);
+                inlineMacroNode(invoke, concrete, graph, macroNodeClass);
             }
 
             InlinedBytecodes.add(concrete.getCodeSize());
@@ -1480,4 +1460,29 @@
     public static Class<? extends FixedWithNextNode> getMacroNodeClass(Replacements replacements, ResolvedJavaMethod target) {
         return replacements.getMacroSubstitution(target);
     }
+
+    public static FixedWithNextNode inlineMacroNode(Invoke invoke, ResolvedJavaMethod concrete, StructuredGraph graph, Class<? extends FixedWithNextNode> macroNodeClass) throws GraalInternalError {
+        if (((MethodCallTargetNode) invoke.callTarget()).targetMethod() != concrete) {
+            assert ((MethodCallTargetNode) invoke.callTarget()).invokeKind() != InvokeKind.Static;
+            InliningUtil.replaceInvokeCallTarget(invoke, graph, InvokeKind.Special, concrete);
+        }
+
+        FixedWithNextNode macroNode;
+        try {
+            macroNode = macroNodeClass.getConstructor(Invoke.class).newInstance(invoke);
+        } catch (ReflectiveOperationException | IllegalArgumentException | SecurityException e) {
+            throw new GraalInternalError(e).addContext(invoke.asNode()).addContext("macroSubstitution", macroNodeClass);
+        }
+
+        CallTargetNode callTarget = invoke.callTarget();
+        if (invoke instanceof InvokeNode) {
+            graph.replaceFixedWithFixed((InvokeNode) invoke, graph.add(macroNode));
+        } else {
+            InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke;
+            invokeWithException.killExceptionEdge();
+            graph.replaceSplitWithFixed(invokeWithException, graph.add(macroNode), invokeWithException.next());
+        }
+        GraphUtil.killWithUnusedFloatingInputs(callTarget);
+        return macroNode;
+    }
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ArraySubstitutions.java	Mon Jul 08 17:32:05 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ArraySubstitutions.java	Mon Jul 08 21:12:41 2013 +0200
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.replacements;
 
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
@@ -36,9 +34,6 @@
 
     @MethodSubstitution
     public static Object newInstance(Class<?> componentType, int length) throws NegativeArraySizeException {
-        if (componentType == null) {
-            DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.NullCheckException);
-        }
-        return DynamicNewArrayNode.newArray(componentType, length);
+        return DynamicNewArrayNode.newArray(GuardingPiNode.guardingNonNull(componentType), length);
     }
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java	Mon Jul 08 17:32:05 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java	Mon Jul 08 21:12:41 2013 +0200
@@ -71,37 +71,39 @@
 
     @Override
     public Object call(PackedFrame caller, Arguments args) {
-        for (;;) {
-            if (compiledMethod != null) {
-                try {
-                    return compiledMethod.execute(this, caller, args);
-                } catch (InvalidInstalledCodeException ex) {
-                    compiledMethod = null;
-                    invokeCounter = invalidationReprofileCount;
-                    if (TruffleFunctionInlining.getValue()) {
-                        originalInvokeCounter += invalidationReprofileCount;
-                    }
-                    if (TraceTruffleCompilation.getValue()) {
-                        OUT.printf("[truffle] invalidated %-48s |Alive %5.0fms\n", rootNode, (System.nanoTime() - timeCompilationFinished) / 1e6);
-                    }
+        if (compiledMethod != null) {
+            try {
+                return compiledMethod.execute(this, caller, args);
+            } catch (InvalidInstalledCodeException ex) {
+                compiledMethod = null;
+                invokeCounter = invalidationReprofileCount;
+                if (TruffleFunctionInlining.getValue()) {
+                    originalInvokeCounter += invalidationReprofileCount;
+                }
+                if (TraceTruffleCompilation.getValue()) {
+                    OUT.printf("[truffle] invalidated %-48s |Alive %5.0fms\n", rootNode, (System.nanoTime() - timeCompilationFinished) / 1e6);
                 }
+                return call(caller, args);
+            }
+        } else {
+            return interpreterCall(caller, args);
+        }
+    }
+
+    private Object interpreterCall(PackedFrame caller, Arguments args) {
+        invokeCounter--;
+        loopAndInvokeCounter--;
+        if (disableCompilation || loopAndInvokeCounter > 0 || invokeCounter > 0) {
+            return executeHelper(caller, args);
+        } else {
+            if (TruffleFunctionInlining.getValue() && inline()) {
+                invokeCounter = 2;
+                loopAndInvokeCounter = inliningReprofileCount;
+                originalInvokeCounter = inliningReprofileCount;
             } else {
-                invokeCounter--;
-                loopAndInvokeCounter--;
-                if (disableCompilation || loopAndInvokeCounter > 0 || invokeCounter > 0) {
-                    return executeHelper(caller, args);
-                } else {
-                    if (TruffleFunctionInlining.getValue()) {
-                        if (inline()) {
-                            invokeCounter = 2;
-                            loopAndInvokeCounter = inliningReprofileCount;
-                            originalInvokeCounter = inliningReprofileCount;
-                            continue;
-                        }
-                    }
-                    compile();
-                }
+                compile();
             }
+            return call(caller, args);
         }
     }
 
@@ -260,7 +262,7 @@
 
                 @Override
                 public boolean visit(Node node) {
-                    if (node instanceof RootNode && node != root) {
+                    if (node instanceof RootNode && visitedCount > 0) {
                         return false;
                     }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluatorCanonicalizer.java	Mon Jul 08 17:32:05 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluatorCanonicalizer.java	Mon Jul 08 21:12:41 2013 +0200
@@ -26,7 +26,6 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.phases.common.*;
@@ -68,41 +67,8 @@
                     return ConstantNode.forObject(value, metaAccessProvider, node.graph());
                 }
             }
-        } else if (node instanceof UnsafeLoadNode) {
-            UnsafeLoadNode unsafeLoadNode = (UnsafeLoadNode) node;
-            if (unsafeLoadNode.offset().isConstant()) {
-                long offset = unsafeLoadNode.offset().asConstant().asLong() + unsafeLoadNode.displacement();
-                ResolvedJavaType type = unsafeLoadNode.object().objectStamp().type();
-                ResolvedJavaField field = recursiveFindFieldWithOffset(type, offset);
-                if (field != null) {
-                    return node.graph().add(new LoadFieldNode(unsafeLoadNode.object(), field));
-                }
-            }
-        } else if (node instanceof UnsafeStoreNode) {
-            UnsafeStoreNode unsafeStoreNode = (UnsafeStoreNode) node;
-            if (unsafeStoreNode.offset().isConstant()) {
-                long offset = unsafeStoreNode.offset().asConstant().asLong() + unsafeStoreNode.displacement();
-                ResolvedJavaType type = unsafeStoreNode.object().objectStamp().type();
-                ResolvedJavaField field = recursiveFindFieldWithOffset(type, offset);
-                if (field != null) {
-                    StoreFieldNode storeFieldNode = node.graph().add(new StoreFieldNode(unsafeStoreNode.object(), field, unsafeStoreNode.value()));
-                    storeFieldNode.setStateAfter(unsafeStoreNode.stateAfter());
-                    return storeFieldNode;
-                }
-            }
         }
 
         return node;
     }
-
-    private ResolvedJavaField recursiveFindFieldWithOffset(ResolvedJavaType type, long offset) {
-        if (type != null) {
-            ResolvedJavaField field = type.findInstanceFieldWithOffset(offset);
-            if (field != null) {
-                return field;
-            }
-            return recursiveFindFieldWithOffset(type.getSuperclass(), offset);
-        }
-        return null;
-    }
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java	Mon Jul 08 17:32:05 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java	Mon Jul 08 21:12:41 2013 +0200
@@ -216,25 +216,25 @@
         if (invoke.callTarget() instanceof MethodCallTargetNode) {
             final MethodCallTargetNode methodCallTargetNode = (MethodCallTargetNode) invoke.callTarget();
             if ((methodCallTargetNode.invokeKind() == InvokeKind.Special || methodCallTargetNode.invokeKind() == InvokeKind.Static) &&
-                            !Modifier.isNative(methodCallTargetNode.targetMethod().getModifiers())) {
-                if (methodCallTargetNode.targetMethod().getAnnotation(ExplodeLoop.class) != null) {
-                    // Do not inline explode loop methods, they need canonicalization and forced
-                    // unrolling.
-                    return invoke.asNode();
-                }
-                StructuredGraph inlinedGraph = Debug.scope("ExpandInvoke", methodCallTargetNode.targetMethod(), new Callable<StructuredGraph>() {
+                            !Modifier.isNative(methodCallTargetNode.targetMethod().getModifiers()) && methodCallTargetNode.targetMethod().getAnnotation(ExplodeLoop.class) == null) {
+                Class<? extends FixedWithNextNode> macroSubstitution = replacements.getMacroSubstitution(methodCallTargetNode.targetMethod());
+                if (macroSubstitution != null) {
+                    return InliningUtil.inlineMacroNode(invoke, methodCallTargetNode.targetMethod(), methodCallTargetNode.graph(), macroSubstitution);
+                } else {
+                    StructuredGraph inlinedGraph = Debug.scope("ExpandInvoke", methodCallTargetNode.targetMethod(), new Callable<StructuredGraph>() {
 
-                    public StructuredGraph call() {
-                        StructuredGraph inlineGraph = replacements.getMethodSubstitution(methodCallTargetNode.targetMethod());
-                        if (inlineGraph == null) {
-                            inlineGraph = parseGraph(methodCallTargetNode.targetMethod());
+                        public StructuredGraph call() {
+                            StructuredGraph inlineGraph = replacements.getMethodSubstitution(methodCallTargetNode.targetMethod());
+                            if (inlineGraph == null) {
+                                inlineGraph = parseGraph(methodCallTargetNode.targetMethod());
+                            }
+                            return inlineGraph;
                         }
-                        return inlineGraph;
-                    }
-                });
-                FixedNode fixedNode = (FixedNode) invoke.predecessor();
-                InliningUtil.inline(invoke, inlinedGraph, true);
-                return fixedNode;
+                    });
+                    FixedNode fixedNode = (FixedNode) invoke.predecessor();
+                    InliningUtil.inline(invoke, inlinedGraph, true);
+                    return fixedNode;
+                }
             }
         }
         return invoke.asNode();
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/UnsafeCastMacroNode.java	Mon Jul 08 17:32:05 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/UnsafeCastMacroNode.java	Mon Jul 08 21:12:41 2013 +0200
@@ -41,7 +41,10 @@
             Class c = (Class) arguments.get(1).asConstant().asObject();
             ResolvedJavaType lookupJavaType = tool.runtime().lookupJavaType(c);
             Stamp s = StampFactory.declaredNonNull(lookupJavaType);
-            return graph().unique(new UnsafeCastNode(arguments.get(0), s));
+            ValueAnchorNode valueAnchorNode = graph().add(new ValueAnchorNode());
+            UnsafeCastNode unsafeCast = graph().unique(new UnsafeCastNode(arguments.get(0), s, (GuardingNode) valueAnchorNode));
+            this.replaceAtUsages(unsafeCast);
+            return valueAnchorNode;
         }
         return this;
     }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/CompilerDirectivesSubstitutions.java	Mon Jul 08 17:32:05 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/CompilerDirectivesSubstitutions.java	Mon Jul 08 21:12:41 2013 +0200
@@ -57,4 +57,7 @@
 
     @MacroSubstitution(macro = BailoutNode.class, isStatic = true)
     public static native void bailout(String reason);
+
+    @MacroSubstitution(macro = UnsafeCastMacroNode.class, isStatic = true)
+    public static native Object unsafeCast(Object value, Class clazz);
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/OptimizedCallTargetSubstitutions.java	Mon Jul 08 17:32:05 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/OptimizedCallTargetSubstitutions.java	Mon Jul 08 21:12:41 2013 +0200
@@ -33,7 +33,7 @@
 public class OptimizedCallTargetSubstitutions {
 
     @MacroSubstitution(macro = NeverInlineMacroNode.class, isStatic = false)
-    public static native Object call(OptimizedCallTarget target, PackedFrame caller, Arguments args);
+    public static native Object interpreterCall(OptimizedCallTarget target, PackedFrame caller, Arguments args);
 
     @MethodSubstitution
     private static FrameWithoutBoxing createFrame(FrameDescriptor descriptor, PackedFrame caller, Arguments args) {
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CompilerDirectives.java	Mon Jul 08 17:32:05 2013 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CompilerDirectives.java	Mon Jul 08 21:12:41 2013 +0200
@@ -126,4 +126,17 @@
     @Target({ElementType.METHOD})
     public @interface Unsafe {
     }
+
+    /**
+     * Treats the given value as a value of the given class. The class must evaluate to a constant.
+     * 
+     * @param value the value that is known to have the specified type
+     * @param clazz the specified type of the value
+     * @return the value
+     */
+    @SuppressWarnings("unchecked")
+    @Unsafe
+    public static <T> T unsafeCast(Object value, Class<T> clazz) {
+        return (T) value;
+    }
 }
--- a/src/cpu/x86/vm/graalCodeInstaller_x86.hpp	Mon Jul 08 17:32:05 2013 +0200
+++ b/src/cpu/x86/vm/graalCodeInstaller_x86.hpp	Mon Jul 08 21:12:41 2013 +0200
@@ -179,7 +179,6 @@
       break;
     }
     default:
-      fatal("invalid _next_call_type value");
       break;
   }
 }