changeset 13558:06c13c9bb4b6

Merge.
author Chris Seaton <chris.seaton@oracle.com>
date Wed, 08 Jan 2014 18:20:32 +0000
parents b63357fbe40c (current diff) 83fd2094ff66 (diff)
children 876d56394996
files graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MonitorReference.java
diffstat 29 files changed, 332 insertions(+), 228 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java	Wed Jan 08 17:44:56 2014 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java	Wed Jan 08 18:20:32 2014 +0000
@@ -482,8 +482,8 @@
             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));
+            for (MonitorIdNode monitorId : commit.getLocks(objIndex)) {
+                MonitorEnterNode enter = graph.add(new MonitorEnterNode(allocations[objIndex], monitorId));
                 graph.addBeforeFixed(commit, enter);
                 enter.lower(tool);
             }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java	Wed Jan 08 17:44:56 2014 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java	Wed Jan 08 18:20:32 2014 +0000
@@ -434,7 +434,7 @@
                 args = new Arguments(monitorenterStub, graph.getGuardsStage(), tool.getLoweringStage());
             }
             args.add("object", monitorenterNode.object());
-            args.addConst("lockDepth", monitorenterNode.getLockDepth());
+            args.addConst("lockDepth", monitorenterNode.getMonitorId().getLockDepth());
             boolean tracingEnabledForMethod = stateAfter != null && (isTracingEnabledForMethod(stateAfter.method()) || isTracingEnabledForMethod(graph.method()));
             args.addConst("threadRegister", registers.getThreadRegister());
             args.addConst("stackPointerRegister", registers.getStackPointerRegister());
@@ -461,7 +461,7 @@
                 args = new Arguments(monitorexitStub, graph.getGuardsStage(), tool.getLoweringStage());
             }
             args.add("object", monitorexitNode.object());
-            args.addConst("lockDepth", monitorexitNode.getLockDepth());
+            args.addConst("lockDepth", monitorexitNode.getMonitorId().getLockDepth());
             args.addConst("trace", isTracingEnabledForType(monitorexitNode.object()) || isTracingEnabledForMethod(stateAfter.method()) || isTracingEnabledForMethod(graph.method()));
 
             Map<Node, Node> nodes = template(args).instantiate(providers.getMetaAccess(), monitorexitNode, DEFAULT_REPLACER, args);
@@ -529,7 +529,7 @@
                         callTarget = graph.add(new MethodCallTargetNode(InvokeKind.Static, checkCounter.getMethod(), new ValueNode[]{errMsg}, returnType));
                         invoke = graph.add(new InvokeNode(callTarget, 0));
                         List<ValueNode> stack = Collections.emptyList();
-                        FrameState stateAfter = new FrameState(graph.method(), FrameState.AFTER_BCI, new ValueNode[0], stack, new ValueNode[0], false, false);
+                        FrameState stateAfter = new FrameState(graph.method(), FrameState.AFTER_BCI, new ValueNode[0], stack, new ValueNode[0], new MonitorIdNode[0], false, false);
                         invoke.setStateAfter(graph.add(stateAfter));
                         graph.addBeforeFixed(ret, invoke);
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java	Wed Jan 08 17:44:56 2014 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java	Wed Jan 08 18:20:32 2014 +0000
@@ -25,6 +25,7 @@
 import static com.oracle.graal.compiler.GraalCompiler.*;
 
 import java.lang.reflect.*;
+import java.util.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
@@ -138,7 +139,7 @@
                     newEntryState[i] = originalState.getEntry(i);
                 }
                 VirtualObjectNode newVirtual = originalVirtual.duplicate();
-                tool.createVirtualObject(newVirtual, newEntryState, null);
+                tool.createVirtualObject(newVirtual, newEntryState, Collections.<MonitorIdNode> emptyList());
                 tool.replaceWithVirtual(newVirtual);
             }
         } else {
@@ -159,7 +160,7 @@
                     state[i] = loads[i] = new LoadFieldNode(obj, fields[i]);
                     tool.addNode(loads[i]);
                 }
-                tool.createVirtualObject(newVirtual, state, null);
+                tool.createVirtualObject(newVirtual, state, Collections.<MonitorIdNode> emptyList());
                 tool.replaceWithVirtual(newVirtual);
             }
         }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java	Wed Jan 08 17:44:56 2014 +0000
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java	Wed Jan 08 18:20:32 2014 +0000
@@ -34,19 +34,22 @@
 import com.oracle.graal.graph.Node.Verbosity;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
 
 public class FrameStateBuilder {
 
     private static final ValueNode[] EMPTY_ARRAY = new ValueNode[0];
+    private static final MonitorIdNode[] EMPTY_MONITOR_ARRAY = new MonitorIdNode[0];
 
     private final ResolvedJavaMethod method;
     private final StructuredGraph graph;
 
     private final ValueNode[] locals;
     private final ValueNode[] stack;
-    private ValueNode[] locks;
+    private ValueNode[] lockedObjects;
+    private MonitorIdNode[] monitorIds;
 
     private int stackSize;
 
@@ -62,7 +65,8 @@
         this.locals = new ValueNode[method.getMaxLocals()];
         // we always need at least one stack slot (for exceptions)
         this.stack = new ValueNode[Math.max(1, method.getMaxStackSize())];
-        this.locks = EMPTY_ARRAY;
+        this.lockedObjects = EMPTY_ARRAY;
+        this.monitorIds = EMPTY_MONITOR_ARRAY;
 
         int javaIndex = 0;
         int index = 0;
@@ -100,12 +104,14 @@
         graph = other.graph;
         locals = other.locals.clone();
         stack = other.stack.clone();
-        locks = other.locks == EMPTY_ARRAY ? EMPTY_ARRAY : other.locks.clone();
+        lockedObjects = other.lockedObjects == EMPTY_ARRAY ? EMPTY_ARRAY : other.lockedObjects.clone();
+        monitorIds = other.monitorIds == EMPTY_MONITOR_ARRAY ? EMPTY_MONITOR_ARRAY : other.monitorIds.clone();
         stackSize = other.stackSize;
         rethrowException = other.rethrowException;
 
         assert locals.length == method.getMaxLocals();
         assert stack.length == Math.max(1, method.getMaxStackSize());
+        assert lockedObjects.length == monitorIds.length;
     }
 
     @Override
@@ -120,8 +126,8 @@
             sb.append(i == 0 ? "" : ",").append(stack[i] == null ? "_" : stack[i].toString(Verbosity.Id));
         }
         sb.append("] locks: [");
-        for (int i = 0; i < locks.length; i++) {
-            sb.append(i == 0 ? "" : ",").append(locks[i] == null ? "_" : locks[i].toString(Verbosity.Id));
+        for (int i = 0; i < lockedObjects.length; i++) {
+            sb.append(i == 0 ? "" : ",").append(lockedObjects[i].toString(Verbosity.Id)).append(" / ").append(monitorIds[i].toString(Verbosity.Id));
         }
         sb.append("]");
         if (rethrowException) {
@@ -132,7 +138,7 @@
     }
 
     public FrameState create(int bci) {
-        return graph.add(new FrameState(method, bci, locals, Arrays.asList(stack).subList(0, stackSize), locks, rethrowException, false));
+        return graph.add(new FrameState(method, bci, locals, Arrays.asList(stack).subList(0, stackSize), lockedObjects, monitorIds, rethrowException, false));
     }
 
     public FrameStateBuilder copy() {
@@ -141,6 +147,7 @@
 
     public boolean isCompatibleWith(FrameStateBuilder other) {
         assert method == other.method && graph == other.graph && localsSize() == other.localsSize() : "Can only compare frame states of the same method";
+        assert lockedObjects.length == monitorIds.length && other.lockedObjects.length == other.monitorIds.length : "mismatch between lockedObjects and monitorIds";
 
         if (stackSize() != other.stackSize()) {
             return false;
@@ -152,11 +159,11 @@
                 return false;
             }
         }
-        if (locks.length != other.locks.length) {
+        if (lockedObjects.length != other.lockedObjects.length) {
             return false;
         }
-        for (int i = 0; i < locks.length; i++) {
-            if (GraphUtil.originalValue(locks[i]) != GraphUtil.originalValue(other.locks[i])) {
+        for (int i = 0; i < lockedObjects.length; i++) {
+            if (GraphUtil.originalValue(lockedObjects[i]) != GraphUtil.originalValue(other.lockedObjects[i]) || monitorIds[i] != other.monitorIds[i]) {
                 throw new BailoutException("unbalanced monitors");
             }
         }
@@ -172,8 +179,9 @@
         for (int i = 0; i < stackSize(); i++) {
             storeStack(i, merge(stackAt(i), other.stackAt(i), block));
         }
-        for (int i = 0; i < locks.length; i++) {
-            locks[i] = merge(locks[i], other.locks[i], block);
+        for (int i = 0; i < lockedObjects.length; i++) {
+            lockedObjects[i] = merge(lockedObjects[i], other.lockedObjects[i], block);
+            assert monitorIds[i] == other.monitorIds[i];
         }
     }
 
@@ -234,8 +242,8 @@
         for (int i = 0; i < stackSize(); i++) {
             storeStack(i, createLoopPhi(loopBegin, stackAt(i)));
         }
-        for (int i = 0; i < locks.length; i++) {
-            locks[i] = createLoopPhi(loopBegin, locks[i]);
+        for (int i = 0; i < lockedObjects.length; i++) {
+            lockedObjects[i] = createLoopPhi(loopBegin, lockedObjects[i]);
         }
     }
 
@@ -254,11 +262,11 @@
                 storeStack(i, ProxyNode.forValue(value, loopExit, graph));
             }
         }
-        for (int i = 0; i < locks.length; i++) {
-            ValueNode value = locks[i];
+        for (int i = 0; i < lockedObjects.length; i++) {
+            ValueNode value = lockedObjects[i];
             if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) {
                 Debug.log(" inserting proxy for %s", value);
-                locks[i] = ProxyNode.forValue(value, loopExit, graph);
+                lockedObjects[i] = ProxyNode.forValue(value, loopExit, graph);
             }
         }
     }
@@ -278,11 +286,11 @@
                 storeStack(i, ProxyNode.forValue(value, begin, graph));
             }
         }
-        for (int i = 0; i < locks.length; i++) {
-            ValueNode value = locks[i];
+        for (int i = 0; i < lockedObjects.length; i++) {
+            ValueNode value = lockedObjects[i];
             if (value != null) {
                 Debug.log(" inserting proxy for %s", value);
-                locks[i] = ProxyNode.forValue(value, begin, graph);
+                lockedObjects[i] = ProxyNode.forValue(value, begin, graph);
             }
         }
     }
@@ -373,10 +381,13 @@
      * 
      * @param object the object whose monitor will be locked.
      */
-    public void pushLock(ValueNode object) {
+    public void pushLock(ValueNode object, MonitorIdNode monitorId) {
         assert object.isAlive() && object.kind() == Kind.Object : "unexpected value: " + object;
-        locks = Arrays.copyOf(locks, locks.length + 1);
-        locks[locks.length - 1] = object;
+        lockedObjects = Arrays.copyOf(lockedObjects, lockedObjects.length + 1);
+        monitorIds = Arrays.copyOf(monitorIds, monitorIds.length + 1);
+        lockedObjects[lockedObjects.length - 1] = object;
+        monitorIds[monitorIds.length - 1] = monitorId;
+        assert lockedObjects.length == monitorIds.length;
     }
 
     /**
@@ -386,17 +397,23 @@
      */
     public ValueNode popLock() {
         try {
-            return locks[locks.length - 1];
+            return lockedObjects[lockedObjects.length - 1];
         } finally {
-            locks = locks.length == 1 ? EMPTY_ARRAY : Arrays.copyOf(locks, locks.length - 1);
+            lockedObjects = lockedObjects.length == 1 ? EMPTY_ARRAY : Arrays.copyOf(lockedObjects, lockedObjects.length - 1);
+            monitorIds = monitorIds.length == 1 ? EMPTY_MONITOR_ARRAY : Arrays.copyOf(monitorIds, monitorIds.length - 1);
         }
     }
 
+    public MonitorIdNode peekMonitorId() {
+        return monitorIds[monitorIds.length - 1];
+    }
+
     /**
      * @return the current lock depth
      */
     public int lockDepth() {
-        return locks.length;
+        assert lockedObjects.length == monitorIds.length;
+        return lockedObjects.length;
     }
 
     /**
@@ -660,8 +677,9 @@
                 return true;
             }
         }
-        for (int i = 0; i < locks.length; i++) {
-            if (locks[i] == value) {
+        assert lockedObjects.length == monitorIds.length;
+        for (int i = 0; i < lockedObjects.length; i++) {
+            if (lockedObjects[i] == value || monitorIds[i] == value) {
                 return true;
             }
         }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Wed Jan 08 17:44:56 2014 +0000
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Wed Jan 08 18:20:32 2014 +0000
@@ -1247,17 +1247,19 @@
     }
 
     private MonitorEnterNode genMonitorEnter(ValueNode x) {
-        MonitorEnterNode monitorEnter = append(new MonitorEnterNode(x, frameState.lockDepth()));
-        frameState.pushLock(x);
+        MonitorIdNode monitorId = currentGraph.add(new MonitorIdNode(frameState.lockDepth()));
+        MonitorEnterNode monitorEnter = append(new MonitorEnterNode(x, monitorId));
+        frameState.pushLock(x, monitorId);
         return monitorEnter;
     }
 
     private MonitorExitNode genMonitorExit(ValueNode x, ValueNode returnValue) {
+        MonitorIdNode monitorId = frameState.peekMonitorId();
         ValueNode lockedObject = frameState.popLock();
         if (GraphUtil.originalValue(lockedObject) != GraphUtil.originalValue(x)) {
             throw new BailoutException("unbalanced monitors: mismatch at monitorexit, %s != %s", GraphUtil.originalValue(x), GraphUtil.originalValue(lockedObject));
         }
-        MonitorExitNode monitorExit = append(new MonitorExitNode(x, returnValue, frameState.lockDepth()));
+        MonitorExitNode monitorExit = append(new MonitorExitNode(x, monitorId, returnValue));
         return monitorExit;
     }
 
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java	Wed Jan 08 17:44:56 2014 +0000
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java	Wed Jan 08 18:20:32 2014 +0000
@@ -31,6 +31,7 @@
 import com.oracle.graal.nodes.VirtualState.NodeClosure;
 import com.oracle.graal.nodes.VirtualState.VirtualClosure;
 import com.oracle.graal.nodes.cfg.*;
+import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.virtual.*;
 
 public abstract class LoopFragment {
@@ -198,11 +199,13 @@
                         markFloating(obj, nodes, notloopNodes);
                     }
                 }
+                if (n instanceof MonitorEnterNode) {
+                    markFloating(((MonitorEnterNode) n).getMonitorId(), nodes, notloopNodes);
+                }
                 for (Node usage : n.usages()) {
                     markFloating(usage, nodes, notloopNodes);
                 }
             }
-
         }
 
         return nodes;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Wed Jan 08 17:44:56 2014 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Wed Jan 08 18:20:32 2014 +0000
@@ -28,6 +28,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.iterators.*;
+import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.virtual.*;
 
 /**
@@ -81,8 +82,13 @@
 
     @Input private FrameState outerFrameState;
 
+    /**
+     * Contains the locals, the expressions and the locked objects, in this order.
+     */
     @Input private final NodeInputList<ValueNode> values;
 
+    @Input private final NodeInputList<MonitorIdNode> monitorIds;
+
     @Input private final NodeInputList<EscapeObjectState> virtualObjectMappings;
 
     /**
@@ -93,16 +99,20 @@
     private final ResolvedJavaMethod method;
 
     /**
-     * Creates a {@code FrameState} for the given scope and maximum number of stack and local
-     * variables.
+     * Creates a {@code FrameState} with the given locals, stack expressions and locked monitors.
      * 
      * @param method the method for this frame state
      * @param bci the bytecode index of the frame state
-     * @param stackSize size of the stack
-     * @param rethrowException if true the VM should re-throw the exception on top of the stack when
-     *            deopt'ing using this framestate
+     * @param values the locals, stack expressions and locked objects, in this order
+     * @param localsSize the number of locals in the values list
+     * @param stackSize the number of stack expressions in the values list
+     * @param rethrowException if true, this FrameState will throw an exception (taken from the top
+     *            of the expression stack) during deoptimization
+     * @param duringCall true if this FrameState describes the state during a call
+     * @param monitorIds one MonitorIdNode for each locked object
+     * @param virtualObjectMappings a description of the current state for every virtual object
      */
-    public FrameState(ResolvedJavaMethod method, int bci, List<ValueNode> values, int localsSize, int stackSize, boolean rethrowException, boolean duringCall,
+    public FrameState(ResolvedJavaMethod method, int bci, List<ValueNode> values, int localsSize, int stackSize, boolean rethrowException, boolean duringCall, List<MonitorIdNode> monitorIds,
                     List<EscapeObjectState> virtualObjectMappings) {
         assert stackSize >= 0;
         this.method = method;
@@ -110,10 +120,12 @@
         this.localsSize = localsSize;
         this.stackSize = stackSize;
         this.values = new NodeInputList<>(this, values);
+        this.monitorIds = new NodeInputList<>(this, monitorIds);
         this.virtualObjectMappings = new NodeInputList<>(this, virtualObjectMappings);
         this.rethrowException = rethrowException;
         this.duringCall = duringCall;
         assert !rethrowException || stackSize == 1 : "must have exception on top of the stack";
+        assert values.size() - localsSize - stackSize == monitorIds.size();
     }
 
     /**
@@ -122,11 +134,12 @@
      * @param bci marker bci, needs to be < 0
      */
     public FrameState(int bci) {
-        this(null, bci, Collections.<ValueNode> emptyList(), 0, 0, false, false, Collections.<EscapeObjectState> emptyList());
+        this(null, bci, Collections.<ValueNode> emptyList(), 0, 0, false, false, Collections.<MonitorIdNode> emptyList(), Collections.<EscapeObjectState> emptyList());
+        assert bci == BEFORE_BCI || bci == AFTER_BCI || bci == AFTER_EXCEPTION_BCI || bci == UNKNOWN_BCI || bci == INVALID_FRAMESTATE_BCI;
     }
 
-    public FrameState(ResolvedJavaMethod method, int bci, ValueNode[] locals, List<ValueNode> stack, ValueNode[] locks, boolean rethrowException, boolean duringCall) {
-        this(method, bci, createValues(locals, stack, locks), locals.length, stack.size(), rethrowException, duringCall, Collections.<EscapeObjectState> emptyList());
+    public FrameState(ResolvedJavaMethod method, int bci, ValueNode[] locals, List<ValueNode> stack, ValueNode[] locks, MonitorIdNode[] monitorIds, boolean rethrowException, boolean duringCall) {
+        this(method, bci, createValues(locals, stack, locks), locals.length, stack.size(), rethrowException, duringCall, Arrays.asList(monitorIds), Collections.<EscapeObjectState> emptyList());
     }
 
     private static List<ValueNode> createValues(ValueNode[] locals, List<ValueNode> stack, ValueNode[] locks) {
@@ -198,7 +211,7 @@
      * Gets a copy of this frame state.
      */
     public FrameState duplicate(int newBci) {
-        FrameState other = graph().add(new FrameState(method, newBci, values, localsSize, stackSize, rethrowException, duringCall, virtualObjectMappings));
+        FrameState other = graph().add(new FrameState(method, newBci, values, localsSize, stackSize, rethrowException, duringCall, monitorIds, virtualObjectMappings));
         other.setOuterFrameState(outerFrameState());
         return other;
     }
@@ -224,7 +237,7 @@
         for (EscapeObjectState state : virtualObjectMappings) {
             newVirtualMappings.add(state.duplicateWithVirtualState());
         }
-        FrameState other = graph().add(new FrameState(method, bci, values, localsSize, stackSize, rethrowException, duringCall, newVirtualMappings));
+        FrameState other = graph().add(new FrameState(method, bci, values, localsSize, stackSize, rethrowException, duringCall, monitorIds, newVirtualMappings));
         other.setOuterFrameState(newOuterFrameState);
         return other;
     }
@@ -248,7 +261,7 @@
         int newStackSize = copy.size() - localsSize;
         copy.addAll(values.subList(localsSize + stackSize, values.size()));
 
-        FrameState other = graph().add(new FrameState(method, newBci, copy, localsSize, newStackSize, newRethrowException, false, virtualObjectMappings));
+        FrameState other = graph().add(new FrameState(method, newBci, copy, localsSize, newStackSize, newRethrowException, false, monitorIds, virtualObjectMappings));
         other.setOuterFrameState(outerFrameState());
         return other;
     }
@@ -319,6 +332,14 @@
         return values.get(localsSize + stackSize + i);
     }
 
+    /**
+     * Get the MonitorIdNode that corresponds to the locked object at the specified index.
+     */
+    public MonitorIdNode monitorIdAt(int i) {
+        assert i >= 0 && i < locksSize();
+        return monitorIds.get(i);
+    }
+
     public NodeIterable<FrameState> innerFrameStates() {
         return usages().filter(FrameState.class);
     }
@@ -375,9 +396,10 @@
 
     @Override
     public boolean verify() {
+        assertTrue(values.size() - localsSize - stackSize == monitorIds.size(), "mismatch in number of locks");
         for (ValueNode value : values) {
-            assert assertTrue(value == null || !value.isDeleted(), "frame state must not contain deleted nodes");
-            assert assertTrue(value == null || value instanceof VirtualObjectNode || (value.kind() != Kind.Void), "unexpected value: %s", value);
+            assertTrue(value == null || !value.isDeleted(), "frame state must not contain deleted nodes");
+            assertTrue(value == null || value instanceof VirtualObjectNode || (value.kind() != Kind.Void), "unexpected value: %s", value);
         }
         return super.verify();
     }
@@ -387,6 +409,9 @@
         for (ValueNode value : values.nonNull()) {
             closure.apply(this, value);
         }
+        for (MonitorIdNode monitorId : monitorIds) {
+            closure.apply(this, monitorId);
+        }
         for (EscapeObjectState state : virtualObjectMappings) {
             state.applyToNonVirtual(closure);
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java	Wed Jan 08 17:44:56 2014 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java	Wed Jan 08 18:20:32 2014 +0000
@@ -22,11 +22,14 @@
  */
 package com.oracle.graal.nodes.extended;
 
+import java.util.*;
+
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.virtual.*;
@@ -79,7 +82,7 @@
         VirtualBoxingNode newVirtual = new VirtualBoxingNode(type, boxingKind);
         assert newVirtual.getFields().length == 1;
 
-        tool.createVirtualObject(newVirtual, new ValueNode[]{v}, null);
+        tool.createVirtualObject(newVirtual, new ValueNode[]{v}, Collections.<MonitorIdNode> emptyList());
         tool.replaceWithVirtual(newVirtual);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MonitorReference.java	Wed Jan 08 17:44:56 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes.extended;
-
-/**
- * Denotes an instruction that references a monitor and wants to know its lock nesting depth.
- */
-public interface MonitorReference {
-
-    /**
-     * Sets the depth of the lock referenced by this operation.
-     */
-    void setLockDepth(int lockDepth);
-
-    /**
-     * Gets the depth of the lock referenced by this operation.
-     */
-    int getLockDepth();
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java	Wed Jan 08 17:44:56 2014 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java	Wed Jan 08 18:20:32 2014 +0000
@@ -36,18 +36,24 @@
 public abstract class AccessMonitorNode extends AbstractMemoryCheckpoint implements MemoryCheckpoint {
 
     @Input private ValueNode object;
+    @Input private MonitorIdNode monitorId;
 
     public ValueNode object() {
         return object;
     }
 
+    public MonitorIdNode getMonitorId() {
+        return monitorId;
+    }
+
     /**
      * Creates a new AccessMonitor instruction.
      * 
      * @param object the instruction producing the object
      */
-    public AccessMonitorNode(ValueNode object) {
+    public AccessMonitorNode(ValueNode object, MonitorIdNode monitorId) {
         super(StampFactory.forVoid());
         this.object = object;
+        this.monitorId = monitorId;
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java	Wed Jan 08 17:44:56 2014 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java	Wed Jan 08 18:20:32 2014 +0000
@@ -30,18 +30,15 @@
 /**
  * The {@code MonitorEnterNode} represents the acquisition of a monitor.
  */
-public final class MonitorEnterNode extends AccessMonitorNode implements Virtualizable, Lowerable, MonitorEnter, MemoryCheckpoint.Single, MonitorReference {
-
-    private int lockDepth;
+public final class MonitorEnterNode extends AccessMonitorNode implements Virtualizable, Lowerable, MonitorEnter, MemoryCheckpoint.Single {
 
     /**
      * Creates a new MonitorEnterNode.
      * 
      * @param object the instruction producing the object
      */
-    public MonitorEnterNode(ValueNode object, int lockDepth) {
-        super(object);
-        this.lockDepth = lockDepth;
+    public MonitorEnterNode(ValueNode object, MonitorIdNode monitorId) {
+        super(object, monitorId);
     }
 
     @Override
@@ -54,19 +51,11 @@
         tool.getLowerer().lower(this, tool);
     }
 
-    public int getLockDepth() {
-        return lockDepth;
-    }
-
-    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());
+            state.addLock(getMonitorId());
             tool.delete();
         }
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java	Wed Jan 08 17:44:56 2014 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java	Wed Jan 08 18:20:32 2014 +0000
@@ -34,19 +34,16 @@
  * a synchronized method, then the return value of the method will be referenced, so that it will be
  * materialized before releasing the monitor.
  */
-public final class MonitorExitNode extends AccessMonitorNode implements Virtualizable, Simplifiable, Lowerable, IterableNodeType, MonitorExit, MemoryCheckpoint.Single, MonitorReference {
+public final class MonitorExitNode extends AccessMonitorNode implements Virtualizable, Simplifiable, Lowerable, IterableNodeType, MonitorExit, MemoryCheckpoint.Single {
 
     @Input private ValueNode escapedReturnValue;
 
-    private int lockDepth;
-
     /**
      * Creates a new MonitorExitNode.
      */
-    public MonitorExitNode(ValueNode object, ValueNode escapedReturnValue, int lockDepth) {
-        super(object);
+    public MonitorExitNode(ValueNode object, MonitorIdNode monitorId, ValueNode escapedReturnValue) {
+        super(object, monitorId);
         this.escapedReturnValue = escapedReturnValue;
-        this.lockDepth = lockDepth;
     }
 
     public void setEscapedReturnValue(ValueNode x) {
@@ -73,22 +70,17 @@
         tool.getLowerer().lower(this, tool);
     }
 
-    public int getLockDepth() {
-        return lockDepth;
-    }
-
-    public void setLockDepth(int lockDepth) {
-        this.lockDepth = lockDepth;
-    }
-
     @Override
     public void virtualize(VirtualizerTool tool) {
         State state = tool.getObjectState(object());
         // the monitor exit for a synchronized method should never be virtualized
         assert stateAfter().bci != FrameState.AFTER_BCI || state == null;
         if (state != null && state.getState() == EscapeState.Virtual && state.getVirtualObject().hasIdentity()) {
-            int removedLock = state.removeLock();
-            assert removedLock == getLockDepth();
+            MonitorIdNode removedLock = state.removeLock();
+            if (removedLock != getMonitorId()) {
+                throw new GraalInternalError("mismatch at %s: %s vs. %s", this, removedLock, getMonitorId());
+            }
+            assert removedLock == getMonitorId() : "mismatch at " + this + ": " + removedLock + " vs. " + getMonitorId();
             tool.delete();
         }
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorIdNode.java	Wed Jan 08 18:20:32 2014 +0000
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes.java;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+
+/**
+ * This node describes one locking scope; it ties the monitor enter, monitor exit and the frame
+ * states together. It is thus referenced from the {@link MonitorEnterNode}, from the
+ * {@link MonitorExitNode} and from the {@link FrameState}.
+ */
+public final class MonitorIdNode extends ValueNode implements IterableNodeType, LIRLowerable {
+
+    private int lockDepth;
+
+    public MonitorIdNode(int lockDepth) {
+        super(StampFactory.dependency());
+        this.lockDepth = lockDepth;
+    }
+
+    public int getLockDepth() {
+        return lockDepth;
+    }
+
+    public void setLockDepth(int lockDepth) {
+        this.lockDepth = lockDepth;
+    }
+
+    public void generate(LIRGeneratorTool generator) {
+        // nothing to do
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java	Wed Jan 08 17:44:56 2014 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java	Wed Jan 08 18:20:32 2014 +0000
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.nodes.java;
 
+import java.util.*;
+
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
@@ -66,7 +68,7 @@
                     state[i] = defaultForKind;
                 }
                 VirtualObjectNode virtualObject = new VirtualArrayNode(elementType(), constantLength);
-                tool.createVirtualObject(virtualObject, state, null);
+                tool.createVirtualObject(virtualObject, state, Collections.<MonitorIdNode> emptyList());
                 tool.replaceWithVirtual(virtualObject);
             }
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java	Wed Jan 08 17:44:56 2014 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java	Wed Jan 08 18:20:32 2014 +0000
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes.java;
 
 import java.lang.ref.*;
+import java.util.*;
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
@@ -74,7 +75,7 @@
             for (int i = 0; i < state.length; i++) {
                 state[i] = defaultFieldValue(fields[i]);
             }
-            tool.createVirtualObject(virtualObject, state, null);
+            tool.createVirtualObject(virtualObject, state, Collections.<MonitorIdNode> emptyList());
             tool.replaceWithVirtual(virtualObject);
         }
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Virtualizable.java	Wed Jan 08 17:44:56 2014 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Virtualizable.java	Wed Jan 08 18:20:32 2014 +0000
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes.spi;
 
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.virtual.*;
 
 /**
@@ -45,9 +46,9 @@
 
         public abstract ValueNode getEntry(int index);
 
-        public abstract void addLock(int depth);
+        public abstract void addLock(MonitorIdNode monitorId);
 
-        public abstract int removeLock();
+        public abstract MonitorIdNode removeLock();
 
         public abstract ValueNode getMaterializedValue();
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java	Wed Jan 08 17:44:56 2014 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java	Wed Jan 08 18:20:32 2014 +0000
@@ -22,10 +22,13 @@
  */
 package com.oracle.graal.nodes.spi;
 
+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.java.*;
 import com.oracle.graal.nodes.spi.Virtualizable.State;
 import com.oracle.graal.nodes.virtual.*;
 
@@ -66,7 +69,7 @@
      * @param entryState the initial state of the virtual object's fields.
      * @param locks the initial locking depths.
      */
-    void createVirtualObject(VirtualObjectNode virtualObject, ValueNode[] entryState, int[] locks);
+    void createVirtualObject(VirtualObjectNode virtualObject, ValueNode[] entryState, List<MonitorIdNode> locks);
 
     /**
      * Queries the current state of the given value: if it is virtualized (thread-local and the
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/CommitAllocationNode.java	Wed Jan 08 17:44:56 2014 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/CommitAllocationNode.java	Wed Jan 08 18:20:32 2014 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2014, 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
@@ -28,6 +28,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -36,7 +37,8 @@
 
     @Input private final NodeInputList<VirtualObjectNode> virtualObjects = new NodeInputList<>(this);
     @Input private final NodeInputList<ValueNode> values = new NodeInputList<>(this);
-    private List<int[]> locks = new ArrayList<>();
+    @Input private final NodeInputList<MonitorIdNode> locks = new NodeInputList<>(this);
+    private ArrayList<Integer> lockIndexes = new ArrayList<>(Arrays.asList(0));
 
     public CommitAllocationNode() {
         super(StampFactory.forVoid());
@@ -50,13 +52,14 @@
         return values;
     }
 
-    public List<int[]> getLocks() {
-        return locks;
+    public List<MonitorIdNode> getLocks(int objIndex) {
+        return locks.subList(lockIndexes.get(objIndex), lockIndexes.get(objIndex + 1));
     }
 
     @Override
     public boolean verify() {
-        assertTrue(virtualObjects.size() == locks.size(), "lockCounts size doesn't match " + virtualObjects + ", " + locks);
+        assertTrue(virtualObjects.size() + 1 == lockIndexes.size(), "lockIndexes size doesn't match " + virtualObjects + ", " + lockIndexes);
+        assertTrue(lockIndexes.get(lockIndexes.size() - 1) == locks.size(), "locks size doesn't match " + lockIndexes + ", " + locks);
         int valueCount = 0;
         for (VirtualObjectNode virtual : virtualObjects) {
             valueCount += virtual.entryCount();
@@ -72,7 +75,12 @@
 
     @Override
     public void afterClone(Node other) {
-        locks = new ArrayList<>(((CommitAllocationNode) other).locks);
+        lockIndexes = new ArrayList<>(lockIndexes);
+    }
+
+    public void addLocks(List<MonitorIdNode> monitorIds) {
+        locks.addAll(monitorIds);
+        lockIndexes.add(locks.size());
     }
 
     @Override
@@ -81,7 +89,7 @@
         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));
+            tool.createVirtualObject(virtualObject, values.subList(pos, pos + entryCount).toArray(new ValueNode[entryCount]), getLocks(i));
             pos += entryCount;
         }
         tool.delete();
@@ -100,8 +108,8 @@
                 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(")");
+            if (!getLocks(objIndex).isEmpty()) {
+                s.append(" locked(").append(locks.get(objIndex)).append(")");
             }
             properties.put("object(" + virtual.toString(Verbosity.Id) + ")", s.toString());
         }
@@ -150,14 +158,17 @@
 
         if (usedCount < virtualObjects.size()) {
             List<VirtualObjectNode> newVirtualObjects = new ArrayList<>(usedCount);
-            List<int[]> newLocks = new ArrayList<>(usedCount);
+            List<MonitorIdNode> newLocks = new ArrayList<>(usedCount);
+            ArrayList<Integer> newLockIndexes = new ArrayList<>(usedCount + 1);
+            newLockIndexes.add(0);
             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));
+                    newLocks.addAll(getLocks(objIndex));
+                    newLockIndexes.add(newLocks.size());
                     newValues.addAll(values.subList(valuePos, valuePos + virtualObject.entryCount()));
                 }
                 valuePos += virtualObject.entryCount();
@@ -168,6 +179,7 @@
             locks.addAll(newLocks);
             values.clear();
             values.addAll(newValues);
+            lockIndexes = newLockIndexes;
         }
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/LockState.java	Wed Jan 08 18:20:32 2014 +0000
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2011, 2014, 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.nodes.java.*;
+
+/**
+ * The class implements a simple linked list of MonitorIdNodes, which can be used to describe the
+ * current lock state of an object.
+ */
+public final class LockState {
+
+    public final MonitorIdNode monitorId;
+    public final LockState next;
+
+    public LockState(MonitorIdNode monitorId, LockState next) {
+        this.monitorId = monitorId;
+        this.next = next;
+    }
+
+    @Override
+    public String toString() {
+        return monitorId.getLockDepth() + (next == null ? "" : "," + next);
+    }
+
+    public static List<MonitorIdNode> asList(LockState state) {
+        if (state == null) {
+            return Collections.emptyList();
+        } else {
+            ArrayList<MonitorIdNode> result = new ArrayList<>();
+            LockState a = state;
+            do {
+                result.add(a.monitorId);
+                a = a.next;
+            } while (a != null);
+            return result;
+        }
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java	Wed Jan 08 17:44:56 2014 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java	Wed Jan 08 18:20:32 2014 +0000
@@ -141,7 +141,7 @@
     }
 
     @Override
-    public ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, int[] locks) {
+    public ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, LockState locks) {
         return new AllocatedObjectNode(this);
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualBoxingNode.java	Wed Jan 08 17:44:56 2014 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualBoxingNode.java	Wed Jan 08 18:20:32 2014 +0000
@@ -41,9 +41,9 @@
     }
 
     @Override
-    public ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, int[] locks) {
+    public ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, LockState locks) {
         assert entries.length == 1;
-        assert locks.length == 0;
+        assert locks == null;
         return new BoxNode(entries[0], type(), boxingKind);
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualInstanceNode.java	Wed Jan 08 17:44:56 2014 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualInstanceNode.java	Wed Jan 08 18:20:32 2014 +0000
@@ -101,7 +101,7 @@
     }
 
     @Override
-    public ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, int[] locks) {
+    public ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, LockState locks) {
         return new AllocatedObjectNode(this);
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java	Wed Jan 08 17:44:56 2014 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java	Wed Jan 08 18:20:32 2014 +0000
@@ -88,7 +88,7 @@
      * {@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(FixedNode fixed, ValueNode[] entries, int[] locks);
+    public abstract ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, LockState locks);
 
     @Override
     public void generate(LIRGeneratorTool gen) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Wed Jan 08 17:44:56 2014 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Wed Jan 08 18:20:32 2014 +0000
@@ -1395,10 +1395,9 @@
         if (stateAfter != null) {
             FrameState outerFrameState = null;
             int callerLockDepth = stateAfter.nestedLockDepth();
-            for (Node inlinedNode : inlineGraph.getNodes()) {
-                Node node = duplicates.get(inlinedNode);
-                if (node instanceof FrameState) {
-                    FrameState frameState = (FrameState) node;
+            for (FrameState original : inlineGraph.getNodes(FrameState.class)) {
+                FrameState frameState = (FrameState) duplicates.get(original);
+                if (frameState != null) {
                     assert frameState.bci != FrameState.BEFORE_BCI : frameState;
                     if (frameState.bci == FrameState.AFTER_BCI) {
                         frameState.replaceAndDelete(stateAfter);
@@ -1421,8 +1420,10 @@
                         }
                     }
                 }
-                if (callerLockDepth != 0 && node instanceof MonitorReference) {
-                    MonitorReference monitor = (MonitorReference) node;
+            }
+            if (callerLockDepth != 0) {
+                for (MonitorIdNode original : inlineGraph.getNodes(MonitorIdNode.class)) {
+                    MonitorIdNode monitor = (MonitorIdNode) duplicates.get(original);
                     monitor.setLockDepth(monitor.getLockDepth() + callerLockDepth);
                 }
             }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/NewFrameNode.java	Wed Jan 08 17:44:56 2014 +0000
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/NewFrameNode.java	Wed Jan 08 18:20:32 2014 +0000
@@ -102,7 +102,7 @@
         }
 
         @Override
-        public ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, int[] locks) {
+        public ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, LockState locks) {
             if (allowMaterialization) {
                 return super.getMaterializedRepresentation(fixed, entries, locks);
             }
@@ -173,9 +173,9 @@
             tool.getAssumptions().record(new AssumptionValidAssumption((OptimizedAssumption) frameDescriptor.getVersion()));
         }
 
-        tool.createVirtualObject(virtualFrameObjectArray, objectArrayEntryState, null);
-        tool.createVirtualObject(virtualFramePrimitiveArray, primitiveArrayEntryState, null);
-        tool.createVirtualObject(virtualFrameTagArray, tagArrayEntryState, null);
+        tool.createVirtualObject(virtualFrameObjectArray, objectArrayEntryState, Collections.<MonitorIdNode> emptyList());
+        tool.createVirtualObject(virtualFramePrimitiveArray, primitiveArrayEntryState, Collections.<MonitorIdNode> emptyList());
+        tool.createVirtualObject(virtualFrameTagArray, tagArrayEntryState, Collections.<MonitorIdNode> emptyList());
 
         assert frameFields.length == 6;
         ValueNode[] frameEntryState = new ValueNode[frameFields.length];
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java	Wed Jan 08 17:44:56 2014 +0000
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java	Wed Jan 08 18:20:32 2014 +0000
@@ -28,6 +28,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.debug.*;
+import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.common.*;
 
@@ -308,7 +309,7 @@
      * @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,
+    public void addMaterializationBefore(final FixedNode position, final List<AllocatedObjectNode> objects, final List<List<MonitorIdNode>> locks, final List<ValueNode> values,
                     final List<ValueNode> otherAllocations) {
         add(new Effect() {
 
@@ -341,7 +342,9 @@
                         obj.setCommit(commit);
                     }
                     commit.getValues().addAll(values);
-                    commit.getLocks().addAll(locks);
+                    for (List<MonitorIdNode> monitorIds : locks) {
+                        commit.addLocks(monitorIds);
+                    }
 
                     assert commit.usages().filter(AllocatedObjectNode.class).count() == commit.usages().count();
                     List<AllocatedObjectNode> materializedValues = commit.usages().filter(AllocatedObjectNode.class).snapshot();
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ObjectState.java	Wed Jan 08 17:44:56 2014 +0000
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ObjectState.java	Wed Jan 08 18:20:32 2014 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2014, 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
@@ -25,6 +25,7 @@
 import java.util.*;
 
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.spi.Virtualizable.EscapeState;
 import com.oracle.graal.nodes.virtual.*;
@@ -36,37 +37,6 @@
  */
 public class ObjectState extends Virtualizable.State {
 
-    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;
@@ -74,17 +44,18 @@
     private ValueNode materializedValue;
     private LockState locks;
 
-    public ObjectState(VirtualObjectNode virtual, ValueNode[] entries, EscapeState state, int[] locks) {
+    public ObjectState(VirtualObjectNode virtual, ValueNode[] entries, EscapeState state, List<MonitorIdNode> locks) {
+        this(virtual, entries, state, (LockState) null);
+        for (int i = locks.size() - 1; i >= 0; i--) {
+            this.locks = new LockState(locks.get(i), this.locks);
+        }
+    }
+
+    public ObjectState(VirtualObjectNode virtual, ValueNode[] entries, EscapeState state, LockState locks) {
         this.virtual = virtual;
         this.entries = entries;
         this.state = state;
-        if (locks == null) {
-            this.locks = null;
-        } else {
-            for (int i = locks.length - 1; i >= 0; i--) {
-                this.locks = new LockState(locks[i], this.locks);
-            }
-        }
+        this.locks = locks;
     }
 
     public ObjectState(VirtualObjectNode virtual, ValueNode materializedValue, EscapeState state, LockState locks) {
@@ -156,37 +127,21 @@
     }
 
     @Override
-    public void addLock(int depth) {
-        locks = new LockState(depth, locks);
+    public void addLock(MonitorIdNode monitorId) {
+        locks = new LockState(monitorId, locks);
     }
 
     @Override
-    public int removeLock() {
+    public MonitorIdNode removeLock() {
         try {
-            return locks.depth;
+            return locks.monitorId;
         } 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 LockState getLocks() {
+        return locks;
     }
 
     public boolean hasLocks() {
@@ -194,7 +149,13 @@
     }
 
     public boolean locksEqual(ObjectState other) {
-        return LockState.equals(locks, other.locks);
+        LockState a = locks;
+        LockState b = other.locks;
+        while (a != null && b != null && a.monitorId == b.monitorId) {
+            a = a.next;
+            b = b.next;
+        }
+        return a == null && b == null;
     }
 
     @Override
@@ -220,7 +181,7 @@
         final int prime = 31;
         int result = 1;
         result = prime * result + Arrays.hashCode(entries);
-        result = prime * result + (locks != null ? locks.depth : 0);
+        result = prime * result + (locks != null ? locks.monitorId.getLockDepth() : 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());
@@ -239,7 +200,7 @@
         if (!Arrays.equals(entries, other.entries)) {
             return false;
         }
-        if (!LockState.equals(locks, other.locks)) {
+        if (!locksEqual(other)) {
             return false;
         }
         if (materializedValue == null) {
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeBlockState.java	Wed Jan 08 17:44:56 2014 +0000
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeBlockState.java	Wed Jan 08 18:20:32 2014 +0000
@@ -25,6 +25,7 @@
 import java.util.*;
 
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.Virtualizable.EscapeState;
 import com.oracle.graal.nodes.virtual.*;
 
@@ -68,15 +69,15 @@
         PartialEscapeClosure.METRIC_MATERIALIZATIONS.increment();
         List<AllocatedObjectNode> objects = new ArrayList<>(2);
         List<ValueNode> values = new ArrayList<>(8);
-        List<int[]> locks = new ArrayList<>(2);
+        List<List<MonitorIdNode>> locks = new ArrayList<>(2);
         List<ValueNode> otherAllocations = new ArrayList<>(2);
         materializeWithCommit(fixed, virtual, objects, locks, values, otherAllocations, state);
 
         materializeEffects.addMaterializationBefore(fixed, objects, locks, values, otherAllocations);
     }
 
-    private void materializeWithCommit(FixedNode fixed, VirtualObjectNode virtual, List<AllocatedObjectNode> objects, List<int[]> locks, List<ValueNode> values, List<ValueNode> otherAllocations,
-                    EscapeState state) {
+    private void materializeWithCommit(FixedNode fixed, VirtualObjectNode virtual, List<AllocatedObjectNode> objects, List<List<MonitorIdNode>> locks, List<ValueNode> values,
+                    List<ValueNode> otherAllocations, EscapeState state) {
         ObjectState obj = getObjectState(virtual);
 
         ValueNode[] entries = obj.getEntries();
@@ -84,7 +85,7 @@
         obj.escape(representation, state);
         if (representation instanceof AllocatedObjectNode) {
             objects.add((AllocatedObjectNode) representation);
-            locks.add(obj.getLocks());
+            locks.add(LockState.asList(obj.getLocks()));
             int pos = values.size();
             while (values.size() < pos + entries.length) {
                 values.add(null);
@@ -104,7 +105,7 @@
         } else {
             VirtualUtil.trace("materialized %s as %s", virtual, representation);
             otherAllocations.add(representation);
-            assert obj.getLocks().length == 0;
+            assert obj.getLocks() == null;
         }
     }
 
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java	Wed Jan 08 17:44:56 2014 +0000
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java	Wed Jan 08 18:20:32 2014 +0000
@@ -24,11 +24,14 @@
 
 import static com.oracle.graal.phases.GraalOptions.*;
 
+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.calc.*;
+import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.Virtualizable.EscapeState;
 import com.oracle.graal.nodes.spi.Virtualizable.State;
 import com.oracle.graal.nodes.spi.*;
@@ -150,7 +153,7 @@
     }
 
     @Override
-    public void createVirtualObject(VirtualObjectNode virtualObject, ValueNode[] entryState, int[] locks) {
+    public void createVirtualObject(VirtualObjectNode virtualObject, ValueNode[] entryState, List<MonitorIdNode> locks) {
         VirtualUtil.trace("{{%s}} ", current);
         if (!virtualObject.isAlive()) {
             effects.addFloatingNode(virtualObject, "newVirtualObject");