changeset 9694:b2ba1c6f9bf8

Merge.
author Doug Simon <doug.simon@oracle.com>
date Tue, 14 May 2013 21:43:06 +0200
parents d04944441454 (current diff) bd5c6b3dedc5 (diff)
children a39e67ca883b f8e0bf2c70e2
files graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/InitializeArrayNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/InitializeObjectNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/TLABAllocateNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/RuntimeCallStub.java
diffstat 30 files changed, 629 insertions(+), 440 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Architecture.java	Tue May 14 21:33:37 2013 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Architecture.java	Tue May 14 21:43:06 2013 +0200
@@ -198,7 +198,19 @@
         }
     }
 
+    /**
+     * Determine whether a kind can be stored in a register of a given category.
+     * 
+     * @param category the category of the register
+     * @param kind the kind that should be stored in the register
+     */
     public abstract boolean canStoreValue(RegisterCategory category, PlatformKind kind);
 
+    /**
+     * Return the largest kind that can be stored in a register of a given category.
+     * 
+     * @param category the category of the register
+     * @return the largest kind that can be stored in a register {@code category}
+     */
     public abstract PlatformKind getLargestStorableKind(RegisterCategory category);
 }
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Tue May 14 21:33:37 2013 +0200
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Tue May 14 21:43:06 2013 +0200
@@ -206,7 +206,7 @@
         return new AMD64AddressValue(target().wordKind, baseRegister, indexRegister, scaleEnum, displacementInt);
     }
 
-    private AMD64AddressValue asAddress(Value address) {
+    protected AMD64AddressValue asAddressValue(Value address) {
         if (address instanceof AMD64AddressValue) {
             return (AMD64AddressValue) address;
         } else {
@@ -216,7 +216,7 @@
 
     @Override
     public Variable emitLoad(Kind kind, Value address, DeoptimizingNode deopting) {
-        AMD64AddressValue loadAddress = asAddress(address);
+        AMD64AddressValue loadAddress = asAddressValue(address);
         Variable result = newVariable(kind);
         append(new LoadOp(kind, result, loadAddress, deopting != null ? state(deopting) : null));
         return result;
@@ -224,7 +224,7 @@
 
     @Override
     public void emitStore(Kind kind, Value address, Value inputVal, DeoptimizingNode deopting) {
-        AMD64AddressValue storeAddress = asAddress(address);
+        AMD64AddressValue storeAddress = asAddressValue(address);
         LIRFrameState state = deopting != null ? state(deopting) : null;
 
         if (isConstant(inputVal)) {
@@ -366,9 +366,7 @@
     @Override
     public void emitNullCheck(ValueNode v, DeoptimizingNode deoping) {
         assert v.kind() == Kind.Object;
-        Variable obj = newVariable(Kind.Object);
-        emitMove(obj, operand(v));
-        append(new AMD64Move.NullCheckOp(obj, state(deoping)));
+        append(new AMD64Move.NullCheckOp(load(operand(v)), state(deoping)));
     }
 
     @Override
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Tue May 14 21:33:37 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Tue May 14 21:43:06 2013 +0200
@@ -77,8 +77,8 @@
     protected final Backend backend;
 
     public GraalCompilerTest() {
+        this.replacements = Graal.getRequiredCapability(Replacements.class);
         this.runtime = Graal.getRequiredCapability(GraalCodeCacheProvider.class);
-        this.replacements = Graal.getRequiredCapability(Replacements.class);
         this.backend = Graal.getRequiredCapability(Backend.class);
     }
 
@@ -247,12 +247,17 @@
             this.returnValue = returnValue;
             this.exception = exception;
         }
+
+        @Override
+        public String toString() {
+            return exception == null ? returnValue == null ? "null" : returnValue.toString() : "!" + exception;
+        }
     }
 
     /**
      * Called before a test is executed.
      */
-    protected void before() {
+    protected void before(@SuppressWarnings("unused") Method method) {
     }
 
     /**
@@ -262,7 +267,7 @@
     }
 
     protected Result executeExpected(Method method, Object receiver, Object... args) {
-        before();
+        before(method);
         try {
             // This gives us both the expected return value as well as ensuring that the method to
             // be compiled is fully resolved
@@ -277,7 +282,7 @@
     }
 
     protected Result executeActual(Method method, Object receiver, Object... args) {
-        before();
+        before(method);
         Object[] executeArgs = argsWithReceiver(receiver, args);
 
         ResolvedJavaMethod javaMethod = runtime.lookupJavaMethod(method);
@@ -347,11 +352,24 @@
     }
 
     protected void test(Method method, Result expect, Object receiver, Object... args) {
+        test(method, expect, Collections.<DeoptimizationReason> emptySet(), receiver, args);
+    }
+
+    protected void test(Method method, Result expect, Set<DeoptimizationReason> shouldNotDeopt, Object receiver, Object... args) {
+        Map<DeoptimizationReason, Integer> deoptCounts = new EnumMap<>(DeoptimizationReason.class);
+        ProfilingInfo profile = runtime.lookupJavaMethod(method).getProfilingInfo();
+        for (DeoptimizationReason reason : shouldNotDeopt) {
+            deoptCounts.put(reason, profile.getDeoptimizationCount(reason));
+        }
         Result actual = executeActual(method, receiver, args);
+        for (DeoptimizationReason reason : shouldNotDeopt) {
+            Assert.assertEquals((int) deoptCounts.get(reason), profile.getDeoptimizationCount(reason));
+        }
 
         if (expect.exception != null) {
             Assert.assertTrue("expected " + expect.exception, actual.exception != null);
             Assert.assertEquals(expect.exception.getClass(), actual.exception.getClass());
+            Assert.assertEquals(expect.exception.getMessage(), actual.exception.getMessage());
         } else {
             if (actual.exception != null) {
                 actual.exception.printStackTrace();
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Tue May 14 21:33:37 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Tue May 14 21:43:06 2013 +0200
@@ -169,11 +169,10 @@
 
     @Override
     public Value setResult(ValueNode x, Value operand) {
-        assert (!isVariable(operand) || x.kind() == operand.getKind()) : operand.getKind() + " for node " + x;
         assert (!isRegister(operand) || !attributes(asRegister(operand)).isAllocatable());
         assert operand(x) == null : "operand cannot be set twice";
         assert operand != null && isLegal(operand) : "operand must be legal";
-        assert operand.getKind().getStackKind() == x.kind() : operand.getKind().getStackKind() + " must match " + x.kind();
+        assert operand.getKind().getStackKind() == x.kind() || x.kind() == Kind.Illegal : operand.getKind().getStackKind() + " must match " + x.kind();
         assert !(x instanceof VirtualObjectNode);
         nodeOperands.set(x, operand);
         return operand;
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/MidTier.java	Tue May 14 21:33:37 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/MidTier.java	Tue May 14 21:43:06 2013 +0200
@@ -72,5 +72,9 @@
         addPhase(new SafepointInsertionPhase());
 
         addPhase(new GuardLoweringPhase());
+
+        if (GraalOptions.OptCanonicalizer) {
+            addPhase(new CanonicalizerPhase());
+        }
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java	Tue May 14 21:33:37 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java	Tue May 14 21:43:06 2013 +0200
@@ -358,6 +358,9 @@
 
     @Override
     public boolean canBeInlined() {
+        if (dontInline) {
+            return false;
+        }
         return graalRuntime().getCompilerToVM().isMethodCompilable(metaspaceMethod);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Tue May 14 21:33:37 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Tue May 14 21:43:06 2013 +0200
@@ -285,15 +285,15 @@
             replacements.registerSubstitutions(ReflectionSubstitutions.class);
         }
 
-        TargetDescription target = graalRuntime.getTarget();
-        checkcastSnippets = new CheckCastSnippets.Templates(this, replacements, target);
-        instanceofSnippets = new InstanceOfSnippets.Templates(this, replacements, target);
-        newObjectSnippets = new NewObjectSnippets.Templates(this, replacements, target, config.useTLAB);
-        monitorSnippets = new MonitorSnippets.Templates(this, replacements, target, config.useFastLocking);
-        writeBarrierSnippets = new WriteBarrierSnippets.Templates(this, replacements, target);
-        boxingSnippets = new BoxingSnippets.Templates(this, replacements, target);
-        exceptionObjectSnippets = new LoadExceptionObjectSnippets.Templates(this, replacements, target);
+        checkcastSnippets = new CheckCastSnippets.Templates(this, replacements, graalRuntime.getTarget());
+        instanceofSnippets = new InstanceOfSnippets.Templates(this, replacements, graalRuntime.getTarget());
+        newObjectSnippets = new NewObjectSnippets.Templates(this, replacements, graalRuntime.getTarget());
+        monitorSnippets = new MonitorSnippets.Templates(this, replacements, graalRuntime.getTarget(), config.useFastLocking);
+        writeBarrierSnippets = new WriteBarrierSnippets.Templates(this, replacements, graalRuntime.getTarget());
+        boxingSnippets = new BoxingSnippets.Templates(this, replacements, graalRuntime.getTarget());
+        exceptionObjectSnippets = new LoadExceptionObjectSnippets.Templates(this, replacements, graalRuntime.getTarget());
 
+        TargetDescription target = getTarget();
         link(new NewInstanceStub(this, replacements, target, runtimeCalls.get(NEW_INSTANCE)));
         link(new NewArrayStub(this, replacements, target, runtimeCalls.get(NEW_ARRAY)));
         link(new NewMultiArrayStub(this, replacements, target, runtimeCalls.get(NEW_MULTI_ARRAY)));
@@ -670,7 +670,9 @@
                         if (value instanceof VirtualObjectNode) {
                             value = allocations[commit.getVirtualObjects().indexOf(value)];
                         }
-                        graph.addBeforeFixed(commit, graph.add(new WriteNode(newObject, value, createFieldLocation(graph, (HotSpotResolvedJavaField) instance.field(i)), WriteBarrierType.NONE)));
+                        if (!(value.isConstant() && value.asConstant().isDefaultForKind())) {
+                            graph.addBeforeFixed(commit, graph.add(new WriteNode(newObject, value, createFieldLocation(graph, (HotSpotResolvedJavaField) instance.field(i)), WriteBarrierType.NONE)));
+                        }
                     }
                 } else {
                     VirtualArrayNode array = (VirtualArrayNode) virtual;
@@ -682,7 +684,10 @@
                             assert indexOf != -1 : commit + " " + value;
                             value = allocations[indexOf];
                         }
-                        graph.addBeforeFixed(commit, graph.add(new WriteNode(newObject, value, createArrayLocation(graph, element.getKind(), ConstantNode.forInt(i, graph)), WriteBarrierType.NONE)));
+                        if (!(value.isConstant() && value.asConstant().isDefaultForKind())) {
+                            graph.addBeforeFixed(commit,
+                                            graph.add(new WriteNode(newObject, value, createArrayLocation(graph, element.getKind(), ConstantNode.forInt(i, graph)), WriteBarrierType.NONE)));
+                        }
                     }
                 }
             }
@@ -736,9 +741,9 @@
         } else if (n instanceof InstanceOfDynamicNode) {
             instanceofSnippets.lower((InstanceOfDynamicNode) n, tool);
         } else if (n instanceof NewInstanceNode) {
-            newObjectSnippets.lower((NewInstanceNode) n, tool);
+            newObjectSnippets.lower((NewInstanceNode) n);
         } else if (n instanceof NewArrayNode) {
-            newObjectSnippets.lower((NewArrayNode) n, tool);
+            newObjectSnippets.lower((NewArrayNode) n);
         } else if (n instanceof MonitorEnterNode) {
             monitorSnippets.lower((MonitorEnterNode) n, tool);
         } else if (n instanceof MonitorExitNode) {
@@ -747,14 +752,8 @@
             writeBarrierSnippets.lower((SerialWriteBarrier) n, tool);
         } else if (n instanceof SerialArrayRangeWriteBarrier) {
             writeBarrierSnippets.lower((SerialArrayRangeWriteBarrier) n, tool);
-        } else if (n instanceof TLABAllocateNode) {
-            newObjectSnippets.lower((TLABAllocateNode) n, tool);
-        } else if (n instanceof InitializeObjectNode) {
-            newObjectSnippets.lower((InitializeObjectNode) n, tool);
-        } else if (n instanceof InitializeArrayNode) {
-            newObjectSnippets.lower((InitializeArrayNode) n, tool);
         } else if (n instanceof NewMultiArrayNode) {
-            newObjectSnippets.lower((NewMultiArrayNode) n, tool);
+            newObjectSnippets.lower((NewMultiArrayNode) n);
         } else if (n instanceof LoadExceptionObjectNode) {
             exceptionObjectSnippets.lower((LoadExceptionObjectNode) n);
         } else if (n instanceof IntegerDivNode || n instanceof IntegerRemNode || n instanceof UnsignedDivNode || n instanceof UnsignedRemNode) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/InitializeArrayNode.java	Tue May 14 21:33:37 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,85 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.nodes;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
-
-/**
- * Initializes the header and body of an uninitialized array cell. This node calls out to a stub to
- * do both the allocation and formatting if the memory address it is given is zero/null (e.g. due to
- * {@linkplain TLABAllocateNode TLAB allocation} failing).
- */
-public final class InitializeArrayNode extends FixedWithNextNode implements Lowerable, ArrayLengthProvider {
-
-    @Input private final ValueNode memory;
-    @Input private final ValueNode length;
-    @Input private final ValueNode allocationSize;
-    private final ResolvedJavaType type;
-    private final boolean fillContents;
-
-    public InitializeArrayNode(ValueNode memory, ValueNode length, ValueNode allocationSize, ResolvedJavaType type, boolean fillContents) {
-        super(StampFactory.exactNonNull(type));
-        this.memory = memory;
-        this.type = type;
-        this.length = length;
-        this.allocationSize = allocationSize;
-        this.fillContents = fillContents;
-    }
-
-    public ValueNode memory() {
-        return memory;
-    }
-
-    @Override
-    public ValueNode length() {
-        return length;
-    }
-
-    /**
-     * Gets the size (in bytes) of the memory chunk allocated for the array.
-     */
-    public ValueNode allocationSize() {
-        return allocationSize;
-    }
-
-    public ResolvedJavaType type() {
-        return type;
-    }
-
-    public boolean fillContents() {
-        // We fill contents when G1 GC is used since we want to record
-        // the original field values prior to stores
-        return fillContents;
-    }
-
-    @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
-        tool.getRuntime().lower(this, tool);
-    }
-
-    @NodeIntrinsic
-    public static native Object initialize(Object memory, int length, int allocationSize, @ConstantNodeParameter ResolvedJavaType type, @ConstantNodeParameter boolean fillContents);
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/InitializeObjectNode.java	Tue May 14 21:33:37 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,64 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.nodes;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
-
-/**
- * Initializes the header and body of an uninitialized object cell. This node calls out to a stub to
- * do both the allocation and formatting if the memory address it is given is zero/null (e.g. due to
- * {@linkplain TLABAllocateNode TLAB allocation} failing).
- */
-public final class InitializeObjectNode extends FixedWithNextNode implements Lowerable {
-
-    @Input private final ValueNode memory;
-    private final ResolvedJavaType type;
-    private final boolean fillContents;
-
-    public InitializeObjectNode(ValueNode memory, ResolvedJavaType type, boolean fillContents) {
-        super(StampFactory.exactNonNull(type));
-        this.memory = memory;
-        this.type = type;
-        this.fillContents = fillContents;
-    }
-
-    public ValueNode memory() {
-        return memory;
-    }
-
-    public ResolvedJavaType type() {
-        return type;
-    }
-
-    public boolean fillContents() {
-        return fillContents;
-    }
-
-    @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
-        tool.getRuntime().lower(this, tool);
-    }
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/TLABAllocateNode.java	Tue May 14 21:33:37 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.nodes;
-
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.word.*;
-
-/**
- * Allocates some uninitialized area. This is used for TLAB allocation only. If allocation fails,
- * zero/null is produced by this node.
- */
-public final class TLABAllocateNode extends FixedWithNextNode implements Lowerable {
-
-    @Input private ValueNode size;
-
-    public TLABAllocateNode(ValueNode size) {
-        super(StampFactory.forWord());
-        this.size = size;
-    }
-
-    public ValueNode size() {
-        return size;
-    }
-
-    @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
-        tool.getRuntime().lower(this, tool);
-    }
-
-    /**
-     * @return null if allocation fails
-     */
-    @NodeIntrinsic
-    public static native Word allocateVariableSize(int size);
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AbstractMethodHandleNode.java	Tue May 14 21:43:06 2013 +0200
@@ -0,0 +1,283 @@
+/*
+ * 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.hotspot.replacements;
+
+import java.lang.reflect.Modifier;
+import java.util.Arrays;
+
+import com.oracle.graal.api.meta.Constant;
+import com.oracle.graal.api.meta.JavaType;
+import com.oracle.graal.api.meta.ResolvedJavaField;
+import com.oracle.graal.api.meta.ResolvedJavaMethod;
+import com.oracle.graal.api.meta.ResolvedJavaType;
+import com.oracle.graal.graph.GraalInternalError;
+import com.oracle.graal.graph.NodeInputList;
+import com.oracle.graal.hotspot.meta.HotSpotResolvedJavaMethod;
+import com.oracle.graal.hotspot.meta.HotSpotResolvedObjectType;
+import com.oracle.graal.hotspot.meta.HotSpotSignature;
+import com.oracle.graal.nodes.CallTargetNode;
+import com.oracle.graal.nodes.Invoke;
+import com.oracle.graal.nodes.InvokeNode;
+import com.oracle.graal.nodes.PiNode;
+import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.nodes.java.MethodCallTargetNode;
+import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
+import com.oracle.graal.nodes.java.SelfReplacingMethodCallTargetNode;
+import com.oracle.graal.nodes.spi.Canonicalizable;
+import com.oracle.graal.nodes.type.StampFactory;
+import com.oracle.graal.replacements.nodes.MacroNode;
+
+/**
+ * Common base class for method handle invoke nodes.
+ */
+public abstract class AbstractMethodHandleNode extends MacroNode implements Canonicalizable {
+
+    private static final ResolvedJavaField methodHandleFormField;
+    private static final ResolvedJavaField lambdaFormVmentryField;
+    private static final ResolvedJavaField memberNameClazzField;
+    private static final ResolvedJavaField memberNameVmtargetField;
+
+    // Replacement method data
+    private ResolvedJavaMethod replacementTargetMethod;
+    private JavaType replacementReturnType;
+    @Input private NodeInputList<ValueNode> replacementArguments;
+
+    /**
+     * Search for an instance field with the given name in a class.
+     * 
+     * @param className name of the class to search in
+     * @param fieldName name of the field to be searched
+     * @return resolved java field
+     * @throws ClassNotFoundException
+     */
+    private static ResolvedJavaField findFieldInClass(String className, String fieldName) throws ClassNotFoundException {
+        Class<?> clazz = Class.forName(className);
+        ResolvedJavaType type = HotSpotResolvedObjectType.fromClass(clazz);
+        ResolvedJavaField[] fields = type.getInstanceFields(false);
+        for (ResolvedJavaField field : fields) {
+            if (field.getName().equals(fieldName)) {
+                return field;
+            }
+        }
+        return null;
+    }
+
+    static {
+        try {
+            methodHandleFormField = findFieldInClass("java.lang.invoke.MethodHandle", "form");
+            lambdaFormVmentryField = findFieldInClass("java.lang.invoke.LambdaForm", "vmentry");
+            memberNameClazzField = findFieldInClass("java.lang.invoke.MemberName", "clazz");
+            memberNameVmtargetField = findFieldInClass("java.lang.invoke.MemberName", "vmtarget");
+        } catch (ClassNotFoundException | SecurityException ex) {
+            throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
+    public AbstractMethodHandleNode(Invoke invoke) {
+        super(invoke);
+
+        // See if we need to save some replacement method data.
+        CallTargetNode callTarget = invoke.callTarget();
+        if (callTarget instanceof SelfReplacingMethodCallTargetNode) {
+            SelfReplacingMethodCallTargetNode selfReplacingMethodCallTargetNode = (SelfReplacingMethodCallTargetNode) callTarget;
+            replacementTargetMethod = selfReplacingMethodCallTargetNode.replacementTargetMethod();
+            replacementReturnType = selfReplacingMethodCallTargetNode.replacementReturnType();
+            replacementArguments = selfReplacingMethodCallTargetNode.replacementArguments();
+        } else {
+            // NodeInputList can't be null.
+            replacementArguments = new NodeInputList<>(this);
+        }
+    }
+
+    /**
+     * Get the receiver of a MethodHandle.invokeBasic call.
+     * 
+     * @return the receiver argument node
+     */
+    private ValueNode getReceiver() {
+        return arguments.first();
+    }
+
+    /**
+     * Get the MemberName argument of a MethodHandle.linkTo* call.
+     * 
+     * @return the MemberName argument node (which is the last argument)
+     */
+    private ValueNode getMemberName() {
+        return arguments.last();
+    }
+
+    /**
+     * Used from {@link MethodHandleInvokeBasicNode} to get the target {@link InvokeNode} if the
+     * method handle receiver is constant.
+     * 
+     * @return invoke node for the {@link java.lang.invoke.MethodHandle} target
+     */
+    protected InvokeNode getInvokeBasicTarget() {
+        ValueNode methodHandleNode = getReceiver();
+        if (methodHandleNode.isConstant() && !methodHandleNode.isNullConstant()) {
+            // Get the data we need from MethodHandle.LambdaForm.MemberName
+            Constant methodHandle = methodHandleNode.asConstant();
+            Constant lambdaForm = methodHandleFormField.readValue(methodHandle);
+            Constant memberName = lambdaFormVmentryField.readValue(lambdaForm);
+            return getTargetInvokeNode(memberName);
+        }
+        return null;
+    }
+
+    /**
+     * Used from {@link MethodHandleLinkToStaticNode}, {@link MethodHandleLinkToSpecialNode},
+     * {@link MethodHandleLinkToVirtualNode}, and {@link MethodHandleLinkToInterfaceNode} to get the
+     * target {@link InvokeNode} if the member name argument is constant.
+     * 
+     * @return invoke node for the member name target
+     */
+    protected InvokeNode getLinkToTarget() {
+        ValueNode memberNameNode = getMemberName();
+        if (memberNameNode.isConstant() && !memberNameNode.isNullConstant()) {
+            Constant memberName = memberNameNode.asConstant();
+            return getTargetInvokeNode(memberName);
+        }
+        return null;
+    }
+
+    /**
+     * Helper function to get the {@link InvokeNode} for the vmtarget of a
+     * java.lang.invoke.MemberName.
+     * 
+     * @param memberName constant member name node
+     * @return invoke node for the member name target
+     */
+    private InvokeNode getTargetInvokeNode(Constant memberName) {
+        // Get the data we need from MemberName
+        Constant clazz = memberNameClazzField.readValue(memberName);
+        Constant vmtarget = memberNameVmtargetField.readValue(memberName);
+
+        // Create a method from the vmtarget pointer
+        Class<?> c = (Class<?>) clazz.asObject();
+        HotSpotResolvedObjectType holderClass = (HotSpotResolvedObjectType) HotSpotResolvedObjectType.fromClass(c);
+        HotSpotResolvedJavaMethod targetMethod = holderClass.createMethod(vmtarget.asLong());
+
+        // In lamda forms we erase signature types to avoid resolving issues
+        // involving class loaders. When we optimize a method handle invoke
+        // to a direct call we must cast the receiver and arguments to its
+        // actual types.
+        HotSpotSignature signature = targetMethod.getSignature();
+        final boolean isStatic = Modifier.isStatic(targetMethod.getModifiers());
+        final int receiverSkip = isStatic ? 0 : 1;
+
+        // Cast receiver to its type.
+        if (!isStatic) {
+            JavaType receiverType = holderClass;
+            maybeCastArgument(0, receiverType);
+        }
+
+        // Cast reference arguments to its type.
+        for (int index = 0; index < signature.getParameterCount(false); index++) {
+            JavaType parameterType = signature.getParameterType(index, holderClass);
+            maybeCastArgument(receiverSkip + index, parameterType);
+        }
+
+        // Try to get the most accurate receiver type
+        if (this instanceof MethodHandleLinkToVirtualNode || this instanceof MethodHandleLinkToInterfaceNode) {
+            ResolvedJavaType receiverType = getReceiver().objectStamp().type();
+            if (receiverType != null) {
+                ResolvedJavaMethod concreteMethod = receiverType.findUniqueConcreteMethod(targetMethod);
+                if (concreteMethod != null) {
+                    return createTargetInvokeNode(concreteMethod);
+                }
+            }
+        }
+
+        if (targetMethod.canBeStaticallyBound()) {
+            return createTargetInvokeNode(targetMethod);
+        }
+
+        ResolvedJavaMethod concreteMethod = targetMethod.uniqueConcreteMethod();
+        if (concreteMethod != null) {
+            return createTargetInvokeNode(concreteMethod);
+        }
+
+        return null;
+    }
+
+    /**
+     * Inserts a node to cast the argument at index to the given type if the given type is more
+     * concrete than the argument type.
+     * 
+     * @param index of the argument to be cast
+     * @param type the type the argument should be cast to
+     */
+    private void maybeCastArgument(int index, JavaType type) {
+        if (type instanceof ResolvedJavaType) {
+            ResolvedJavaType targetType = (ResolvedJavaType) type;
+            if (!targetType.isPrimitive()) {
+                ValueNode argument = arguments.get(index);
+                ResolvedJavaType argumentType = argument.objectStamp().type();
+                if (argumentType == null || (argumentType.isAssignableFrom(targetType) && !argumentType.equals(targetType))) {
+                    PiNode piNode = graph().unique(new PiNode(argument, StampFactory.declared(targetType)));
+                    arguments.set(index, piNode);
+                }
+            }
+        }
+    }
+
+    /**
+     * Creates an {@link InvokeNode} for the given target method. The {@link CallTargetNode} passed
+     * to the InvokeNode is in fact a {@link SelfReplacingMethodCallTargetNode}.
+     * 
+     * @param targetMethod the method the be called
+     * @return invoke node for the member name target
+     */
+    private InvokeNode createTargetInvokeNode(ResolvedJavaMethod targetMethod) {
+        InvokeKind invokeKind = Modifier.isStatic(targetMethod.getModifiers()) ? InvokeKind.Static : InvokeKind.Special;
+        JavaType returnType = targetMethod.getSignature().getReturnType(null);
+
+        // MethodHandleLinkTo* nodes have a trailing MemberName argument which
+        // needs to be popped.
+        ValueNode[] originalArguments = arguments.toArray(new ValueNode[arguments.size()]);
+        ValueNode[] targetArguments;
+        if (this instanceof MethodHandleInvokeBasicNode) {
+            targetArguments = originalArguments;
+        } else {
+            assert this instanceof MethodHandleLinkToStaticNode || this instanceof MethodHandleLinkToSpecialNode || this instanceof MethodHandleLinkToVirtualNode ||
+                            this instanceof MethodHandleLinkToInterfaceNode : this;
+            targetArguments = Arrays.copyOfRange(originalArguments, 0, arguments.size() - 1);
+        }
+
+        // If there is already replacement information, use that instead.
+        MethodCallTargetNode callTarget;
+        if (replacementTargetMethod == null) {
+            callTarget = new SelfReplacingMethodCallTargetNode(invokeKind, targetMethod, targetArguments, returnType, getTargetMethod(), originalArguments, getReturnType());
+        } else {
+            ValueNode[] args = replacementArguments.toArray(new ValueNode[replacementArguments.size()]);
+            callTarget = new SelfReplacingMethodCallTargetNode(invokeKind, targetMethod, targetArguments, returnType, replacementTargetMethod, args, replacementReturnType);
+        }
+
+        graph().add(callTarget);
+        InvokeNode invoke = graph().add(new InvokeNode(callTarget, getBci()));
+        invoke.setStateAfter(stateAfter());
+        return invoke;
+    }
+
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleInvokeBasicNode.java	Tue May 14 21:33:37 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleInvokeBasicNode.java	Tue May 14 21:43:06 2013 +0200
@@ -22,17 +22,29 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
-import java.lang.invoke.*;
+import java.lang.invoke.MethodHandle;
 
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.replacements.nodes.*;
+import com.oracle.graal.nodes.Invoke;
+import com.oracle.graal.nodes.InvokeNode;
+import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.nodes.spi.CanonicalizerTool;
 
 /**
  * Macro node for {@link MethodHandle}{@code .invokeBasic(Object...)}.
  */
-public class MethodHandleInvokeBasicNode extends MacroNode {
+public class MethodHandleInvokeBasicNode extends AbstractMethodHandleNode {
 
     public MethodHandleInvokeBasicNode(Invoke invoke) {
         super(invoke);
     }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool) {
+        InvokeNode invoke = getInvokeBasicTarget();
+        if (invoke != null) {
+            return invoke;
+        }
+        return this;
+    }
+
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleLinkToInterfaceNode.java	Tue May 14 21:33:37 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleLinkToInterfaceNode.java	Tue May 14 21:43:06 2013 +0200
@@ -22,17 +22,29 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
-import java.lang.invoke.*;
+import java.lang.invoke.MethodHandle;
 
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.replacements.nodes.*;
+import com.oracle.graal.nodes.Invoke;
+import com.oracle.graal.nodes.InvokeNode;
+import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.nodes.spi.CanonicalizerTool;
 
 /**
  * Macro node for {@link MethodHandle}{@code .linkToInterface(Object...)}.
  */
-public class MethodHandleLinkToInterfaceNode extends MacroNode {
+public class MethodHandleLinkToInterfaceNode extends AbstractMethodHandleNode {
 
     public MethodHandleLinkToInterfaceNode(Invoke invoke) {
         super(invoke);
     }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool) {
+        InvokeNode invoke = getLinkToTarget();
+        if (invoke != null) {
+            return invoke;
+        }
+        return this;
+    }
+
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleLinkToSpecialNode.java	Tue May 14 21:33:37 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleLinkToSpecialNode.java	Tue May 14 21:43:06 2013 +0200
@@ -22,17 +22,29 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
-import java.lang.invoke.*;
+import java.lang.invoke.MethodHandle;
 
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.replacements.nodes.*;
+import com.oracle.graal.nodes.Invoke;
+import com.oracle.graal.nodes.InvokeNode;
+import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.nodes.spi.CanonicalizerTool;
 
 /**
  * Macro node for {@link MethodHandle}{@code .linkToSpecial(Object...)}.
  */
-public class MethodHandleLinkToSpecialNode extends MacroNode {
+public class MethodHandleLinkToSpecialNode extends AbstractMethodHandleNode {
 
     public MethodHandleLinkToSpecialNode(Invoke invoke) {
         super(invoke);
     }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool) {
+        InvokeNode invoke = getLinkToTarget();
+        if (invoke != null) {
+            return invoke;
+        }
+        return this;
+    }
+
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleLinkToStaticNode.java	Tue May 14 21:33:37 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleLinkToStaticNode.java	Tue May 14 21:43:06 2013 +0200
@@ -22,17 +22,29 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
-import java.lang.invoke.*;
+import java.lang.invoke.MethodHandle;
 
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.replacements.nodes.*;
+import com.oracle.graal.nodes.Invoke;
+import com.oracle.graal.nodes.InvokeNode;
+import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.nodes.spi.CanonicalizerTool;
 
 /**
  * Macro node for {@link MethodHandle}{@code .linkToStatic(Object...)}.
  */
-public class MethodHandleLinkToStaticNode extends MacroNode {
+public class MethodHandleLinkToStaticNode extends AbstractMethodHandleNode {
 
     public MethodHandleLinkToStaticNode(Invoke invoke) {
         super(invoke);
     }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool) {
+        InvokeNode invoke = getLinkToTarget();
+        if (invoke != null) {
+            return invoke;
+        }
+        return this;
+    }
+
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleLinkToVirtualNode.java	Tue May 14 21:33:37 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleLinkToVirtualNode.java	Tue May 14 21:43:06 2013 +0200
@@ -22,17 +22,29 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
-import java.lang.invoke.*;
+import java.lang.invoke.MethodHandle;
 
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.replacements.nodes.*;
+import com.oracle.graal.nodes.Invoke;
+import com.oracle.graal.nodes.InvokeNode;
+import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.nodes.spi.CanonicalizerTool;
 
 /**
  * Macro node for {@link MethodHandle}{@code .linkToVirtual(Object...)}.
  */
-public class MethodHandleLinkToVirtualNode extends MacroNode {
+public class MethodHandleLinkToVirtualNode extends AbstractMethodHandleNode {
 
     public MethodHandleLinkToVirtualNode(Invoke invoke) {
         super(invoke);
     }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool) {
+        InvokeNode invoke = getLinkToTarget();
+        if (invoke != null) {
+            return invoke;
+        }
+        return this;
+    }
+
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Tue May 14 21:33:37 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Tue May 14 21:43:06 2013 +0200
@@ -72,54 +72,52 @@
     }
 
     @Snippet
-    public static Object initializeObject(Word memory, Word hub, Word prototypeMarkWord, @ConstantParameter int size, @ConstantParameter boolean fillContents) {
-
+    public static Object allocateInstance(@ConstantParameter int size, Word hub, Word prototypeMarkWord, @ConstantParameter boolean fillContents) {
         Object result;
-        if (probability(SLOW_PATH_PROBABILITY, memory.equal(0))) {
+        Word thread = thread();
+        Word top = readTlabTop(thread);
+        Word end = readTlabEnd(thread);
+        Word newTop = top.add(size);
+        if (useTLAB() && probability(FAST_PATH_PROBABILITY, newTop.belowOrEqual(end))) {
+            writeTlabTop(thread, newTop);
+            result = formatObject(hub, size, top, prototypeMarkWord, fillContents);
+        } else {
             new_stub.inc();
             result = NewInstanceStubCall.call(hub);
-        } else {
-            formatObject(hub, size, memory, prototypeMarkWord, fillContents);
-            result = memory.toObject();
         }
-        /*
-         * make sure that the unsafeCast is anchored after initialization, see ReadAfterCheckCast
-         * and CheckCastSnippets
-         */
         BeginNode anchorNode = BeginNode.anchor(StampFactory.forNodeIntrinsic());
         return unsafeCast(verifyOop(result), StampFactory.forNodeIntrinsic(), anchorNode);
     }
 
-    @Snippet
-    public static Object initializeArray(Word memory, Word hub, int length, int allocationSize, Word prototypeMarkWord, @ConstantParameter int headerSize, @ConstantParameter boolean fillContents) {
-        Object result;
-        if (probability(SLOW_PATH_PROBABILITY, memory.equal(0))) {
-            newarray_stub.inc();
-            result = NewArrayStubCall.call(hub, length);
-        } else {
-            newarray_loopInit.inc();
-            formatArray(hub, allocationSize, length, headerSize, memory, prototypeMarkWord, fillContents);
-            result = memory.toObject();
-        }
-        BeginNode anchorNode = BeginNode.anchor(StampFactory.forNodeIntrinsic());
-        return unsafeArrayCast(verifyOop(result), length, StampFactory.forNodeIntrinsic(), anchorNode);
-    }
-
     /**
      * Maximum array length for which fast path allocation is used.
      */
     public static final int MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH = 0x00FFFFFF;
 
     @Snippet
-    public static Object allocateArrayAndInitialize(int length, @ConstantParameter int alignment, @ConstantParameter int headerSize, @ConstantParameter int log2ElementSize,
-                    @ConstantParameter boolean fillContents, @ConstantParameter ResolvedJavaType type) {
+    public static Object allocateArray(Word hub, int length, Word prototypeMarkWord, @ConstantParameter int headerSize, @ConstantParameter int log2ElementSize, @ConstantParameter boolean fillContents) {
         if (!belowThan(length, MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH)) {
             // This handles both negative array sizes and very large array sizes
             DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
         }
+
+        Object result;
+        int alignment = wordSize();
         int allocationSize = computeArrayAllocationSize(length, alignment, headerSize, log2ElementSize);
-        Word memory = TLABAllocateNode.allocateVariableSize(allocationSize);
-        return InitializeArrayNode.initialize(memory, length, allocationSize, type, fillContents);
+        Word thread = thread();
+        Word top = readTlabTop(thread);
+        Word end = readTlabEnd(thread);
+        Word newTop = top.add(allocationSize);
+        if (useTLAB() && probability(FAST_PATH_PROBABILITY, newTop.belowOrEqual(end))) {
+            writeTlabTop(thread, newTop);
+            newarray_loopInit.inc();
+            result = formatArray(hub, allocationSize, length, headerSize, top, prototypeMarkWord, fillContents);
+        } else {
+            newarray_stub.inc();
+            result = NewArrayStubCall.call(hub, length);
+        }
+        BeginNode anchorNode = BeginNode.anchor(StampFactory.forNodeIntrinsic());
+        return unsafeArrayCast(verifyOop(result), length, StampFactory.forNodeIntrinsic(), anchorNode);
     }
 
     /**
@@ -160,7 +158,7 @@
     /**
      * Formats some allocated memory with an object header zeroes out the rest.
      */
-    private static void formatObject(Word hub, int size, Word memory, Word compileTimePrototypeMarkWord, boolean fillContents) {
+    private static Object formatObject(Word hub, int size, Word memory, Word compileTimePrototypeMarkWord, boolean fillContents) {
         Word prototypeMarkWord = useBiasedLocking() ? hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION) : compileTimePrototypeMarkWord;
         initializeObjectHeader(memory, prototypeMarkWord, hub);
         if (fillContents) {
@@ -177,12 +175,13 @@
                 }
             }
         }
+        return memory.toObject();
     }
 
     /**
-     * Formats some allocated memory with an object header zeroes out the rest.
+     * Formats some allocated memory with an object header and zeroes out the rest.
      */
-    public static void formatArray(Word hub, int allocationSize, int length, int headerSize, Word memory, Word prototypeMarkWord, boolean fillContents) {
+    public static Object formatArray(Word hub, int allocationSize, int length, int headerSize, Word memory, Word prototypeMarkWord, boolean fillContents) {
         memory.writeInt(arrayLengthOffset(), length, ANY_LOCATION);
         /*
          * store hub last as the concurrent garbage collectors assume length is valid if hub field
@@ -194,151 +193,66 @@
                 memory.writeWord(offset, Word.zero(), ANY_LOCATION);
             }
         }
+        return memory.toObject();
     }
 
     public static class Templates extends AbstractTemplates {
 
-        private final SnippetInfo allocate = snippet(NewObjectSnippets.class, "allocate");
-        private final SnippetInfo initializeObject = snippet(NewObjectSnippets.class, "initializeObject");
-        private final SnippetInfo initializeArray = snippet(NewObjectSnippets.class, "initializeArray");
-        private final SnippetInfo allocateArrayAndInitialize = snippet(NewObjectSnippets.class, "allocateArrayAndInitialize");
+        private final SnippetInfo allocateInstance = snippet(NewObjectSnippets.class, "allocateInstance");
+        private final SnippetInfo allocateArray = snippet(NewObjectSnippets.class, "allocateArray");
         private final SnippetInfo newmultiarray = snippet(NewObjectSnippets.class, "newmultiarray");
 
-        private final boolean useTLAB;
-
-        public Templates(CodeCacheProvider runtime, Replacements replacements, TargetDescription target, boolean useTLAB) {
+        public Templates(CodeCacheProvider runtime, Replacements replacements, TargetDescription target) {
             super(runtime, replacements, target);
-            this.useTLAB = useTLAB;
         }
 
         /**
          * Lowers a {@link NewInstanceNode}.
          */
-        @SuppressWarnings("unused")
-        public void lower(NewInstanceNode newInstanceNode, LoweringTool tool) {
+        public void lower(NewInstanceNode newInstanceNode) {
             StructuredGraph graph = newInstanceNode.graph();
             HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) newInstanceNode.instanceClass();
+            assert !type.isArray();
             ConstantNode hub = ConstantNode.forConstant(type.klass(), runtime, graph);
             int size = instanceSize(type);
 
-            ValueNode memory;
-            if (!useTLAB) {
-                memory = ConstantNode.defaultForKind(target.wordKind, graph);
-            } else {
-                ConstantNode sizeNode = ConstantNode.forInt(size, graph);
-                TLABAllocateNode tlabAllocateNode = graph.add(new TLABAllocateNode(sizeNode));
-                graph.addBeforeFixed(newInstanceNode, tlabAllocateNode);
-                memory = tlabAllocateNode;
-            }
-            InitializeObjectNode initializeNode = graph.add(new InitializeObjectNode(memory, type, newInstanceNode.fillContents()));
-            graph.replaceFixedWithFixed(newInstanceNode, initializeNode);
+            Arguments args = new Arguments(allocateInstance);
+            args.addConst("size", size);
+            args.add("hub", hub);
+            args.add("prototypeMarkWord", type.prototypeMarkWord());
+            args.addConst("fillContents", newInstanceNode.fillContents());
+
+            SnippetTemplate template = template(args);
+            Debug.log("Lowering allocateInstance in %s: node=%s, template=%s, arguments=%s", graph, newInstanceNode, template, args);
+            template.instantiate(runtime, newInstanceNode, DEFAULT_REPLACER, args);
         }
 
         /**
          * Lowers a {@link NewArrayNode}.
          */
-        @SuppressWarnings("unused")
-        public void lower(NewArrayNode newArrayNode, LoweringTool tool) {
+        public void lower(NewArrayNode newArrayNode) {
             StructuredGraph graph = newArrayNode.graph();
-            ValueNode lengthNode = newArrayNode.length();
-            TLABAllocateNode tlabAllocateNode;
             ResolvedJavaType elementType = newArrayNode.elementType();
-            ResolvedJavaType arrayType = elementType.getArrayClass();
+            HotSpotResolvedObjectType arrayType = (HotSpotResolvedObjectType) elementType.getArrayClass();
             Kind elementKind = elementType.getKind();
-            final int alignment = target.wordSize;
+            ConstantNode hub = ConstantNode.forConstant(arrayType.klass(), runtime, graph);
             final int headerSize = HotSpotRuntime.getArrayBaseOffset(elementKind);
-            final Integer length = lengthNode.isConstant() ? Integer.valueOf(lengthNode.asConstant().asInt()) : null;
             int log2ElementSize = CodeUtil.log2(target.arch.getSizeInBytes(elementKind));
-            if (!useTLAB) {
-                ConstantNode zero = ConstantNode.defaultForKind(target.wordKind, graph);
-                /*
-                 * value for 'size' doesn't matter as it isn't used since a stub call will be made
-                 * anyway for both allocation and initialization - it just needs to be non-null
-                 */
-                ConstantNode size = ConstantNode.forInt(-1, graph);
-                InitializeArrayNode initializeNode = graph.add(new InitializeArrayNode(zero, lengthNode, size, arrayType, newArrayNode.fillContents()));
-                graph.replaceFixedWithFixed(newArrayNode, initializeNode);
-            } else if (length != null && belowThan(length, MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH)) {
-                // Calculate aligned size
-                int size = computeArrayAllocationSize(length, alignment, headerSize, log2ElementSize);
-                ConstantNode sizeNode = ConstantNode.forInt(size, graph);
-                tlabAllocateNode = graph.add(new TLABAllocateNode(sizeNode));
-                graph.addBeforeFixed(newArrayNode, tlabAllocateNode);
-                InitializeArrayNode initializeNode = graph.add(new InitializeArrayNode(tlabAllocateNode, lengthNode, sizeNode, arrayType, newArrayNode.fillContents()));
-                graph.replaceFixedWithFixed(newArrayNode, initializeNode);
-            } else {
-                Arguments args = new Arguments(allocateArrayAndInitialize);
-                args.add("length", lengthNode);
-                args.addConst("alignment", alignment);
-                args.addConst("headerSize", headerSize);
-                args.addConst("log2ElementSize", log2ElementSize);
-                args.addConst("fillContents", newArrayNode.fillContents());
-                args.addConst("type", arrayType);
 
-                SnippetTemplate template = template(args);
-                Debug.log("Lowering allocateArrayAndInitialize in %s: node=%s, template=%s, arguments=%s", graph, newArrayNode, template, args);
-                template.instantiate(runtime, newArrayNode, DEFAULT_REPLACER, args);
-            }
-        }
-
-        @SuppressWarnings("unused")
-        public void lower(TLABAllocateNode tlabAllocateNode, LoweringTool tool) {
-            StructuredGraph graph = tlabAllocateNode.graph();
-            ValueNode size = tlabAllocateNode.size();
-            Arguments args = new Arguments(allocate).add("size", size);
+            Arguments args = new Arguments(allocateArray);
+            args.add("hub", hub);
+            args.add("length", newArrayNode.length());
+            args.add("prototypeMarkWord", arrayType.prototypeMarkWord());
+            args.addConst("headerSize", headerSize);
+            args.addConst("log2ElementSize", log2ElementSize);
+            args.addConst("fillContents", newArrayNode.fillContents());
 
             SnippetTemplate template = template(args);
-            Debug.log("Lowering fastAllocate in %s: node=%s, template=%s, arguments=%s", graph, tlabAllocateNode, template, args);
-            template.instantiate(runtime, tlabAllocateNode, DEFAULT_REPLACER, args);
-        }
-
-        @SuppressWarnings("unused")
-        public void lower(InitializeObjectNode initializeNode, LoweringTool tool) {
-            StructuredGraph graph = initializeNode.graph();
-            HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) initializeNode.type();
-            assert !type.isArray();
-            ConstantNode hub = ConstantNode.forConstant(type.klass(), runtime, graph);
-            int size = instanceSize(type);
-            ValueNode memory = initializeNode.memory();
-
-            Arguments args = new Arguments(initializeObject);
-            args.add("memory", memory);
-            args.add("hub", hub);
-            args.add("prototypeMarkWord", type.prototypeMarkWord());
-            args.addConst("size", size).addConst("fillContents", initializeNode.fillContents());
-
-            SnippetTemplate template = template(args);
-            Debug.log("Lowering initializeObject in %s: node=%s, template=%s, arguments=%s", graph, initializeNode, template, args);
-            template.instantiate(runtime, initializeNode, DEFAULT_REPLACER, args);
+            Debug.log("Lowering allocateArray in %s: node=%s, template=%s, arguments=%s", graph, newArrayNode, template, args);
+            template.instantiate(runtime, newArrayNode, DEFAULT_REPLACER, args);
         }
 
-        @SuppressWarnings("unused")
-        public void lower(InitializeArrayNode initializeNode, LoweringTool tool) {
-            StructuredGraph graph = initializeNode.graph();
-            HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) initializeNode.type();
-            ResolvedJavaType elementType = type.getComponentType();
-            assert elementType != null;
-            ConstantNode hub = ConstantNode.forConstant(type.klass(), runtime, graph);
-            Kind elementKind = elementType.getKind();
-            final int headerSize = HotSpotRuntime.getArrayBaseOffset(elementKind);
-            ValueNode memory = initializeNode.memory();
-
-            Arguments args = new Arguments(initializeArray);
-            args.add("memory", memory);
-            args.add("hub", hub);
-            args.add("length", initializeNode.length());
-            args.add("allocationSize", initializeNode.allocationSize());
-            args.add("prototypeMarkWord", type.prototypeMarkWord());
-            args.addConst("headerSize", headerSize);
-            args.addConst("fillContents", initializeNode.fillContents());
-
-            SnippetTemplate template = template(args);
-            Debug.log("Lowering initializeArray in %s: node=%s, template=%s, arguments=%s", graph, initializeNode, template, args);
-            template.instantiate(runtime, initializeNode, DEFAULT_REPLACER, args);
-        }
-
-        @SuppressWarnings("unused")
-        public void lower(NewMultiArrayNode newmultiarrayNode, LoweringTool tool) {
+        public void lower(NewMultiArrayNode newmultiarrayNode) {
             StructuredGraph graph = newmultiarrayNode.graph();
             int rank = newmultiarrayNode.dimensionCount();
             ValueNode[] dims = new ValueNode[rank];
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java	Tue May 14 21:33:37 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java	Tue May 14 21:43:06 2013 +0200
@@ -52,11 +52,10 @@
 
     private static Object instanceClone(Object src, Word hub, int layoutHelper) {
         int instanceSize = layoutHelper;
-        Pointer memory = NewObjectSnippets.allocate(instanceSize);
         Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION);
-        Object result = NewObjectSnippets.initializeObject((Word) memory, hub, prototypeMarkWord, instanceSize, false);
+        Object result = NewObjectSnippets.allocateInstance(instanceSize, hub, prototypeMarkWord, false);
 
-        memory = Word.fromObject(result);
+        Pointer memory = Word.fromObject(result);
         for (int offset = 2 * wordSize(); offset < instanceSize; offset += wordSize()) {
             memory.writeWord(offset, Word.fromObject(src).readWord(offset, ANY_LOCATION), ANY_LOCATION);
         }
@@ -70,11 +69,10 @@
         int headerSize = (layoutHelper >> layoutHelperHeaderSizeShift()) & layoutHelperHeaderSizeMask();
         int sizeInBytes = NewObjectSnippets.computeArrayAllocationSize(arrayLength, wordSize(), headerSize, log2ElementSize);
 
-        Pointer memory = NewObjectSnippets.allocate(sizeInBytes);
         Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION);
-        Object result = NewObjectSnippets.initializeArray((Word) memory, hub, arrayLength, sizeInBytes, prototypeMarkWord, headerSize, false);
+        Object result = NewObjectSnippets.allocateArray(hub, arrayLength, prototypeMarkWord, headerSize, log2ElementSize, false);
 
-        memory = Word.fromObject(result);
+        Pointer memory = Word.fromObject(result);
         for (int offset = headerSize; offset < sizeInBytes; offset += wordSize()) {
             memory.writeWord(offset, Word.fromObject(src).readWord(offset, ANY_LOCATION), ANY_LOCATION);
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ExceptionHandlerStub.java	Tue May 14 21:33:37 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ExceptionHandlerStub.java	Tue May 14 21:43:06 2013 +0200
@@ -73,7 +73,7 @@
         if (logging()) {
             printf("handling exception %p (", Word.fromObject(exception).rawValue());
             decipher(Word.fromObject(exception).rawValue());
-            printf(") at %p (", Word.fromObject(exception).rawValue(), exceptionPc.rawValue());
+            printf(") at %p (", exceptionPc.rawValue());
             decipher(exceptionPc.rawValue());
             printf(")\n");
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java	Tue May 14 21:33:37 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java	Tue May 14 21:43:06 2013 +0200
@@ -108,8 +108,7 @@
                 if (logging()) {
                     printf("newArray: allocated new array at %p\n", memory.rawValue());
                 }
-                formatArray(hub, sizeInBytes, length, headerSize, memory, Word.unsigned(arrayPrototypeMarkWord()), true);
-                return verifyObject(memory.toObject());
+                return verifyObject(formatArray(hub, sizeInBytes, length, headerSize, memory, Word.unsigned(arrayPrototypeMarkWord()), true));
             }
         }
         if (logging()) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/RuntimeCallStub.java	Tue May 14 21:33:37 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/RuntimeCallStub.java	Tue May 14 21:43:06 2013 +0200
@@ -33,13 +33,13 @@
 import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.debug.*;
-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.replacements.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.spi.*;
@@ -150,19 +150,19 @@
         final StructuredGraph graph;
         private FixedWithNextNode lastFixedNode;
 
-        <T extends Node> T add(T node) {
+        <T extends FloatingNode> T add(T node) {
+            return graph.unique(node);
+        }
+
+        <T extends FixedNode> T append(T node) {
             T result = graph.add(node);
-            assert node == result;
-            if (result instanceof FixedNode) {
-                assert lastFixedNode != null;
-                FixedNode fixed = (FixedNode) result;
-                assert fixed.predecessor() == null;
-                graph.addAfterFixed(lastFixedNode, fixed);
-                if (fixed instanceof FixedWithNextNode) {
-                    lastFixedNode = (FixedWithNextNode) fixed;
-                } else {
-                    lastFixedNode = null;
-                }
+            assert lastFixedNode != null;
+            assert result.predecessor() == null;
+            graph.addAfterFixed(lastFixedNode, result);
+            if (result instanceof FixedWithNextNode) {
+                lastFixedNode = (FixedWithNextNode) result;
+            } else {
+                lastFixedNode = null;
             }
             return result;
         }
@@ -172,19 +172,17 @@
     protected StructuredGraph getGraph() {
         Class<?>[] args = linkage.getDescriptor().getArgumentTypes();
         boolean isObjectResult = linkage.getCallingConvention().getReturn().getKind() == Kind.Object;
-
         GraphBuilder builder = new GraphBuilder(this);
-
         LocalNode[] locals = createLocals(builder, args);
 
-        ReadRegisterNode thread = prependThread || isObjectResult ? builder.add(new ReadRegisterNode(runtime.threadRegister(), true, false)) : null;
+        ReadRegisterNode thread = prependThread || isObjectResult ? builder.append(new ReadRegisterNode(runtime.threadRegister(), true, false)) : null;
         ValueNode result = createTargetCall(builder, locals, thread);
         createInvoke(builder, StubUtil.class, "handlePendingException", ConstantNode.forBoolean(isObjectResult, builder.graph));
         if (isObjectResult) {
             InvokeNode object = createInvoke(builder, HotSpotReplacementsUtil.class, "getAndClearObjectResult", thread);
             result = createInvoke(builder, StubUtil.class, "verifyObject", object);
         }
-        builder.add(new ReturnNode(linkage.getDescriptor().getResultType() == void.class ? null : result));
+        builder.append(new ReturnNode(linkage.getDescriptor().getResultType() == void.class ? null : result));
 
         if (Debug.isDumpEnabled()) {
             Debug.dump(builder.graph, "Initial stub graph");
@@ -230,8 +228,8 @@
         }
         assert method != null : "did not find method in " + declaringClass + " named " + name;
         JavaType returnType = method.getSignature().getReturnType(null);
-        MethodCallTargetNode callTarget = builder.add(new MethodCallTargetNode(InvokeKind.Static, method, hpeArgs, returnType));
-        InvokeNode invoke = builder.add(new InvokeNode(callTarget, FrameState.UNKNOWN_BCI));
+        MethodCallTargetNode callTarget = builder.graph.add(new MethodCallTargetNode(InvokeKind.Static, method, hpeArgs, returnType));
+        InvokeNode invoke = builder.append(new InvokeNode(callTarget, FrameState.UNKNOWN_BCI));
         return invoke;
     }
 
@@ -240,9 +238,9 @@
             ValueNode[] targetArguments = new ValueNode[1 + locals.length];
             targetArguments[0] = thread;
             System.arraycopy(locals, 0, targetArguments, 1, locals.length);
-            return builder.add(new CRuntimeCall(target.getDescriptor(), targetArguments));
+            return builder.append(new CRuntimeCall(target.getDescriptor(), targetArguments));
         } else {
-            return builder.add(new CRuntimeCall(target.getDescriptor(), locals));
+            return builder.append(new CRuntimeCall(target.getDescriptor(), locals));
         }
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/UnwindExceptionToCallerStub.java	Tue May 14 21:33:37 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/UnwindExceptionToCallerStub.java	Tue May 14 21:43:06 2013 +0200
@@ -66,7 +66,7 @@
         if (logging()) {
             printf("unwinding exception %p (", exceptionOop.rawValue());
             decipher(exceptionOop.rawValue());
-            printf(") at %p (", exceptionOop.rawValue(), returnAddress.rawValue());
+            printf(") at %p (", returnAddress.rawValue());
             decipher(returnAddress.rawValue());
             printf(")\n");
         }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/JTTTest.java	Tue May 14 21:33:37 2013 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/JTTTest.java	Tue May 14 21:43:06 2013 +0200
@@ -26,6 +26,7 @@
 import static java.lang.reflect.Modifier.*;
 
 import java.lang.reflect.*;
+import java.util.*;
 
 import org.junit.*;
 
@@ -93,15 +94,19 @@
     }
 
     protected void runTest(String name, Object... args) {
+        runTest(Collections.<DeoptimizationReason> emptySet(), name, args);
+    }
+
+    protected void runTest(Set<DeoptimizationReason> shoutNotDeopt, String name, Object... args) {
         Method method = getMethod(name);
         Object receiver = Modifier.isStatic(method.getModifiers()) ? null : this;
 
         Result expect = executeExpected(method, receiver, args);
 
-        test(method, expect, receiver, args);
+        test(method, expect, shoutNotDeopt, receiver, args);
         if (args.length > 0) {
             this.argsToBind = args;
-            test(method, expect, receiver, args);
+            test(method, expect, shoutNotDeopt, receiver, args);
             this.argsToBind = null;
         }
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_field01.java	Tue May 14 21:33:37 2013 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_field01.java	Tue May 14 21:43:06 2013 +0200
@@ -23,6 +23,8 @@
 // Checkstyle: stop
 package com.oracle.graal.jtt.hotpath;
 
+import java.lang.reflect.*;
+
 import com.oracle.graal.jtt.*;
 import org.junit.*;
 
@@ -48,7 +50,7 @@
     }
 
     @Override
-    public void before() {
+    public void before(Method m) {
         a = 0;
         b = 0;
         c = 0;
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_field03.java	Tue May 14 21:33:37 2013 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_field03.java	Tue May 14 21:43:06 2013 +0200
@@ -23,6 +23,8 @@
 // Checkstyle: stop
 package com.oracle.graal.jtt.hotpath;
 
+import java.lang.reflect.*;
+
 import com.oracle.graal.jtt.*;
 import org.junit.*;
 
@@ -52,7 +54,7 @@
     }
 
     @Override
-    public void before() {
+    public void before(Method m) {
         b = 0;
         c = 0;
         s = 0;
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/Unsafe_compareAndSwap.java	Tue May 14 21:33:37 2013 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/Unsafe_compareAndSwap.java	Tue May 14 21:43:06 2013 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.jtt.jdk;
 
+import java.lang.reflect.*;
+
 import org.junit.*;
 
 import com.oracle.graal.jtt.*;
@@ -54,7 +56,7 @@
     private static final Unsafe_compareAndSwap instance = new Unsafe_compareAndSwap();
 
     @Override
-    protected void before() {
+    protected void before(Method m) {
         instance.value = "a";
     }
 
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/loop/LoopNewInstance.java	Tue May 14 21:33:37 2013 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/loop/LoopNewInstance.java	Tue May 14 21:43:06 2013 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.jtt.loop;
 
+import java.lang.reflect.*;
+
 import com.oracle.graal.jtt.*;
 import org.junit.*;
 
@@ -54,7 +56,7 @@
     }
 
     @Override
-    protected void before() {
+    protected void before(Method m) {
         count = 0;
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/SelfReplacingMethodCallTargetNode.java	Tue May 14 21:43:06 2013 +0200
@@ -0,0 +1,84 @@
+/*
+ * 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.java;
+
+import java.lang.reflect.Modifier;
+
+import com.oracle.graal.api.meta.JavaType;
+import com.oracle.graal.api.meta.ResolvedJavaMethod;
+import com.oracle.graal.graph.GraalInternalError;
+import com.oracle.graal.graph.NodeInputList;
+import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.nodes.spi.LIRGeneratorTool;
+import com.oracle.graal.nodes.spi.Lowerable;
+import com.oracle.graal.nodes.spi.LoweringTool;
+
+/**
+ * A SelfReplacingMethodCallTargetNode replaces itself in the graph when being lowered with a
+ * {@link MethodCallTargetNode} that calls the stored replacement target method.
+ * 
+ * This node is used for method handle call nodes which have a constant call target but are not
+ * inlined.
+ */
+public class SelfReplacingMethodCallTargetNode extends MethodCallTargetNode implements Lowerable {
+
+    // Replacement method data
+    private final ResolvedJavaMethod replacementTargetMethod;
+    private final JavaType replacementReturnType;
+    @Input private final NodeInputList<ValueNode> replacementArguments;
+
+    public SelfReplacingMethodCallTargetNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] arguments, JavaType returnType, ResolvedJavaMethod replacementTargetMethod,
+                    ValueNode[] replacementArguments, JavaType replacementReturnType) {
+        super(invokeKind, targetMethod, arguments, returnType);
+        this.replacementTargetMethod = replacementTargetMethod;
+        this.replacementReturnType = replacementReturnType;
+        this.replacementArguments = new NodeInputList<>(this, replacementArguments);
+    }
+
+    public ResolvedJavaMethod replacementTargetMethod() {
+        return replacementTargetMethod;
+    }
+
+    public JavaType replacementReturnType() {
+        return replacementReturnType;
+    }
+
+    public NodeInputList<ValueNode> replacementArguments() {
+        return replacementArguments;
+    }
+
+    @Override
+    public void lower(LoweringTool tool, LoweringType loweringType) {
+        InvokeKind invokeKind = Modifier.isStatic(replacementTargetMethod.getModifiers()) ? InvokeKind.Static : InvokeKind.Special;
+        MethodCallTargetNode replacement = graph().add(
+                        new MethodCallTargetNode(invokeKind, replacementTargetMethod, replacementArguments.toArray(new ValueNode[replacementArguments.size()]), replacementReturnType));
+
+        // Replace myself...
+        this.replaceAndDelete(replacement);
+    }
+
+    @Override
+    public void generate(LIRGeneratorTool gen) {
+        throw GraalInternalError.shouldNotReachHere("should have replaced itself");
+    }
+}
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Tue May 14 21:33:37 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Tue May 14 21:43:06 2013 +0200
@@ -33,6 +33,7 @@
 import com.oracle.graal.api.meta.ResolvedJavaType.Representation;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.Node.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
@@ -1267,6 +1268,8 @@
                     monitor.setLockDepth(monitor.getLockDepth() + callerLockDepth);
                 }
             }
+        } else {
+            assert checkContainsOnlyInvalidOrAfterFrameState(duplicates);
         }
         Node returnValue = null;
         if (returnNode != null) {
@@ -1289,6 +1292,16 @@
         return duplicates;
     }
 
+    private static boolean checkContainsOnlyInvalidOrAfterFrameState(Map<Node, Node> duplicates) {
+        for (Node node : duplicates.values()) {
+            if (node instanceof FrameState) {
+                FrameState frameState = (FrameState) node;
+                assert frameState.bci == FrameState.AFTER_BCI || frameState.bci == FrameState.INVALID_FRAMESTATE_BCI : node.toString(Verbosity.Debugger);
+            }
+        }
+        return true;
+    }
+
     public static void receiverNullCheck(Invoke invoke) {
         MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
         StructuredGraph graph = callTarget.graph();
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Tue May 14 21:33:37 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Tue May 14 21:43:06 2013 +0200
@@ -204,7 +204,7 @@
             ((Virtualizable) node).virtualize(tool);
         }
         if (tool.isDeleted()) {
-            if (!(node instanceof VirtualizableAllocation)) {
+            if (!(node instanceof CommitAllocationNode || node instanceof AllocatedObjectNode)) {
                 changed = true;
             }
             return true;