changeset 9516:cf8104ed68ba

Merge.
author Doug Simon <doug.simon@oracle.com>
date Thu, 02 May 2013 14:12:24 +0200
parents 9384ec90632b (current diff) 106f0a0acafa (diff)
children 51973e9ec004
files graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/nodes/MaterializeObjectNode.java
diffstat 41 files changed, 702 insertions(+), 516 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java	Thu May 02 12:19:41 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java	Thu May 02 14:12:24 2013 +0200
@@ -31,7 +31,6 @@
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
-import com.oracle.graal.virtual.nodes.*;
 import com.oracle.graal.virtual.phases.ea.*;
 
 /**
@@ -334,10 +333,6 @@
                 new CanonicalizerPhase().apply(graph, context);
                 new PartialEscapeAnalysisPhase(false, false).apply(graph, context);
 
-                for (MaterializeObjectNode materialize : graph.getNodes(MaterializeObjectNode.class)) {
-                    materialize.getVirtualObject().materializeAt(materialize, materialize.getValues(), false, materialize.getLockCount());
-                }
-
                 new CullFrameStatesPhase().apply(graph);
                 new DeadCodeEliminationPhase().apply(graph);
                 new CanonicalizerPhase().apply(graph, context);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java	Thu May 02 12:19:41 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java	Thu May 02 14:12:24 2013 +0200
@@ -35,16 +35,15 @@
 import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
-import com.oracle.graal.virtual.nodes.*;
 import com.oracle.graal.virtual.phases.ea.*;
 
 /**
- * In these test cases the probability of all invokes is set to a high value, such that an
- * InliningPhase should inline them all. After that, the EscapeAnalysisPhase is expected to remove
- * all allocations and return the correct values.
+ * The PartialEscapeAnalysisPhase is expected to remove all allocations and return the correct
+ * values.
  */
 public class EscapeAnalysisTest extends GraalCompilerTest {
 
@@ -230,7 +229,7 @@
                     Assert.assertTrue(returnNode.result().toString(), returnNode.result().isConstant());
                     Assert.assertEquals(expectedConstantResult, returnNode.result().asConstant());
                 }
-                int newInstanceCount = graph.getNodes(NewInstanceNode.class).count() + graph.getNodes(NewArrayNode.class).count() + graph.getNodes(MaterializeObjectNode.class).count();
+                int newInstanceCount = graph.getNodes(NewInstanceNode.class).count() + graph.getNodes(NewArrayNode.class).count() + graph.getNodes(CommitAllocationNode.class).count();
                 Assert.assertEquals(0, newInstanceCount);
                 return returnNode;
             }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java	Thu May 02 12:19:41 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java	Thu May 02 14:12:24 2013 +0200
@@ -35,17 +35,16 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.util.*;
+import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.graph.*;
 import com.oracle.graal.phases.tiers.*;
-import com.oracle.graal.virtual.nodes.*;
 import com.oracle.graal.virtual.phases.ea.*;
 
 /**
- * In these test cases the probability of all invokes is set to a high value, such that an
- * InliningPhase should inline them all. After that, the PartialEscapeAnalysisPhase is expected to
- * remove all allocations and return the correct values.
+ * The PartialEscapeAnalysisPhase is expected to remove all allocations and return the correct
+ * values.
  */
 public class PartialEscapeAnalysisTest extends GraalCompilerTest {
 
@@ -137,9 +136,9 @@
             NodesToDoubles nodeProbabilities = new ComputeProbabilityClosure(result).apply();
             double probabilitySum = 0;
             int materializeCount = 0;
-            for (MaterializeObjectNode materialize : result.getNodes(MaterializeObjectNode.class)) {
-                probabilitySum += nodeProbabilities.get(materialize);
-                materializeCount++;
+            for (CommitAllocationNode materialize : result.getNodes(CommitAllocationNode.class)) {
+                probabilitySum += nodeProbabilities.get(materialize) * materialize.getVirtualObjects().size();
+                materializeCount += materialize.getVirtualObjects().size();
             }
             Assert.assertEquals("unexpected number of MaterializeObjectNodes", expectedCount, materializeCount);
             Assert.assertEquals("unexpected probability of MaterializeObjectNodes", expectedProbability, probabilitySum, 0.01);
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Thu May 02 12:19:41 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Thu May 02 14:12:24 2013 +0200
@@ -165,7 +165,6 @@
                 throw new GraalInternalError("no mapping found for virtual object %s", obj);
             }
             if (state instanceof MaterializedObjectState) {
-                assert !(((MaterializedObjectState) state).materializedValue() instanceof VirtualObjectNode);
                 return toValue(((MaterializedObjectState) state).materializedValue());
             } else {
                 assert obj.entryCount() == 0 || state instanceof VirtualObjectState;
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Thu May 02 12:19:41 2013 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Thu May 02 14:12:24 2013 +0200
@@ -458,7 +458,7 @@
      * Provides a {@link Map} of properties of this node for use in debugging (e.g., to view in the
      * ideal graph visualizer).
      */
-    public Map<Object, Object> getDebugProperties() {
+    public final Map<Object, Object> getDebugProperties() {
         return getDebugProperties(new HashMap<>());
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Thu May 02 12:19:41 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Thu May 02 14:12:24 2013 +0200
@@ -78,6 +78,7 @@
 import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.printer.*;
 import com.oracle.graal.replacements.*;
@@ -665,7 +666,7 @@
             HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) loadField.field();
             ValueNode object = loadField.isStatic() ? ConstantNode.forObject(field.getDeclaringClass().mirror(), this, graph) : loadField.object();
             assert loadField.kind() != Kind.Illegal;
-            ReadNode memoryRead = graph.add(new ReadNode(object, ConstantLocationNode.create(field, field.getKind(), field.offset(), graph), loadField.stamp()));
+            ReadNode memoryRead = graph.add(new ReadNode(object, createFieldLocation(graph, field), loadField.stamp()));
             tool.createNullCheckGuard(memoryRead.dependencies(), object);
 
             graph.replaceFixedWithFixed(loadField, memoryRead);
@@ -680,9 +681,8 @@
             StoreFieldNode storeField = (StoreFieldNode) n;
             HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) storeField.field();
             ValueNode object = storeField.isStatic() ? ConstantNode.forObject(field.getDeclaringClass().mirror(), this, graph) : storeField.object();
-            LocationNode location = ConstantLocationNode.create(field, field.getKind(), field.offset(), graph);
             WriteBarrierType barrierType = getFieldStoreBarrierType(storeField);
-            WriteNode memoryWrite = graph.add(new WriteNode(object, storeField.value(), location, barrierType));
+            WriteNode memoryWrite = graph.add(new WriteNode(object, storeField.value(), createFieldLocation(graph, field), barrierType));
             tool.createNullCheckGuard(memoryWrite.dependencies(), object);
             memoryWrite.setStateAfter(storeField.stateAfter());
             graph.replaceFixedWithFixed(storeField, memoryWrite);
@@ -774,6 +774,70 @@
             FixedGuardNode node = (FixedGuardNode) n;
             ValueAnchorNode newAnchor = graph.add(new ValueAnchorNode(tool.createGuard(node.condition(), node.getReason(), node.getAction(), node.isNegated())));
             graph.replaceFixedWithFixed(node, newAnchor);
+        } else if (n instanceof CommitAllocationNode) {
+            CommitAllocationNode commit = (CommitAllocationNode) n;
+
+            ValueNode[] allocations = new ValueNode[commit.getVirtualObjects().size()];
+            for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
+                VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex);
+                int entryCount = virtual.entryCount();
+
+                FixedWithNextNode newObject;
+                if (virtual instanceof VirtualInstanceNode) {
+                    newObject = graph.add(new NewInstanceNode(virtual.type(), true));
+                } else {
+                    ResolvedJavaType element = ((VirtualArrayNode) virtual).componentType();
+                    newObject = graph.add(new NewArrayNode(element, ConstantNode.forInt(entryCount, graph), true));
+                }
+                graph.addBeforeFixed(commit, newObject);
+                allocations[objIndex] = newObject;
+            }
+            int valuePos = 0;
+            for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
+                VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex);
+                int entryCount = virtual.entryCount();
+
+                ValueNode newObject = allocations[objIndex];
+                if (virtual instanceof VirtualInstanceNode) {
+                    VirtualInstanceNode instance = (VirtualInstanceNode) virtual;
+                    for (int i = 0; i < entryCount; i++) {
+                        ValueNode value = commit.getValues().get(valuePos++);
+                        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)));
+                    }
+                } else {
+                    VirtualArrayNode array = (VirtualArrayNode) virtual;
+                    ResolvedJavaType element = array.componentType();
+                    for (int i = 0; i < entryCount; i++) {
+                        ValueNode value = commit.getValues().get(valuePos++);
+                        if (value instanceof VirtualObjectNode) {
+                            int indexOf = commit.getVirtualObjects().indexOf(value);
+                            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)));
+                    }
+                }
+            }
+            for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
+                FixedValueAnchorNode anchor = graph.add(new FixedValueAnchorNode(allocations[objIndex]));
+                allocations[objIndex] = anchor;
+                graph.addBeforeFixed(commit, anchor);
+            }
+            for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
+                for (int lockDepth : commit.getLocks().get(objIndex)) {
+                    MonitorEnterNode enter = graph.add(new MonitorEnterNode(allocations[objIndex], lockDepth));
+                    graph.addBeforeFixed(commit, enter);
+                }
+            }
+            for (Node usage : commit.usages().snapshot()) {
+                AllocatedObjectNode addObject = (AllocatedObjectNode) usage;
+                int index = commit.getVirtualObjects().indexOf(addObject.getVirtualObject());
+                graph.replaceFloating(addObject, allocations[index]);
+            }
+            graph.removeFixed(commit);
         } else if (n instanceof CheckCastNode) {
             checkcastSnippets.lower((CheckCastNode) n, tool);
         } else if (n instanceof CheckCastDynamicNode) {
@@ -881,6 +945,10 @@
         return barrierType;
     }
 
+    private static ConstantLocationNode createFieldLocation(StructuredGraph graph, HotSpotResolvedJavaField field) {
+        return ConstantLocationNode.create(field, field.getKind(), field.offset(), graph);
+    }
+
     private IndexedLocationNode createArrayLocation(Graph graph, Kind elementKind, ValueNode index) {
         int scale = this.graalRuntime.getTarget().arch.getSizeInBytes(elementKind);
         return IndexedLocationNode.create(LocationNode.getArrayLocation(elementKind), elementKind, getArrayBaseOffset(elementKind), index, graph, scale);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java	Thu May 02 12:19:41 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java	Thu May 02 14:12:24 2013 +0200
@@ -38,22 +38,12 @@
  * is locked (ensuring the GC sees and updates the object) so it must come after any null pointer
  * check on the object.
  */
-public final class BeginLockScopeNode extends AbstractStateSplit implements LIRGenLowerable, MonitorEnter, MonitorReference {
-
-    private final boolean eliminated;
+public final class BeginLockScopeNode extends AbstractStateSplit implements LIRGenLowerable, MonitorEnter {
 
-    private int lockDepth = -1;
+    private int lockDepth;
 
-    public BeginLockScopeNode(boolean eliminated) {
+    public BeginLockScopeNode(int lockDepth) {
         super(StampFactory.forWord());
-        this.eliminated = eliminated;
-    }
-
-    public int getLockDepth() {
-        return lockDepth;
-    }
-
-    public void setLockDepth(int lockDepth) {
         this.lockDepth = lockDepth;
     }
 
@@ -72,12 +62,10 @@
         assert lockDepth != -1;
         HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen;
         StackSlot slot = hsGen.getLockSlot(lockDepth);
-        if (!eliminated) {
-            Value result = gen.emitAddress(slot);
-            gen.setResult(this, result);
-        }
+        Value result = gen.emitAddress(slot);
+        gen.setResult(this, result);
     }
 
     @NodeIntrinsic
-    public static native Word beginLockScope(@ConstantNodeParameter boolean eliminated);
+    public static native Word beginLockScope(@ConstantNodeParameter int lockDepth);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentLockNode.java	Thu May 02 12:19:41 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentLockNode.java	Thu May 02 14:12:24 2013 +0200
@@ -28,26 +28,18 @@
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.word.*;
 
 /**
  * Intrinsic for getting the lock in the current {@linkplain BeginLockScopeNode lock scope}.
  */
-public final class CurrentLockNode extends FixedWithNextNode implements LIRGenLowerable, MonitorReference {
+public final class CurrentLockNode extends FixedWithNextNode implements LIRGenLowerable {
 
-    private int lockDepth = -1;
+    private int lockDepth;
 
-    public CurrentLockNode() {
+    public CurrentLockNode(int lockDepth) {
         super(StampFactory.forWord());
-    }
-
-    public int getLockDepth() {
-        return lockDepth;
-    }
-
-    public void setLockDepth(int lockDepth) {
         this.lockDepth = lockDepth;
     }
 
@@ -62,5 +54,5 @@
     }
 
     @NodeIntrinsic
-    public static native Word currentLock();
+    public static native Word currentLock(@ConstantNodeParameter int lockDepth);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/InitializeArrayNode.java	Thu May 02 12:19:41 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/InitializeArrayNode.java	Thu May 02 14:12:24 2013 +0200
@@ -39,16 +39,14 @@
     @Input private final ValueNode allocationSize;
     private final ResolvedJavaType type;
     private final boolean fillContents;
-    private final boolean locked;
 
-    public InitializeArrayNode(ValueNode memory, ValueNode length, ValueNode allocationSize, ResolvedJavaType type, boolean fillContents, boolean locked) {
+    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;
-        this.locked = locked;
     }
 
     public ValueNode memory() {
@@ -77,16 +75,11 @@
         return fillContents;
     }
 
-    public boolean locked() {
-        return locked;
-    }
-
     @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,
-                    @ConstantNodeParameter boolean locked);
+    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	Thu May 02 12:19:41 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/InitializeObjectNode.java	Thu May 02 14:12:24 2013 +0200
@@ -37,14 +37,12 @@
     @Input private final ValueNode memory;
     private final ResolvedJavaType type;
     private final boolean fillContents;
-    private final boolean locked;
 
-    public InitializeObjectNode(ValueNode memory, ResolvedJavaType type, boolean fillContents, boolean locked) {
+    public InitializeObjectNode(ValueNode memory, ResolvedJavaType type, boolean fillContents) {
         super(StampFactory.exactNonNull(type));
         this.memory = memory;
         this.type = type;
         this.fillContents = fillContents;
-        this.locked = locked;
     }
 
     public ValueNode memory() {
@@ -59,10 +57,6 @@
         return fillContents;
     }
 
-    public boolean locked() {
-        return locked;
-    }
-
     @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/MonitorExitStubCall.java	Thu May 02 12:19:41 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorExitStubCall.java	Thu May 02 14:12:24 2013 +0200
@@ -28,29 +28,21 @@
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.word.*;
 
 /**
  * Node implementing a call to HotSpot's {@code graal_monitorexit} stub.
  */
-public class MonitorExitStubCall extends DeoptimizingStubCall implements LIRGenLowerable, MonitorReference {
+public class MonitorExitStubCall extends DeoptimizingStubCall implements LIRGenLowerable {
 
     @Input private final ValueNode object;
     private int lockDepth;
     public static final Descriptor MONITOREXIT = new Descriptor("monitorexit", true, void.class, Object.class, Word.class);
 
-    public MonitorExitStubCall(ValueNode object) {
+    public MonitorExitStubCall(ValueNode object, int lockDepth) {
         super(StampFactory.forVoid());
         this.object = object;
-    }
-
-    public int getLockDepth() {
-        return lockDepth;
-    }
-
-    public void setLockDepth(int lockDepth) {
         this.lockDepth = lockDepth;
     }
 
@@ -64,5 +56,5 @@
     }
 
     @NodeIntrinsic
-    public static native void call(Object hub);
+    public static native void call(Object hub, @ConstantNodeParameter int lockDepth);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java	Thu May 02 12:19:41 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java	Thu May 02 14:12:24 2013 +0200
@@ -76,7 +76,7 @@
     public static final boolean CHECK_BALANCED_MONITORS = Boolean.getBoolean("graal.monitors.checkBalanced");
 
     @Snippet
-    public static void monitorenter(Object object, @ConstantParameter boolean checkNull, @ConstantParameter boolean trace) {
+    public static void monitorenter(Object object, @ConstantParameter int lockDepth, @ConstantParameter boolean checkNull, @ConstantParameter boolean trace) {
         verifyOop(object);
 
         if (checkNull && object == null) {
@@ -86,7 +86,7 @@
         // Load the mark word - this includes a null-check on object
         final Word mark = loadWordFromObject(object, markOffset());
 
-        final Word lock = beginLockScope(false);
+        final Word lock = beginLockScope(lockDepth);
 
         trace(trace, "           object: 0x%016lx\n", Word.fromObject(object));
         trace(trace, "             lock: 0x%016lx\n", lock);
@@ -248,17 +248,11 @@
         }
     }
 
-    @Snippet
-    public static void monitorenterEliminated() {
-        incCounter();
-        beginLockScope(true);
-    }
-
     /**
      * Calls straight out to the monitorenter stub.
      */
     @Snippet
-    public static void monitorenterStub(Object object, @ConstantParameter boolean checkNull, @ConstantParameter boolean trace) {
+    public static void monitorenterStub(Object object, @ConstantParameter int lockDepth, @ConstantParameter boolean checkNull, @ConstantParameter boolean trace) {
         verifyOop(object);
         incCounter();
         if (checkNull && object == null) {
@@ -266,13 +260,13 @@
         }
         // BeginLockScope nodes do not read from object so a use of object
         // cannot float about the null check above
-        final Word lock = beginLockScope(false);
+        final Word lock = beginLockScope(lockDepth);
         traceObject(trace, "+lock{stub}", object);
         MonitorEnterStubCall.call(object, lock);
     }
 
     @Snippet
-    public static void monitorexit(Object object, @ConstantParameter boolean trace) {
+    public static void monitorexit(Object object, @ConstantParameter int lockDepth, @ConstantParameter boolean trace) {
         trace(trace, "           object: 0x%016lx\n", Word.fromObject(object));
         if (useBiasedLocking()) {
             // Check for biased locking unlock case, which is a no-op
@@ -291,7 +285,7 @@
             }
         }
 
-        final Word lock = CurrentLockNode.currentLock();
+        final Word lock = CurrentLockNode.currentLock(lockDepth);
 
         // Load displaced mark
         final Word displacedMark = lock.readWord(lockDisplacedMarkOffset(), DISPLACED_MARK_WORD_LOCATION);
@@ -309,7 +303,7 @@
                 // The object's mark word was not pointing to the displaced header,
                 // we do unlocking via runtime call.
                 traceObject(trace, "-lock{stub}", object);
-                MonitorExitStubCall.call(object);
+                MonitorExitStubCall.call(object, lockDepth);
             } else {
                 traceObject(trace, "-lock{cas}", object);
             }
@@ -322,16 +316,10 @@
      * Calls straight out to the monitorexit stub.
      */
     @Snippet
-    public static void monitorexitStub(Object object, @ConstantParameter boolean trace) {
+    public static void monitorexitStub(Object object, @ConstantParameter int lockDepth, @ConstantParameter boolean trace) {
         verifyOop(object);
         traceObject(trace, "-lock{stub}", object);
-        MonitorExitStubCall.call(object);
-        endLockScope();
-        decCounter();
-    }
-
-    @Snippet
-    public static void monitorexitEliminated() {
+        MonitorExitStubCall.call(object, lockDepth);
         endLockScope();
         decCounter();
     }
@@ -398,8 +386,6 @@
         private final SnippetInfo monitorexit = snippet(MonitorSnippets.class, "monitorexit");
         private final SnippetInfo monitorenterStub = snippet(MonitorSnippets.class, "monitorenterStub");
         private final SnippetInfo monitorexitStub = snippet(MonitorSnippets.class, "monitorexitStub");
-        private final SnippetInfo monitorenterEliminated = snippet(MonitorSnippets.class, "monitorenterEliminated");
-        private final SnippetInfo monitorexitEliminated = snippet(MonitorSnippets.class, "monitorexitEliminated");
         private final SnippetInfo initCounter = snippet(MonitorSnippets.class, "initCounter");
         private final SnippetInfo checkCounter = snippet(MonitorSnippets.class, "checkCounter");
 
@@ -416,18 +402,16 @@
             FrameState stateAfter = monitorenterNode.stateAfter();
 
             Arguments args;
-            if (monitorenterNode.eliminated()) {
-                args = new Arguments(monitorenterEliminated);
+            if (useFastLocking) {
+                args = new Arguments(monitorenter);
             } else {
-                if (useFastLocking) {
-                    args = new Arguments(monitorenter);
-                } else {
-                    args = new Arguments(monitorenterStub);
-                }
-                args.add("object", monitorenterNode.object());
-                args.addConst("checkNull", !monitorenterNode.object().stamp().nonNull());
-                args.addConst("trace", isTracingEnabledForType(monitorenterNode.object()) || isTracingEnabledForMethod(stateAfter.method()) || isTracingEnabledForMethod(graph.method()));
+                args = new Arguments(monitorenterStub);
             }
+            args.add("object", monitorenterNode.object());
+            args.addConst("lockDepth", monitorenterNode.getLockDepth());
+            args.addConst("checkNull", !monitorenterNode.object().stamp().nonNull());
+            boolean tracingEnabledForMethod = stateAfter != null && (isTracingEnabledForMethod(stateAfter.method()) || isTracingEnabledForMethod(graph.method()));
+            args.addConst("trace", isTracingEnabledForType(monitorenterNode.object()) || tracingEnabledForMethod);
 
             Map<Node, Node> nodes = template(args).instantiate(runtime, monitorenterNode, DEFAULT_REPLACER, args);
 
@@ -436,9 +420,6 @@
                     BeginLockScopeNode begin = (BeginLockScopeNode) n;
                     begin.setStateAfter(stateAfter);
                 }
-                if (n instanceof MonitorReference) {
-                    ((MonitorReference) n).setLockDepth(monitorenterNode.getLockDepth());
-                }
             }
         }
 
@@ -447,17 +428,14 @@
             FrameState stateAfter = monitorexitNode.stateAfter();
 
             Arguments args;
-            if (monitorexitNode.eliminated()) {
-                args = new Arguments(monitorexitEliminated);
+            if (useFastLocking) {
+                args = new Arguments(monitorexit);
             } else {
-                if (useFastLocking) {
-                    args = new Arguments(monitorexit);
-                } else {
-                    args = new Arguments(monitorexitStub);
-                }
-                args.add("object", monitorexitNode.object());
-                args.addConst("trace", isTracingEnabledForType(monitorexitNode.object()) || isTracingEnabledForMethod(stateAfter.method()) || isTracingEnabledForMethod(graph.method()));
+                args = new Arguments(monitorexitStub);
             }
+            args.add("object", monitorexitNode.object());
+            args.addConst("lockDepth", monitorexitNode.getLockDepth());
+            args.addConst("trace", isTracingEnabledForType(monitorexitNode.object()) || isTracingEnabledForMethod(stateAfter.method()) || isTracingEnabledForMethod(graph.method()));
 
             Map<Node, Node> nodes = template(args).instantiate(runtime, monitorexitNode, DEFAULT_REPLACER, args);
 
@@ -466,9 +444,6 @@
                     EndLockScopeNode end = (EndLockScopeNode) n;
                     end.setStateAfter(stateAfter);
                 }
-                if (n instanceof MonitorReference) {
-                    ((MonitorReference) n).setLockDepth(monitorexitNode.getLockDepth());
-                }
             }
         }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Thu May 02 12:19:41 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Thu May 02 14:12:24 2013 +0200
@@ -72,18 +72,14 @@
     }
 
     @Snippet
-    public static Object initializeObject(Word memory, Word hub, Word prototypeMarkWord, @ConstantParameter int size, @ConstantParameter boolean fillContents, @ConstantParameter boolean locked) {
+    public static Object initializeObject(Word memory, Word hub, Word prototypeMarkWord, @ConstantParameter int size, @ConstantParameter boolean fillContents) {
 
         Object result;
         if (probability(SLOW_PATH_PROBABILITY, memory.equal(0))) {
             new_stub.inc();
             result = NewInstanceStubCall.call(hub);
         } else {
-            if (locked) {
-                formatObject(hub, size, memory, thread().or(biasedLockPattern()), fillContents);
-            } else {
-                formatObject(hub, size, memory, prototypeMarkWord, fillContents);
-            }
+            formatObject(hub, size, memory, prototypeMarkWord, fillContents);
             result = memory.toObject();
         }
         /*
@@ -95,16 +91,7 @@
     }
 
     @Snippet
-    public static Object initializeArray(Word memory, Word hub, int length, int allocationSize, Word prototypeMarkWord, @ConstantParameter int headerSize, @ConstantParameter boolean fillContents,
-                    @ConstantParameter boolean locked) {
-        if (locked) {
-            return initializeArray(memory, hub, length, allocationSize, thread().or(biasedLockPattern()), headerSize, fillContents);
-        } else {
-            return initializeArray(memory, hub, length, allocationSize, prototypeMarkWord, headerSize, fillContents);
-        }
-    }
-
-    private static Object initializeArray(Word memory, Word hub, int length, int allocationSize, Word prototypeMarkWord, int headerSize, boolean fillContents) {
+    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();
@@ -132,7 +119,7 @@
         }
         int allocationSize = computeArrayAllocationSize(length, alignment, headerSize, log2ElementSize);
         Word memory = TLABAllocateNode.allocateVariableSize(allocationSize);
-        return InitializeArrayNode.initialize(memory, length, allocationSize, type, fillContents, false);
+        return InitializeArrayNode.initialize(memory, length, allocationSize, type, fillContents);
     }
 
     /**
@@ -243,7 +230,7 @@
                 graph.addBeforeFixed(newInstanceNode, tlabAllocateNode);
                 memory = tlabAllocateNode;
             }
-            InitializeObjectNode initializeNode = graph.add(new InitializeObjectNode(memory, type, newInstanceNode.fillContents(), newInstanceNode.locked()));
+            InitializeObjectNode initializeNode = graph.add(new InitializeObjectNode(memory, type, newInstanceNode.fillContents()));
             graph.replaceFixedWithFixed(newInstanceNode, initializeNode);
         }
 
@@ -269,7 +256,7 @@
                  * 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(), newArrayNode.locked()));
+                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
@@ -277,7 +264,7 @@
                 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(), newArrayNode.locked()));
+                InitializeArrayNode initializeNode = graph.add(new InitializeArrayNode(tlabAllocateNode, lengthNode, sizeNode, arrayType, newArrayNode.fillContents()));
                 graph.replaceFixedWithFixed(newArrayNode, initializeNode);
             } else {
                 Arguments args = new Arguments(allocateArrayAndInitialize);
@@ -319,7 +306,6 @@
             args.add("hub", hub);
             args.add("prototypeMarkWord", type.prototypeMarkWord());
             args.addConst("size", size).addConst("fillContents", initializeNode.fillContents());
-            args.addConst("locked", initializeNode.locked());
 
             SnippetTemplate template = template(args);
             Debug.log("Lowering initializeObject in %s: node=%s, template=%s, arguments=%s", graph, initializeNode, template, args);
@@ -345,7 +331,6 @@
             args.add("prototypeMarkWord", type.prototypeMarkWord());
             args.addConst("headerSize", headerSize);
             args.addConst("fillContents", initializeNode.fillContents());
-            args.addConst("locked", initializeNode.locked());
 
             SnippetTemplate template = template(args);
             Debug.log("Lowering initializeArray in %s: node=%s, template=%s, arguments=%s", graph, initializeNode, template, args);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java	Thu May 02 12:19:41 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java	Thu May 02 14:12:24 2013 +0200
@@ -103,7 +103,7 @@
                     newEntryState[i] = originalState.getEntry(i);
                 }
                 VirtualObjectNode newVirtual = originalVirtual.duplicate();
-                tool.createVirtualObject(newVirtual, newEntryState, 0);
+                tool.createVirtualObject(newVirtual, newEntryState, null);
                 tool.replaceWithVirtual(newVirtual);
             }
         } else {
@@ -134,7 +134,7 @@
                             }
                         }
                     });
-                    tool.createVirtualObject(newVirtual, state, 0);
+                    tool.createVirtualObject(newVirtual, state, null);
                     tool.replaceWithVirtual(newVirtual);
                 }
             }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java	Thu May 02 12:19:41 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java	Thu May 02 14:12:24 2013 +0200
@@ -54,7 +54,7 @@
         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, false);
+        Object result = NewObjectSnippets.initializeObject((Word) memory, hub, prototypeMarkWord, instanceSize, false);
 
         memory = Word.fromObject(result);
         for (int offset = 2 * wordSize(); offset < instanceSize; offset += wordSize()) {
@@ -72,7 +72,7 @@
 
         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, false);
+        Object result = NewObjectSnippets.initializeArray((Word) memory, hub, arrayLength, sizeInBytes, prototypeMarkWord, headerSize, false);
 
         memory = Word.fromObject(result);
         for (int offset = headerSize; offset < sizeInBytes; offset += wordSize()) {
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Thu May 02 12:19:41 2013 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Thu May 02 14:12:24 2013 +0200
@@ -828,7 +828,7 @@
     void genNewInstance(int cpi) {
         JavaType type = lookupType(cpi, NEW);
         if (type instanceof ResolvedJavaType && ((ResolvedJavaType) type).isInitialized()) {
-            NewInstanceNode n = currentGraph.add(new NewInstanceNode((ResolvedJavaType) type, true, false));
+            NewInstanceNode n = currentGraph.add(new NewInstanceNode((ResolvedJavaType) type, true));
             frameState.apush(append(n));
         } else {
             handleUnresolvedNewInstance(type);
@@ -870,7 +870,7 @@
     private void genNewPrimitiveArray(int typeCode) {
         Class<?> clazz = arrayTypeCodeToClass(typeCode);
         ResolvedJavaType elementType = runtime.lookupJavaType(clazz);
-        NewArrayNode nta = currentGraph.add(new NewArrayNode(elementType, frameState.ipop(), true, false));
+        NewArrayNode nta = currentGraph.add(new NewArrayNode(elementType, frameState.ipop(), true));
         frameState.apush(append(nta));
     }
 
@@ -878,7 +878,7 @@
         JavaType type = lookupType(cpi, ANEWARRAY);
         ValueNode length = frameState.ipop();
         if (type instanceof ResolvedJavaType) {
-            NewArrayNode n = currentGraph.add(new NewArrayNode((ResolvedJavaType) type, length, true, false));
+            NewArrayNode n = currentGraph.add(new NewArrayNode((ResolvedJavaType) type, length, true));
             frameState.apush(append(n));
         } else {
             handleUnresolvedNewObjectArray(type, length);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java	Thu May 02 12:19:41 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java	Thu May 02 14:12:24 2013 +0200
@@ -27,6 +27,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.util.*;
 
 @NodeInfo(nameTemplate = "FixedGuard(!={p#negated}) {p#reason/s}")
 public final class FixedGuardNode extends FixedWithNextNode implements Simplifiable, Lowerable, Node.IterableNodeType, Negatable {
@@ -97,7 +98,21 @@
 
     @Override
     public void lower(LoweringTool tool, LoweringType loweringType) {
-        tool.getRuntime().lower(this, tool);
+        if (loweringType == LoweringType.BEFORE_GUARDS) {
+            tool.getRuntime().lower(this, tool);
+        } else {
+            FixedNode next = next();
+            setNext(null);
+            DeoptimizeNode deopt = graph().add(new DeoptimizeNode(action, reason));
+            IfNode ifNode;
+            if (negated) {
+                ifNode = graph().add(new IfNode(condition, deopt, next, 0));
+            } else {
+                ifNode = graph().add(new IfNode(condition, next, deopt, 1));
+            }
+            ((FixedWithNextNode) predecessor()).setNext(ifNode);
+            GraphUtil.killWithUnusedFloatingInputs(this);
+        }
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java	Thu May 02 12:19:41 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java	Thu May 02 14:12:24 2013 +0200
@@ -52,7 +52,8 @@
         if (computePostdominators) {
             cfg.computePostdominators();
         }
-        assert CFGVerifier.verify(cfg);
+        // there's not much to verify when connectBlocks == false
+        assert !connectBlocks || CFGVerifier.verify(cfg);
         return cfg;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java	Thu May 02 12:19:41 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java	Thu May 02 14:12:24 2013 +0200
@@ -76,7 +76,7 @@
         VirtualBoxingNode newVirtual = new VirtualBoxingNode(type, boxingKind);
         assert newVirtual.getFields().length == 1;
 
-        tool.createVirtualObject(newVirtual, new ValueNode[]{v}, 0);
+        tool.createVirtualObject(newVirtual, new ValueNode[]{v}, null);
         tool.replaceWithVirtual(newVirtual);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java	Thu May 02 12:19:41 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java	Thu May 02 14:12:24 2013 +0200
@@ -23,43 +23,24 @@
 package com.oracle.graal.nodes.java;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.debug.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.nodes.virtual.*;
 
 /**
  * The {@code AccessMonitorNode} is the base class of both monitor acquisition and release.
  * <p>
- * The VM needs information about monitors in the debug information. This information is built from
- * the nesting level of {@link MonitorEnterNode} when the LIR is constructed. Therefore, monitor
- * nodes must not be removed from the graph unless it is guaranteed that the nesting level does not
- * change. For example, you must not remove a {@link MonitorEnterNode} for a thread-local object or
- * for a recursive locking. Instead, mark the node as {@link #eliminated}. This makes sure that the
- * meta data still contains the complete locking hierarchy.
- * <p>
  * The Java bytecode specification allows non-balanced locking. Graal does not handle such cases and
  * throws a {@link BailoutException} instead during graph building.
  */
-public abstract class AccessMonitorNode extends AbstractStateSplit implements StateSplit, MemoryCheckpoint, Virtualizable {
+public abstract class AccessMonitorNode extends AbstractStateSplit implements StateSplit, MemoryCheckpoint {
 
     @Input private ValueNode object;
-    private boolean eliminated;
 
     public ValueNode object() {
         return object;
     }
 
-    public boolean eliminated() {
-        return eliminated;
-    }
-
-    public void eliminate() {
-        eliminated = true;
-    }
-
     /**
      * Creates a new AccessMonitor instruction.
      * 
@@ -69,22 +50,4 @@
         super(StampFactory.forVoid());
         this.object = object;
     }
-
-    @Override
-    public void virtualize(VirtualizerTool tool) {
-        State state = tool.getObjectState(object);
-        if (state != null && state.getState() == EscapeState.Virtual && state.getVirtualObject().getClass() == VirtualInstanceNode.class) {
-            Debug.log("monitor operation %s on %s\n", this, state);
-            int newLockCount = state.getLockCount() + (this instanceof MonitorEnterNode ? 1 : -1);
-            state.setLockCount(newLockCount);
-            tool.replaceFirstInput(object(), state.getVirtualObject());
-            tool.customAction(new Runnable() {
-
-                @Override
-                public void run() {
-                    eliminate();
-                }
-            });
-        }
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java	Thu May 02 12:19:41 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java	Thu May 02 14:12:24 2013 +0200
@@ -29,7 +29,7 @@
 /**
  * The {@code MonitorEnterNode} represents the acquisition of a monitor.
  */
-public final class MonitorEnterNode extends AccessMonitorNode implements Lowerable, MonitorEnter, MonitorReference {
+public final class MonitorEnterNode extends AccessMonitorNode implements Virtualizable, Lowerable, MonitorEnter, MonitorReference {
 
     private int lockDepth;
 
@@ -48,6 +48,7 @@
         return new Object[]{LocationNode.ANY_LOCATION};
     }
 
+    @Override
     public void lower(LoweringTool tool, LoweringType loweringType) {
         tool.getRuntime().lower(this, tool);
     }
@@ -59,4 +60,13 @@
     public void setLockDepth(int lockDepth) {
         this.lockDepth = lockDepth;
     }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        State state = tool.getObjectState(object());
+        if (state != null && state.getState() == EscapeState.Virtual && state.getVirtualObject().hasIdentity()) {
+            state.addLock(getLockDepth());
+            tool.delete();
+        }
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java	Thu May 02 12:19:41 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java	Thu May 02 14:12:24 2013 +0200
@@ -22,15 +22,15 @@
  */
 package com.oracle.graal.nodes.java;
 
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.graph.*;
 
 /**
  * The {@code MonitorEnterNode} represents a monitor release.
  */
-public final class MonitorExitNode extends AccessMonitorNode implements Lowerable, Node.IterableNodeType, MonitorExit, MonitorReference {
+public final class MonitorExitNode extends AccessMonitorNode implements Virtualizable, Lowerable, Node.IterableNodeType, MonitorExit, MonitorReference {
 
     private int lockDepth;
 
@@ -49,6 +49,7 @@
         return new Object[]{LocationNode.ANY_LOCATION};
     }
 
+    @Override
     public void lower(LoweringTool tool, LoweringType loweringType) {
         tool.getRuntime().lower(this, tool);
     }
@@ -60,4 +61,14 @@
     public void setLockDepth(int lockDepth) {
         this.lockDepth = lockDepth;
     }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        State state = tool.getObjectState(object());
+        if (state != null && state.getState() == EscapeState.Virtual && state.getVirtualObject().hasIdentity()) {
+            int removedLock = state.removeLock();
+            assert removedLock == getLockDepth();
+            tool.delete();
+        }
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java	Thu May 02 12:19:41 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java	Thu May 02 14:12:24 2013 +0200
@@ -38,8 +38,6 @@
     private final ResolvedJavaType elementType;
     private final boolean fillContents;
 
-    private final boolean locked;
-
     @Override
     public ValueNode length() {
         return length;
@@ -52,14 +50,12 @@
      *            the array itself).
      * @param length the node that produces the length for this allocation.
      * @param fillContents determines whether the array elements should be initialized to zero/null.
-     * @param locked determines whether the array should be locked immediately.
      */
-    public NewArrayNode(ResolvedJavaType elementType, ValueNode length, boolean fillContents, boolean locked) {
+    public NewArrayNode(ResolvedJavaType elementType, ValueNode length, boolean fillContents) {
         super(StampFactory.exactNonNull(elementType.getArrayClass()));
         this.length = length;
         this.elementType = elementType;
         this.fillContents = fillContents;
-        this.locked = locked;
     }
 
     /**
@@ -70,13 +66,6 @@
     }
 
     /**
-     * @return <code>true</code> if the array will be locked immediately.
-     */
-    public boolean locked() {
-        return locked;
-    }
-
-    /**
      * The list of node which produce input for this instruction.
      */
     public ValueNode dimension(int index) {
@@ -111,7 +100,9 @@
 
     @Override
     public void lower(LoweringTool tool, LoweringType loweringType) {
-        tool.getRuntime().lower(this, tool);
+        if (loweringType == LoweringType.AFTER_GUARDS) {
+            tool.getRuntime().lower(this, tool);
+        }
     }
 
     @Override
@@ -125,7 +116,7 @@
                     state[i] = defaultForKind;
                 }
                 VirtualObjectNode virtualObject = new VirtualArrayNode(elementType, constantLength);
-                tool.createVirtualObject(virtualObject, state, 0);
+                tool.createVirtualObject(virtualObject, state, null);
                 tool.replaceWithVirtual(virtualObject);
             }
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java	Thu May 02 12:19:41 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java	Thu May 02 14:12:24 2013 +0200
@@ -37,7 +37,6 @@
 
     private final ResolvedJavaType instanceClass;
     private final boolean fillContents;
-    private final boolean locked;
 
     /**
      * Constructs a NewInstanceNode.
@@ -45,13 +44,11 @@
      * @param type the class being allocated
      * @param fillContents determines whether the new object's fields should be initialized to
      *            zero/null.
-     * @param locked determines whether the new object should be locked immediately.
      */
-    public NewInstanceNode(ResolvedJavaType type, boolean fillContents, boolean locked) {
+    public NewInstanceNode(ResolvedJavaType type, boolean fillContents) {
         super(StampFactory.exactNonNull(type));
         this.instanceClass = type;
         this.fillContents = fillContents;
-        this.locked = locked;
     }
 
     /**
@@ -70,13 +67,6 @@
         return fillContents;
     }
 
-    /**
-     * @return <code>true</code> if the new object will be locked immediately.
-     */
-    public boolean locked() {
-        return locked;
-    }
-
     @Override
     public ValueNode canonical(CanonicalizerTool tool) {
         if (usages().isEmpty()) {
@@ -88,7 +78,9 @@
 
     @Override
     public void lower(LoweringTool tool, LoweringType loweringType) {
-        tool.getRuntime().lower(this, tool);
+        if (loweringType == LoweringType.AFTER_GUARDS) {
+            tool.getRuntime().lower(this, tool);
+        }
     }
 
     @Override
@@ -101,7 +93,7 @@
             for (int i = 0; i < state.length; i++) {
                 state[i] = ConstantNode.defaultForKind(fields[i].getType().getKind(), graph());
             }
-            tool.createVirtualObject(virtualObject, state, 0);
+            tool.createVirtualObject(virtualObject, state, null);
             tool.replaceWithVirtual(virtualObject);
         }
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewMultiArrayNode.java	Thu May 02 12:19:41 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewMultiArrayNode.java	Thu May 02 14:12:24 2013 +0200
@@ -63,7 +63,9 @@
 
     @Override
     public void lower(LoweringTool tool, LoweringType loweringType) {
-        tool.getRuntime().lower(this, tool);
+        if (loweringType == LoweringType.AFTER_GUARDS) {
+            tool.getRuntime().lower(this, tool);
+        }
     }
 
     public ResolvedJavaType type() {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreIndexedNode.java	Thu May 02 12:19:41 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreIndexedNode.java	Thu May 02 14:12:24 2013 +0200
@@ -73,8 +73,11 @@
             ValueNode indexValue = tool.getReplacedValue(index());
             int index = indexValue.isConstant() ? indexValue.asConstant().asInt() : -1;
             if (index >= 0 && index < arrayState.getVirtualObject().entryCount()) {
-                tool.setVirtualEntry(arrayState, index, value());
-                tool.delete();
+                ResolvedJavaType componentType = arrayState.getVirtualObject().type().getComponentType();
+                if (componentType.isPrimitive() || value.objectStamp().alwaysNull() || componentType.isAssignableFrom(value.objectStamp().type())) {
+                    tool.setVirtualEntry(arrayState, index, value());
+                    tool.delete();
+                }
             }
         }
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Virtualizable.java	Thu May 02 12:19:41 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Virtualizable.java	Thu May 02 14:12:24 2013 +0200
@@ -47,9 +47,9 @@
 
         public abstract ValueNode getEntry(int index);
 
-        public abstract int getLockCount();
+        public abstract void addLock(int depth);
 
-        public abstract void setLockCount(int lockCount);
+        public abstract int removeLock();
 
         public abstract ValueNode getMaterializedValue();
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java	Thu May 02 12:19:41 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java	Thu May 02 14:12:24 2013 +0200
@@ -64,9 +64,9 @@
      * 
      * @param virtualObject the new virtual object.
      * @param entryState the initial state of the virtual object's fields.
-     * @param lockCount the initial locking depth.
+     * @param locks the initial locking depths.
      */
-    void createVirtualObject(VirtualObjectNode virtualObject, ValueNode[] entryState, int lockCount);
+    void createVirtualObject(VirtualObjectNode virtualObject, ValueNode[] entryState, int[] locks);
 
     /**
      * Queries the current state of the given value: if it is virtualized (thread-local and the
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/AllocatedObjectNode.java	Thu May 02 14:12:24 2013 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes.virtual;
+
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+
+/**
+ * Selects one object from a {@link CommitAllocationNode}. The object is identified by its
+ * {@link VirtualObjectNode}.
+ */
+public class AllocatedObjectNode extends FloatingNode implements Virtualizable {
+
+    @Input private VirtualObjectNode virtualObject;
+    @Input private CommitAllocationNode commit;
+
+    public AllocatedObjectNode(VirtualObjectNode virtualObject) {
+        super(StampFactory.exactNonNull(virtualObject.type()));
+        this.virtualObject = virtualObject;
+    }
+
+    public VirtualObjectNode getVirtualObject() {
+        return virtualObject;
+    }
+
+    public CommitAllocationNode getCommit() {
+        return commit;
+    }
+
+    public void setCommit(CommitAllocationNode x) {
+        updateUsages(commit, x);
+        commit = x;
+    }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        tool.replaceWithVirtual(getVirtualObject());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/CommitAllocationNode.java	Thu May 02 14:12:24 2013 +0200
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes.virtual;
+
+import java.util.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+
+@NodeInfo(nameTemplate = "Alloc {i#virtualObjects}")
+public final class CommitAllocationNode extends FixedWithNextNode implements VirtualizableAllocation, Lowerable, Node.IterableNodeType, Simplifiable {
+
+    @Input private final NodeInputList<VirtualObjectNode> virtualObjects = new NodeInputList<>(this);
+    @Input private final NodeInputList<ValueNode> values = new NodeInputList<>(this);
+    private final List<int[]> locks = new ArrayList<>();
+
+    public CommitAllocationNode() {
+        super(StampFactory.forVoid());
+    }
+
+    public List<VirtualObjectNode> getVirtualObjects() {
+        return virtualObjects;
+    }
+
+    public List<ValueNode> getValues() {
+        return values;
+    }
+
+    public List<int[]> getLocks() {
+        return locks;
+    }
+
+    @Override
+    public boolean verify() {
+        assertTrue(virtualObjects.size() == locks.size(), "lockCounts size doesn't match");
+        int valueCount = 0;
+        for (VirtualObjectNode virtual : virtualObjects) {
+            valueCount += virtual.entryCount();
+        }
+        assertTrue(values.size() == valueCount, "values size doesn't match");
+        return super.verify();
+    }
+
+    @Override
+    public void lower(LoweringTool tool, LoweringType loweringType) {
+        if (loweringType == LoweringType.AFTER_GUARDS) {
+            tool.getRuntime().lower(this, tool);
+        }
+    }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        int pos = 0;
+        for (int i = 0; i < virtualObjects.size(); i++) {
+            VirtualObjectNode virtualObject = virtualObjects.get(i);
+            int entryCount = virtualObject.entryCount();
+            tool.createVirtualObject(virtualObject, values.subList(pos, pos + entryCount).toArray(new ValueNode[entryCount]), locks.get(i));
+            pos += entryCount;
+        }
+        tool.delete();
+    }
+
+    @Override
+    public Map<Object, Object> getDebugProperties(Map<Object, Object> map) {
+        Map<Object, Object> properties = super.getDebugProperties(map);
+        int valuePos = 0;
+        for (int objIndex = 0; objIndex < virtualObjects.size(); objIndex++) {
+            VirtualObjectNode virtual = virtualObjects.get(objIndex);
+            StringBuilder s = new StringBuilder();
+            s.append(MetaUtil.toJavaName(virtual.type(), false)).append("[");
+            for (int i = 0; i < virtual.entryCount(); i++) {
+                ValueNode value = values.get(valuePos++);
+                s.append(i == 0 ? "" : ",").append(value == null ? "_" : value.toString(Verbosity.Id));
+            }
+            s.append("]");
+            if (locks.get(objIndex).length > 0) {
+                s.append(" locked(").append(Arrays.toString(locks.get(objIndex))).append(")");
+            }
+            properties.put("object(" + virtual.toString(Verbosity.Id) + ")", s.toString());
+        }
+        return properties;
+    }
+
+    @Override
+    public void simplify(SimplifierTool tool) {
+        boolean[] used = new boolean[virtualObjects.size()];
+        int usedCount = 0;
+        for (Node usage : usages()) {
+            AllocatedObjectNode addObject = (AllocatedObjectNode) usage;
+            int index = virtualObjects.indexOf(addObject.getVirtualObject());
+            assert !used[index];
+            used[index] = true;
+            usedCount++;
+        }
+        boolean progress;
+        do {
+            progress = false;
+            int valuePos = 0;
+            for (int objIndex = 0; objIndex < virtualObjects.size(); objIndex++) {
+                VirtualObjectNode virtualObject = virtualObjects.get(objIndex);
+                if (used[objIndex]) {
+                    for (int i = 0; i < virtualObject.entryCount(); i++) {
+                        int index = virtualObjects.indexOf(values.get(valuePos + i));
+                        if (index != -1 && !used[index]) {
+                            progress = true;
+                            used[index] = true;
+                            usedCount++;
+                        }
+                    }
+                }
+                valuePos += virtualObject.entryCount();
+            }
+
+        } while (progress);
+
+        if (usedCount < virtualObjects.size()) {
+            List<VirtualObjectNode> newVirtualObjects = new ArrayList<>(usedCount);
+            List<int[]> newLocks = new ArrayList<>(usedCount);
+            List<ValueNode> newValues = new ArrayList<>();
+            int valuePos = 0;
+            for (int objIndex = 0; objIndex < virtualObjects.size(); objIndex++) {
+                VirtualObjectNode virtualObject = virtualObjects.get(objIndex);
+                if (used[objIndex]) {
+                    newVirtualObjects.add(virtualObject);
+                    newLocks.add(locks.get(objIndex));
+                    newValues.addAll(values.subList(valuePos, valuePos + virtualObject.entryCount()));
+                }
+                valuePos += virtualObject.entryCount();
+            }
+            virtualObjects.clear();
+            virtualObjects.addAll(newVirtualObjects);
+            locks.clear();
+            locks.addAll(newLocks);
+            values.clear();
+            values.addAll(newValues);
+        }
+    }
+
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java	Thu May 02 12:19:41 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java	Thu May 02 14:12:24 2013 +0200
@@ -22,14 +22,11 @@
  */
 package com.oracle.graal.nodes.virtual;
 
-import java.util.*;
-
 import sun.misc.*;
 
 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.*;
 
 @NodeInfo(nameTemplate = "VirtualArray {p#componentType/s}[{p#length}]")
@@ -72,7 +69,7 @@
     }
 
     @Override
-    public String fieldName(int index) {
+    public String entryName(int index) {
         return "[" + index + "]";
     }
 
@@ -143,17 +140,7 @@
     }
 
     @Override
-    public void materializeAt(FixedWithNextNode materializeNode, List<ValueNode> values, boolean defaultValuesOnly, int lockCount) {
-        StructuredGraph graph = (StructuredGraph) graph();
-        ResolvedJavaType element = componentType();
-        NewArrayNode newArray = graph.add(new NewArrayNode(element, ConstantNode.forInt(entryCount(), graph), defaultValuesOnly, lockCount > 0));
-        materializeNode.replaceAtUsages(newArray);
-        graph.addBeforeFixed(materializeNode, newArray);
-        if (!defaultValuesOnly) {
-            for (int i = 0; i < entryCount(); i++) {
-                graph.addBeforeFixed(materializeNode, graph.add(new StoreIndexedNode(newArray, ConstantNode.forInt(i, graph), element.getKind(), values.get(i))));
-            }
-        }
-        graph.removeFixed(materializeNode);
+    public AllocatedObjectNode getMaterializedRepresentation(ValueNode[] entries, int[] locks) {
+        return new AllocatedObjectNode(this);
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualBoxingNode.java	Thu May 02 12:19:41 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualBoxingNode.java	Thu May 02 14:12:24 2013 +0200
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.nodes.virtual;
 
-import java.util.*;
-
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
@@ -48,11 +46,9 @@
     }
 
     @Override
-    public void materializeAt(FixedWithNextNode materializeNode, List<ValueNode> values, boolean defaultValuesOnly, int lockCount) {
-        assert values.size() == 1;
-        assert lockCount == 0;
-        StructuredGraph graph = (StructuredGraph) graph();
-        BoxNode valueOf = graph.add(new BoxNode(values.get(0), type(), boxingKind));
-        graph.replaceFixedWithFixed(materializeNode, valueOf);
+    public ValueNode getMaterializedRepresentation(ValueNode[] entries, int[] locks) {
+        assert entries.length == 1;
+        assert locks.length == 0;
+        return new BoxNode(entries[0], type(), boxingKind);
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualInstanceNode.java	Thu May 02 12:19:41 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualInstanceNode.java	Thu May 02 14:12:24 2013 +0200
@@ -22,14 +22,11 @@
  */
 package com.oracle.graal.nodes.virtual;
 
-import java.util.*;
-
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.java.*;
 
-@NodeInfo(nameTemplate = "VirtualInstance {p#type}")
+@NodeInfo(nameTemplate = "VirtualInstance {p#type/s}")
 public class VirtualInstanceNode extends VirtualObjectNode {
 
     private final ResolvedJavaType type;
@@ -68,7 +65,7 @@
     }
 
     @Override
-    public String fieldName(int index) {
+    public String entryName(int index) {
         return fields[index].getName();
     }
 
@@ -99,16 +96,7 @@
     }
 
     @Override
-    public void materializeAt(FixedWithNextNode materializeNode, List<ValueNode> values, boolean defaultValuesOnly, int lockCount) {
-        StructuredGraph graph = (StructuredGraph) graph();
-        NewInstanceNode newInstance = graph.add(new NewInstanceNode(type(), defaultValuesOnly, lockCount > 0));
-        materializeNode.replaceAtUsages(newInstance);
-        graph.addBeforeFixed(materializeNode, newInstance);
-        if (!defaultValuesOnly) {
-            for (int i = 0; i < entryCount(); i++) {
-                graph.addBeforeFixed(materializeNode, graph.add(new StoreFieldNode(newInstance, field(i), values.get(i))));
-            }
-        }
-        graph.removeFixed(materializeNode);
+    public ValueNode getMaterializedRepresentation(ValueNode[] entries, int[] locks) {
+        return new AllocatedObjectNode(this);
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java	Thu May 02 12:19:41 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java	Thu May 02 14:12:24 2013 +0200
@@ -22,41 +22,68 @@
  */
 package com.oracle.graal.nodes.virtual;
 
-import java.util.*;
-
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
-@NodeInfo(nameTemplate = "VirtualObject {p#type}")
 public abstract class VirtualObjectNode extends ValueNode implements LIRLowerable {
 
     public VirtualObjectNode() {
         super(StampFactory.virtual());
     }
 
+    /**
+     * The type of object described by this {@link VirtualObjectNode}. In case of arrays, this is
+     * the array type (and not the component type).
+     */
     public abstract ResolvedJavaType type();
 
+    /**
+     * The number of entries this virtual object has. Either the number of fields or the number of
+     * array elements.
+     */
     public abstract int entryCount();
 
+    /**
+     * Returns the name of the entry at the given index. Only used for debugging purposes.
+     */
+    public abstract String entryName(int i);
+
+    /**
+     * If the given index denotes an entry in this virtual object, the index of this entry is
+     * returned. If no such entry can be found, this method returns -1.
+     */
+    public abstract int entryIndexForOffset(long constantOffset);
+
+    /**
+     * Returns the {@link Kind} of the entry at the given index.
+     */
+    public abstract Kind entryKind(int index);
+
+    /**
+     * Returns an exact duplicate of this virtual object node, which has not been added to the graph
+     * yet.
+     */
+    public abstract VirtualObjectNode duplicate();
+
+    /**
+     * Specifies whether this virtual object has an object identity. If not, then the result of a
+     * comparison of two virtual objects is determined by comparing their contents.
+     */
+    public boolean hasIdentity() {
+        return true;
+    }
+
+    /**
+     * Returns a node that can be used to materialize this virtual object. If this returns an
+     * {@link AllocatedObjectNode} then this node will be attached to a {@link CommitAllocationNode}
+     * , otherwise the node will just be added to the graph.
+     */
+    public abstract ValueNode getMaterializedRepresentation(ValueNode[] entries, int[] locks);
+
     @Override
     public void generate(LIRGeneratorTool gen) {
         // nothing to do...
     }
-
-    public abstract String fieldName(int i);
-
-    public abstract void materializeAt(FixedWithNextNode materializeNode, List<ValueNode> values, boolean defaultValuesOnly, int lockCount);
-
-    public abstract int entryIndexForOffset(long constantOffset);
-
-    public abstract Kind entryKind(int index);
-
-    public abstract VirtualObjectNode duplicate();
-
-    public boolean hasIdentity() {
-        return true;
-    }
 }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/nodes/MaterializeObjectNode.java	Thu May 02 12:19:41 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,100 +0,0 @@
-/*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.virtual.nodes;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.nodes.virtual.*;
-
-@NodeInfo(nameTemplate = "Materialize {i#virtualObject}")
-public final class MaterializeObjectNode extends FixedWithNextNode implements VirtualizableAllocation, Lowerable, Node.IterableNodeType, Canonicalizable, ArrayLengthProvider {
-
-    @Input private final NodeInputList<ValueNode> values;
-    @Input private final VirtualObjectNode virtualObject;
-    private final int lockCount;
-
-    public MaterializeObjectNode(VirtualObjectNode virtualObject, int lockCount) {
-        super(StampFactory.exactNonNull(virtualObject.type()));
-        this.virtualObject = virtualObject;
-        this.lockCount = lockCount;
-        this.values = new NodeInputList<>(this, virtualObject.entryCount());
-    }
-
-    public NodeInputList<ValueNode> getValues() {
-        return values;
-    }
-
-    public VirtualObjectNode getVirtualObject() {
-        return virtualObject;
-    }
-
-    public int getLockCount() {
-        return lockCount;
-    }
-
-    @Override
-    public ValueNode length() {
-        assert virtualObject.type().isArray();
-        return ConstantNode.forInt(values.size(), graph());
-    }
-
-    /**
-     * @return true if the object that will be created is without locks and has only entries that
-     *         are {@link Constant#defaultForKind(Kind)}, false otherwise.
-     */
-    public boolean isDefault() {
-        if (lockCount > 0) {
-            return false;
-        } else {
-            for (ValueNode value : values) {
-                if (!value.isConstant() || !value.asConstant().isDefaultForKind()) {
-                    return false;
-                }
-            }
-        }
-        return true;
-    }
-
-    @Override
-    public void lower(LoweringTool tool, LoweringType loweringType) {
-        virtualObject.materializeAt(this, values, isDefault(), lockCount);
-    }
-
-    @Override
-    public ValueNode canonical(CanonicalizerTool tool) {
-        if (usages().isEmpty()) {
-            return null;
-        } else {
-            return this;
-        }
-    }
-
-    @Override
-    public void virtualize(VirtualizerTool tool) {
-        tool.createVirtualObject(virtualObject, values.toArray(new ValueNode[values.size()]), lockCount);
-        tool.replaceWithVirtual(virtualObject);
-    }
-}
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/BlockState.java	Thu May 02 12:19:41 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/BlockState.java	Thu May 02 14:12:24 2013 +0200
@@ -26,14 +26,11 @@
 
 import java.util.*;
 
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.Virtualizable.EscapeState;
 import com.oracle.graal.nodes.virtual.*;
-import com.oracle.graal.virtual.nodes.*;
 
 class BlockState {
 
@@ -151,62 +148,50 @@
 
     public void materializeBefore(FixedNode fixed, VirtualObjectNode virtual, EscapeState state, GraphEffectList materializeEffects) {
         PartialEscapeClosure.METRIC_MATERIALIZATIONS.increment();
-        HashSet<VirtualObjectNode> deferred = new HashSet<>();
-        GraphEffectList deferredStores = new GraphEffectList();
-        materializeChangedBefore(fixed, virtual, state, deferred, deferredStores, materializeEffects);
-        materializeEffects.addAll(deferredStores);
+        List<AllocatedObjectNode> objects = new ArrayList<>(2);
+        List<ValueNode> values = new ArrayList<>(8);
+        List<int[]> locks = new ArrayList<>(2);
+        List<ValueNode> otherAllocations = new ArrayList<>(2);
+        materializeWithCommit(virtual, objects, locks, values, otherAllocations, state);
+
+        materializeEffects.addMaterializationBefore(fixed, objects, locks, values, otherAllocations);
     }
 
-    private void materializeChangedBefore(FixedNode fixed, VirtualObjectNode virtual, EscapeState state, HashSet<VirtualObjectNode> deferred, GraphEffectList deferredStores,
-                    GraphEffectList materializeEffects) {
-        trace("materializing %s at %s", virtual, fixed);
+    private void materializeWithCommit(VirtualObjectNode virtual, List<AllocatedObjectNode> objects, List<int[]> locks, List<ValueNode> values, List<ValueNode> otherAllocations, EscapeState state) {
+        trace("materializing %s", virtual);
         ObjectState obj = getObjectState(virtual);
-        if (obj.getLockCount() > 0 && obj.virtual.type().isArray()) {
-            throw new BailoutException("array materialized with lock");
-        }
-
-        ValueNode[] fieldState = obj.getEntries();
 
-        MaterializeObjectNode materialize = new MaterializeObjectNode(virtual, obj.getLockCount());
-        ValueNode[] values = new ValueNode[obj.getEntries().length];
-        obj.escape(materialize, state);
-        deferred.add(virtual);
-        for (int i = 0; i < fieldState.length; i++) {
-            ObjectState valueObj = getObjectState(fieldState[i]);
-            if (valueObj != null) {
-                if (valueObj.isVirtual()) {
-                    materializeChangedBefore(fixed, valueObj.virtual, state, deferred, deferredStores, materializeEffects);
+        ValueNode[] entries = obj.getEntries();
+        ValueNode representation = virtual.getMaterializedRepresentation(entries, obj.getLocks());
+        obj.escape(representation, state);
+        if (representation instanceof AllocatedObjectNode) {
+            objects.add((AllocatedObjectNode) representation);
+            locks.add(obj.getLocks());
+            int pos = values.size();
+            while (values.size() < pos + entries.length) {
+                values.add(null);
+            }
+            for (int i = 0; i < entries.length; i++) {
+                ObjectState entryObj = getObjectState(entries[i]);
+                if (entryObj != null) {
+                    if (entryObj.isVirtual()) {
+                        materializeWithCommit(entryObj.getVirtualObject(), objects, locks, values, otherAllocations, state);
+                    }
+                    values.set(pos + i, entryObj.getMaterializedValue());
+                } else {
+                    values.set(pos + i, entries[i]);
                 }
-                if (deferred.contains(valueObj.virtual)) {
-                    Kind fieldKind;
-                    CyclicMaterializeStoreNode store;
-                    if (virtual instanceof VirtualArrayNode) {
-                        store = new CyclicMaterializeStoreNode(materialize, valueObj.getMaterializedValue(), i);
-                        fieldKind = ((VirtualArrayNode) virtual).componentType().getKind();
-                    } else {
-                        VirtualInstanceNode instanceObject = (VirtualInstanceNode) virtual;
-                        store = new CyclicMaterializeStoreNode(materialize, valueObj.getMaterializedValue(), instanceObject.field(i));
-                        fieldKind = instanceObject.field(i).getType().getKind();
-                    }
-                    deferredStores.addFixedNodeBefore(store, fixed);
-                    values[i] = ConstantNode.defaultForKind(fieldKind, fixed.graph());
-                } else {
-                    values[i] = valueObj.getMaterializedValue();
+            }
+            if (virtual instanceof VirtualInstanceNode) {
+                VirtualInstanceNode instance = (VirtualInstanceNode) virtual;
+                for (int i = 0; i < entries.length; i++) {
+                    readCache.put(new ReadCacheEntry(instance.field(i), representation), values.get(pos + i));
                 }
-            } else {
-                values[i] = fieldState[i];
             }
+        } else {
+            otherAllocations.add(representation);
+            assert obj.getLocks().length == 0;
         }
-        deferred.remove(virtual);
-
-        if (virtual instanceof VirtualInstanceNode) {
-            VirtualInstanceNode instance = (VirtualInstanceNode) virtual;
-            for (int i = 0; i < fieldState.length; i++) {
-                readCache.put(new ReadCacheEntry(instance.field(i), materialize), fieldState[i]);
-            }
-        }
-
-        materializeEffects.addMaterialization(materialize, fixed, values);
     }
 
     void addAndMarkAlias(VirtualObjectNode virtual, ValueNode node, NodeBitMap usages) {
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java	Thu May 02 12:19:41 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java	Thu May 02 14:12:24 2013 +0200
@@ -26,10 +26,10 @@
 
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.debug.*;
 import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.common.*;
-import com.oracle.graal.virtual.nodes.*;
 
 public class GraphEffectList extends EffectList {
 
@@ -118,33 +118,6 @@
     }
 
     /**
-     * Add the materialization node to the graph's control flow at the given position, and then sets
-     * its values.
-     * 
-     * @param node The materialization node that should be added.
-     * @param position The fixed node before which the materialization node should be added.
-     * @param values The values for the materialization node's entries.
-     */
-    public void addMaterialization(final MaterializeObjectNode node, final FixedNode position, final ValueNode[] values) {
-        add(new Effect() {
-
-            @Override
-            public String name() {
-                return "addMaterialization";
-            }
-
-            @Override
-            public void apply(StructuredGraph graph, ArrayList<Node> obsoleteNodes) {
-                assert !node.isAlive() && !node.isDeleted() && position.isAlive();
-                graph.addBeforeFixed(position, graph.add(node));
-                for (int i = 0; i < values.length; i++) {
-                    node.getValues().set(i, values[i]);
-                }
-            }
-        });
-    }
-
-    /**
      * Adds an value to the given phi node.
      * 
      * @param node The phi node to which the value should be added.
@@ -330,4 +303,68 @@
             }
         });
     }
+
+    /**
+     * Add the materialization node to the graph's control flow at the given position, and then sets
+     * its values.
+     * 
+     * @param position The fixed node before which the materialization node should be added.
+     * @param objects The allocated objects.
+     * @param locks The lock depths for each object.
+     * @param values The values (field, elements) of all objects.
+     * @param otherAllocations A list of allocations that need to be added before the rest (used for
+     *            boxing allocations).
+     */
+    public void addMaterializationBefore(final FixedNode position, final List<AllocatedObjectNode> objects, final List<int[]> locks, final List<ValueNode> values,
+                    final List<ValueNode> otherAllocations) {
+        add(new Effect() {
+
+            @Override
+            public String name() {
+                return "addMaterializationBefore";
+            }
+
+            @Override
+            public void apply(StructuredGraph graph, ArrayList<Node> obsoleteNodes) {
+                for (ValueNode otherAllocation : otherAllocations) {
+                    graph.add(otherAllocation);
+                    if (otherAllocation instanceof FixedWithNextNode) {
+                        graph.addBeforeFixed(position, (FixedWithNextNode) otherAllocation);
+                    } else {
+                        assert otherAllocation instanceof FloatingNode;
+                    }
+                }
+                if (!objects.isEmpty()) {
+                    CommitAllocationNode commit;
+                    if (position.predecessor() instanceof CommitAllocationNode) {
+                        commit = (CommitAllocationNode) position.predecessor();
+                    } else {
+                        commit = graph.add(new CommitAllocationNode());
+                        graph.addBeforeFixed(position, commit);
+                    }
+                    for (AllocatedObjectNode obj : objects) {
+                        graph.add(obj);
+                        commit.getVirtualObjects().add(obj.getVirtualObject());
+                        obj.setCommit(commit);
+                    }
+                    commit.getValues().addAll(values);
+                    commit.getLocks().addAll(locks);
+
+                    assert commit.usages().filter(AllocatedObjectNode.class).count() == commit.usages().count();
+                    HashSet<AllocatedObjectNode> materializedValues = new HashSet<>(commit.usages().filter(AllocatedObjectNode.class).snapshot());
+                    for (int i = 0; i < commit.getValues().size(); i++) {
+                        if (materializedValues.contains(commit.getValues().get(i))) {
+                            commit.getValues().set(i, ((AllocatedObjectNode) commit.getValues().get(i)).getVirtualObject());
+                        }
+                    }
+
+                }
+            }
+
+            @Override
+            public boolean isVisible() {
+                return true;
+            }
+        });
+    }
 }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ObjectState.java	Thu May 02 12:19:41 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ObjectState.java	Thu May 02 14:12:24 2013 +0200
@@ -36,32 +36,69 @@
  */
 class ObjectState extends Virtualizable.State {
 
-    public final VirtualObjectNode virtual;
+    private static final int[] EMPTY_INT_ARRAY = new int[0];
+
+    public static final class LockState {
+
+        public final int depth;
+        public final LockState next;
+
+        private LockState(int depth, LockState next) {
+            this.depth = depth;
+            this.next = next;
+        }
+
+        @Override
+        public String toString() {
+            return next == null ? String.valueOf(depth) : depth + "," + next;
+        }
+
+        public static boolean equals(LockState a, LockState b) {
+            if ((a == null) != (b == null)) {
+                return false;
+            }
+            if (a != null) {
+                if (a.depth != b.depth) {
+                    return false;
+                }
+                return equals(a.next, b.next);
+            }
+            return true;
+        }
+    }
+
+    final VirtualObjectNode virtual;
 
     private EscapeState state;
     private ValueNode[] entries;
     private ValueNode materializedValue;
-    private int lockCount;
+    private LockState locks;
 
-    public ObjectState(VirtualObjectNode virtual, ValueNode[] entries, EscapeState state, int lockCount) {
+    public ObjectState(VirtualObjectNode virtual, ValueNode[] entries, EscapeState state, int[] locks) {
         this.virtual = virtual;
         this.entries = entries;
         this.state = state;
-        this.lockCount = lockCount;
+        if (locks == null) {
+            this.locks = null;
+        } else {
+            for (int i = locks.length - 1; i >= 0; i--) {
+                this.locks = new LockState(locks[i], this.locks);
+            }
+        }
     }
 
-    public ObjectState(VirtualObjectNode virtual, ValueNode materializedValue, EscapeState state, int lockCount) {
+    public ObjectState(VirtualObjectNode virtual, ValueNode materializedValue, EscapeState state, LockState locks) {
         this.virtual = virtual;
         this.materializedValue = materializedValue;
         this.state = state;
-        this.lockCount = lockCount;
+        this.locks = locks;
     }
 
     private ObjectState(ObjectState other) {
         virtual = other.virtual;
         entries = other.entries == null ? null : other.entries.clone();
         materializedValue = other.materializedValue;
-        lockCount = other.lockCount;
+        locks = other.locks;
         state = other.state;
     }
 
@@ -120,24 +157,56 @@
     }
 
     @Override
-    public int getLockCount() {
-        return lockCount;
+    public void addLock(int depth) {
+        locks = new LockState(depth, locks);
     }
 
     @Override
-    public void setLockCount(int lockCount) {
-        this.lockCount = lockCount;
+    public int removeLock() {
+        try {
+            return locks.depth;
+        } finally {
+            locks = locks.next;
+        }
+    }
+
+    public int[] getLocks() {
+        if (locks == null) {
+            return EMPTY_INT_ARRAY;
+        }
+        int cnt = 0;
+        LockState current = locks;
+        while (current != null) {
+            cnt++;
+            current = current.next;
+        }
+        int[] result = new int[cnt];
+        current = locks;
+        cnt = 0;
+        while (current != null) {
+            result[cnt++] = current.depth;
+            current = current.next;
+        }
+        return result;
+    }
+
+    public boolean hasLocks() {
+        return locks != null;
+    }
+
+    public boolean locksEqual(ObjectState other) {
+        return LockState.equals(locks, other.locks);
     }
 
     @Override
     public String toString() {
         StringBuilder str = new StringBuilder().append('{');
-        if (lockCount > 0) {
-            str.append('l').append(lockCount).append(' ');
+        if (locks != null) {
+            str.append('l').append(locks).append(' ');
         }
         if (entries != null) {
             for (int i = 0; i < entries.length; i++) {
-                str.append(virtual.fieldName(i)).append('=').append(entries[i]).append(' ');
+                str.append(virtual.entryName(i)).append('=').append(entries[i]).append(' ');
             }
         }
         if (materializedValue != null) {
@@ -152,7 +221,7 @@
         final int prime = 31;
         int result = 1;
         result = prime * result + Arrays.hashCode(entries);
-        result = prime * result + lockCount;
+        result = prime * result + (locks != null ? locks.depth : 0);
         result = prime * result + ((materializedValue == null) ? 0 : materializedValue.hashCode());
         result = prime * result + ((state == null) ? 0 : state.hashCode());
         result = prime * result + ((virtual == null) ? 0 : virtual.hashCode());
@@ -171,7 +240,7 @@
         if (!Arrays.equals(entries, other.entries)) {
             return false;
         }
-        if (lockCount != other.lockCount) {
+        if (!LockState.equals(locks, other.locks)) {
             return false;
         }
         if (materializedValue == null) {
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java	Thu May 02 12:19:41 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java	Thu May 02 14:12:24 2013 +0200
@@ -32,13 +32,13 @@
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.util.*;
+import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.common.CanonicalizerPhase.CustomCanonicalizer;
 import com.oracle.graal.phases.graph.*;
 import com.oracle.graal.phases.schedule.*;
 import com.oracle.graal.phases.tiers.*;
-import com.oracle.graal.virtual.nodes.*;
 
 public class PartialEscapeAnalysisPhase extends BasePhase<HighTierContext> {
 
@@ -126,8 +126,13 @@
 
     private static boolean matches(StructuredGraph graph, String filter) {
         if (filter != null) {
-            ResolvedJavaMethod method = graph.method();
-            return method != null && MetaUtil.format("%H.%n", method).contains(filter);
+            if (filter.startsWith("~")) {
+                ResolvedJavaMethod method = graph.method();
+                return method == null || !MetaUtil.format("%H.%n", method).contains(filter.substring(1));
+            } else {
+                ResolvedJavaMethod method = graph.method();
+                return method != null && MetaUtil.format("%H.%n", method).contains(filter);
+            }
         }
         return true;
     }
@@ -203,32 +208,36 @@
     public static Map<Invoke, Double> getHints(StructuredGraph graph) {
         NodesToDoubles probabilities = new ComputeProbabilityClosure(graph).apply();
         Map<Invoke, Double> hints = null;
-        for (MaterializeObjectNode materialize : graph.getNodes(MaterializeObjectNode.class)) {
+        for (CommitAllocationNode commit : graph.getNodes(CommitAllocationNode.class)) {
             double sum = 0;
             double invokeSum = 0;
-            for (Node usage : materialize.usages()) {
-                if (usage instanceof FixedNode) {
-                    sum += probabilities.get((FixedNode) usage);
-                } else {
-                    if (usage instanceof MethodCallTargetNode) {
-                        invokeSum += probabilities.get(((MethodCallTargetNode) usage).invoke().asNode());
-                    }
-                    for (Node secondLevelUage : materialize.usages()) {
-                        if (secondLevelUage instanceof FixedNode) {
-                            sum += probabilities.get(((FixedNode) secondLevelUage));
+            for (Node commitUsage : commit.usages()) {
+                for (Node usage : commitUsage.usages()) {
+                    if (usage instanceof FixedNode) {
+                        sum += probabilities.get((FixedNode) usage);
+                    } else {
+                        if (usage instanceof MethodCallTargetNode) {
+                            invokeSum += probabilities.get(((MethodCallTargetNode) usage).invoke().asNode());
+                        }
+                        for (Node secondLevelUage : usage.usages()) {
+                            if (secondLevelUage instanceof FixedNode) {
+                                sum += probabilities.get(((FixedNode) secondLevelUage));
+                            }
                         }
                     }
                 }
             }
             // TODO(lstadler) get rid of this magic number
             if (sum > 100 && invokeSum > 0) {
-                for (Node usage : materialize.usages()) {
-                    if (usage instanceof MethodCallTargetNode) {
-                        if (hints == null) {
-                            hints = new HashMap<>();
+                for (Node commitUsage : commit.usages()) {
+                    for (Node usage : commitUsage.usages()) {
+                        if (usage instanceof MethodCallTargetNode) {
+                            if (hints == null) {
+                                hints = new HashMap<>();
+                            }
+                            Invoke invoke = ((MethodCallTargetNode) usage).invoke();
+                            hints.put(invoke, sum / invokeSum);
                         }
-                        Invoke invoke = ((MethodCallTargetNode) usage).invoke();
-                        hints.put(invoke, sum / invokeSum);
                     }
                 }
             }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Thu May 02 12:19:41 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Thu May 02 14:12:24 2013 +0200
@@ -238,7 +238,7 @@
                     }
                 });
                 for (ObjectState obj : state.getStates()) {
-                    if (obj.isVirtual() && obj.getLockCount() > 0) {
+                    if (obj.isVirtual() && obj.hasLocks()) {
                         virtual.add(obj);
                     }
                 }
@@ -502,7 +502,6 @@
                     }
                     int virtual = 0;
                     ObjectState startObj = objStates[0];
-                    int lockCount = startObj.getLockCount();
                     boolean locksMatch = true;
                     ValueNode singleValue = startObj.isVirtual() ? null : startObj.getMaterializedValue();
                     for (ObjectState obj : objStates) {
@@ -514,7 +513,7 @@
                                 singleValue = null;
                             }
                         }
-                        locksMatch &= obj.getLockCount() == lockCount;
+                        locksMatch &= obj.locksEqual(startObj);
                     }
 
                     assert virtual < states.size() || locksMatch : "mismatching lock counts at " + merge;
@@ -531,9 +530,9 @@
                                 ensureMaterialized(state, obj, predecessor.getEndNode(), blockEffects.get(predecessor), METRIC_MATERIALIZATIONS_MERGE);
                                 afterMergeEffects.addPhiInput(materializedValuePhi, obj.getMaterializedValue());
                             }
-                            newState.addObject(object, new ObjectState(object, materializedValuePhi, EscapeState.Global, lockCount));
+                            newState.addObject(object, new ObjectState(object, materializedValuePhi, EscapeState.Global, null));
                         } else {
-                            newState.addObject(object, new ObjectState(object, singleValue, EscapeState.Global, lockCount));
+                            newState.addObject(object, new ObjectState(object, singleValue, EscapeState.Global, null));
                         }
                     } else {
                         assert virtual == states.size();
@@ -567,7 +566,7 @@
                                 values[index] = phis[index];
                             }
                         }
-                        newState.addObject(object, new ObjectState(object, values, EscapeState.Virtual, lockCount));
+                        newState.addObject(object, new ObjectState(object, values, EscapeState.Virtual, startObj.getLocks()));
                     }
                 }
 
@@ -638,7 +637,7 @@
                             }
                         }
                         mergeEffects.addFloatingNode(virtual, "valueObjectNode");
-                        newState.addObject(virtual, new ObjectState(virtual, Arrays.copyOf(phis, phis.length, ValueNode[].class), EscapeState.Virtual, 0));
+                        newState.addObject(virtual, new ObjectState(virtual, Arrays.copyOf(phis, phis.length, ValueNode[].class), EscapeState.Virtual, null));
                         newState.addAndMarkAlias(virtual, virtual, usages);
                         newState.addAndMarkAlias(virtual, phi, usages);
                     } else {
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java	Thu May 02 12:19:41 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java	Thu May 02 14:12:24 2013 +0200
@@ -148,7 +148,7 @@
     }
 
     @Override
-    public void createVirtualObject(VirtualObjectNode virtualObject, ValueNode[] entryState, int lockCount) {
+    public void createVirtualObject(VirtualObjectNode virtualObject, ValueNode[] entryState, int[] locks) {
         trace("{{%s}} ", current);
         if (virtualObject.isAlive()) {
             state.addAndMarkAlias(virtualObject, virtualObject, usages);
@@ -158,7 +158,7 @@
         for (int i = 0; i < entryState.length; i++) {
             entryState[i] = state.getScalarAlias(entryState[i]);
         }
-        state.addObject(virtualObject, new ObjectState(virtualObject, entryState, EscapeState.Virtual, lockCount));
+        state.addObject(virtualObject, new ObjectState(virtualObject, entryState, EscapeState.Virtual, locks));
         state.addAndMarkAlias(virtualObject, virtualObject, usages);
         PartialEscapeClosure.METRIC_ALLOCATION_REMOVED.increment();
     }