changeset 8586:82f6a25321b8

modeling of lock state removed from LIR and runtime specific debug info for locks moved into runtime specific classes
author Doug Simon <doug.simon@oracle.com>
date Fri, 29 Mar 2013 12:31:42 +0100
parents aaf3988bd1b4
children 6b5b9673de9f
files graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotDebugInfoBuilder.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRGenerator.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLockStack.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentLockNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EndLockScopeNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorExitStubCall.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MonitorReference.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java
diffstat 17 files changed, 325 insertions(+), 109 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Fri Mar 29 12:22:27 2013 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Fri Mar 29 12:31:42 2013 +0100
@@ -34,18 +34,21 @@
 import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.virtual.nodes.*;
 
+/**
+ * Builds {@link LIRFrameState}s from {@link FrameState}s.
+ */
 public class DebugInfoBuilder {
 
-    private final NodeMap<Value> nodeOperands;
+    protected final NodeMap<Value> nodeOperands;
 
     public DebugInfoBuilder(NodeMap<Value> nodeOperands) {
         this.nodeOperands = nodeOperands;
     }
 
-    private HashMap<VirtualObjectNode, VirtualObject> virtualObjects = new HashMap<>();
-    private IdentityHashMap<VirtualObjectNode, EscapeObjectState> objectStates = new IdentityHashMap<>();
+    protected HashMap<VirtualObjectNode, VirtualObject> virtualObjects = new HashMap<>();
+    protected IdentityHashMap<VirtualObjectNode, EscapeObjectState> objectStates = new IdentityHashMap<>();
 
-    public LIRFrameState build(FrameState topState, List<StackSlot> lockData, short reason, LabelRef exceptionEdge) {
+    public LIRFrameState build(FrameState topState, short reason, LabelRef exceptionEdge) {
         assert virtualObjects.size() == 0;
         assert objectStates.size() == 0;
 
@@ -65,7 +68,7 @@
             current = current.outerFrameState();
         } while (current != null);
 
-        BytecodeFrame frame = computeFrameForState(topState, lockData);
+        BytecodeFrame frame = computeFrameForState(topState);
 
         VirtualObject[] virtualObjectsArray = null;
         if (virtualObjects.size() != 0) {
@@ -106,40 +109,55 @@
         return new LIRFrameState(frame, virtualObjectsArray, exceptionEdge, reason);
     }
 
-    private BytecodeFrame computeFrameForState(FrameState state, List<StackSlot> lockDataSlots) {
+    protected BytecodeFrame computeFrameForState(FrameState state) {
         int numLocals = state.localsSize();
         int numStack = state.stackSize();
         int numLocks = state.locksSize();
 
         Value[] values = new Value[numLocals + numStack + numLocks];
-        for (int i = 0; i < numLocals; i++) {
-            values[i] = toValue(state.localAt(i));
-        }
-        for (int i = 0; i < numStack; i++) {
-            values[numLocals + i] = toValue(state.stackAt(i));
-        }
-        for (int i = 0; i < numLocks; i++) {
-            // frames are traversed from the outside in, so the locks for the current frame are at
-            // the end of the lockDataSlots list
-            StackSlot lockData = lockDataSlots.get(lockDataSlots.size() - numLocks + i);
-            values[numLocals + numStack + i] = new MonitorValue(toValue(state.lockAt(i)), lockData, state.lockAt(i) instanceof VirtualObjectNode);
-        }
+        computeLocals(state, numLocals, values);
+        computeStack(state, numLocals, numStack, values);
+        computeLocks(state, values);
 
         BytecodeFrame caller = null;
         if (state.outerFrameState() != null) {
-            // remove the locks that were used for this frame from the lockDataSlots list
-            List<StackSlot> nextLockDataSlots = lockDataSlots.subList(0, lockDataSlots.size() - numLocks);
-            caller = computeFrameForState(state.outerFrameState(), nextLockDataSlots);
-        } else {
-            if (lockDataSlots.size() != numLocks) {
-                throw new BailoutException("unbalanced monitors: found monitor for unknown frame (%d != %d) at %s", lockDataSlots.size(), numLocks, state);
-            }
+            caller = computeFrameForState(state.outerFrameState());
         }
         assert state.bci >= 0 || state.bci == FrameState.BEFORE_BCI : "bci == " + state.bci;
         return new BytecodeFrame(caller, state.method(), state.bci, state.rethrowException(), state.duringCall(), values, numLocals, numStack, numLocks);
     }
 
-    private Value toValue(ValueNode value) {
+    protected void computeLocals(FrameState state, int numLocals, Value[] values) {
+        for (int i = 0; i < numLocals; i++) {
+            values[i] = computeLocalValue(state, i);
+        }
+    }
+
+    protected Value computeLocalValue(FrameState state, int i) {
+        return toValue(state.localAt(i));
+    }
+
+    protected void computeStack(FrameState state, int numLocals, int numStack, Value[] values) {
+        for (int i = 0; i < numStack; i++) {
+            values[numLocals + i] = computeStackValue(state, i);
+        }
+    }
+
+    protected Value computeStackValue(FrameState state, int i) {
+        return toValue(state.stackAt(i));
+    }
+
+    protected void computeLocks(FrameState state, Value[] values) {
+        for (int i = 0; i < state.locksSize(); i++) {
+            values[state.localsSize() + state.stackSize() + i] = computeLockValue(state, i);
+        }
+    }
+
+    protected Value computeLockValue(FrameState state, int i) {
+        return toValue(state.lockAt(i));
+    }
+
+    protected Value toValue(ValueNode value) {
         if (value instanceof VirtualObjectNode) {
             VirtualObjectNode obj = (VirtualObjectNode) value;
             EscapeObjectState state = objectStates.get(obj);
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Fri Mar 29 12:22:27 2013 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Fri Mar 29 12:31:42 2013 +0100
@@ -63,7 +63,7 @@
     protected final TargetDescription target;
     protected final ResolvedJavaMethod method;
 
-    private final DebugInfoBuilder debugInfoBuilder;
+    protected final DebugInfoBuilder debugInfoBuilder;
 
     protected Block currentBlock;
     private ValueNode currentInstruction;
@@ -76,22 +76,6 @@
     private final BlockMap<FrameState> blockLastState;
 
     /**
-     * The number of currently locked monitors.
-     */
-    private int currentLockCount;
-
-    /**
-     * Mapping from blocks to the number of locked monitors at the end of the block.
-     */
-    private final BlockMap<Integer> blockLastLockCount;
-
-    /**
-     * Contains the lock data slot for each lock depth (so these may be reused within a compiled
-     * method).
-     */
-    private final ArrayList<StackSlot> lockDataSlots;
-
-    /**
      * Checks whether the supplied constant can be used without loading it into a register for store
      * operations, i.e., on the right hand side of a memory access.
      * 
@@ -109,12 +93,15 @@
         this.method = method;
         this.nodeOperands = graph.createNodeMap();
         this.lir = lir;
-        this.debugInfoBuilder = new DebugInfoBuilder(nodeOperands);
-        this.blockLastLockCount = new BlockMap<>(lir.cfg);
-        this.lockDataSlots = new ArrayList<>();
+        this.debugInfoBuilder = createDebugInfoBuilder(nodeOperands);
         this.blockLastState = new BlockMap<>(lir.cfg);
     }
 
+    @SuppressWarnings("hiding")
+    protected DebugInfoBuilder createDebugInfoBuilder(NodeMap<Value> nodeOperands) {
+        return new DebugInfoBuilder(nodeOperands);
+    }
+
     @Override
     public TargetDescription target() {
         return target;
@@ -248,7 +235,7 @@
         if (needOnlyOopMaps()) {
             return new LIRFrameState(null, null, null, (short) -1);
         }
-        return debugInfoBuilder.build(state, lockDataSlots.subList(0, currentLockCount), lir.getDeoptimizationReasons().addSpeculation(reason), exceptionEdge);
+        return debugInfoBuilder.build(state, lir.getDeoptimizationReasons().addSpeculation(reason), exceptionEdge);
     }
 
     /**
@@ -297,22 +284,10 @@
 
         if (block == lir.cfg.getStartBlock()) {
             assert block.getPredecessorCount() == 0;
-            currentLockCount = 0;
             emitPrologue();
 
         } else {
             assert block.getPredecessorCount() > 0;
-
-            currentLockCount = -1;
-            for (Block pred : block.getPredecessors()) {
-                Integer predLocks = blockLastLockCount.get(pred);
-                if (currentLockCount == -1) {
-                    currentLockCount = predLocks;
-                } else {
-                    assert (predLocks == null && pred.isLoopEnd()) || currentLockCount == predLocks;
-                }
-            }
-
             FrameState fs = null;
 
             for (Block pred : block.getPredecessors()) {
@@ -401,7 +376,6 @@
         // share the frame state that flowed into the loop
         assert blockLastState.get(block) == null || blockLastState.get(block) == lastState;
 
-        blockLastLockCount.put(currentBlock, currentLockCount);
         blockLastState.put(block, lastState);
         currentBlock = null;
 
@@ -480,36 +454,6 @@
         append(new ParametersOp(params));
     }
 
-    /**
-     * Increases the number of currently locked monitors and makes sure that a lock data slot is
-     * available for the new lock.
-     */
-    public void lock() {
-        if (lockDataSlots.size() == currentLockCount) {
-            lockDataSlots.add(frameMap.allocateStackBlock(runtime.getSizeOfLockData(), false));
-        }
-        currentLockCount++;
-    }
-
-    /**
-     * Decreases the number of currently locked monitors.
-     * 
-     * @throws GraalInternalError if the number of currently locked monitors is already zero.
-     */
-    public void unlock() {
-        if (currentLockCount == 0) {
-            throw new GraalInternalError("unmatched locks");
-        }
-        currentLockCount--;
-    }
-
-    /**
-     * @return The lock data slot for the topmost locked monitor.
-     */
-    public StackSlot peekLock() {
-        return lockDataSlots.get(currentLockCount - 1);
-    }
-
     @Override
     public void visitReturn(ReturnNode x) {
         Value operand = Value.ILLEGAL;
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Fri Mar 29 12:22:27 2013 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Fri Mar 29 12:31:42 2013 +0100
@@ -35,6 +35,8 @@
 import com.oracle.graal.asm.*;
 import com.oracle.graal.asm.amd64.AMD64Address.*;
 import com.oracle.graal.compiler.amd64.*;
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
@@ -84,6 +86,19 @@
      */
     List<AMD64HotSpotEpilogueOp> epilogueOps = new ArrayList<>(2);
 
+    @SuppressWarnings("hiding")
+    @Override
+    protected DebugInfoBuilder createDebugInfoBuilder(NodeMap<Value> nodeOperands) {
+        assert runtime().config.basicLockSize == 8;
+        HotSpotLockStack lockStack = new HotSpotLockStack(frameMap, Kind.Long);
+        return new HotSpotDebugInfoBuilder(nodeOperands, lockStack);
+    }
+
+    @Override
+    public StackSlot getLockSlot(int lockDepth) {
+        return ((HotSpotDebugInfoBuilder) debugInfoBuilder).lockStack().makeLockSlot(lockDepth);
+    }
+
     @Override
     protected void emitPrologue() {
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotDebugInfoBuilder.java	Fri Mar 29 12:31:42 2013 +0100
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.virtual.*;
+
+/**
+ * Extends {@link DebugInfoBuilder} to allocate the extra debug information required for locks.
+ */
+public class HotSpotDebugInfoBuilder extends DebugInfoBuilder {
+
+    private final HotSpotLockStack lockStack;
+
+    public HotSpotDebugInfoBuilder(NodeMap<Value> nodeOperands, HotSpotLockStack lockStack) {
+        super(nodeOperands);
+        this.lockStack = lockStack;
+    }
+
+    public HotSpotLockStack lockStack() {
+        return lockStack;
+    }
+
+    @Override
+    protected Value computeLockValue(FrameState state, int i) {
+        int lockDepth = i;
+        for (FrameState outer = state.outerFrameState(); outer != null; outer = outer.outerFrameState()) {
+            lockDepth += outer.locksSize();
+        }
+        StackSlot slot = lockStack.makeLockSlot(lockDepth);
+        ValueNode lock = state.lockAt(i);
+        Value object = toValue(lock);
+        boolean eliminated = lock instanceof VirtualObjectNode;
+        return new MonitorValue(object, slot, eliminated);
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRGenerator.java	Fri Mar 29 12:22:27 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRGenerator.java	Fri Mar 29 12:31:42 2013 +0100
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.hotspot;
 
+import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.hotspot.nodes.*;
@@ -42,4 +43,9 @@
     void emitTailcall(Value[] args, Value address);
 
     void visitDirectCompareAndSwap(DirectCompareAndSwapNode x);
+
+    /**
+     * Gets a stack slot for a lock at a given lock nesting depth.
+     */
+    StackSlot getLockSlot(int lockDepth);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLockStack.java	Fri Mar 29 12:31:42 2013 +0100
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.lir.*;
+
+/**
+ * Manages allocation and re-use of lock slots in a scoped manner. The slots are used in HotSpot's
+ * lightweight locking mechanism to store the mark word of an object being locked.
+ */
+public class HotSpotLockStack {
+
+    private StackSlot[] locks;
+    private final FrameMap frameMap;
+    private final Kind slotKind;
+
+    public HotSpotLockStack(FrameMap frameMap, Kind slotKind) {
+        this.frameMap = frameMap;
+        this.slotKind = slotKind;
+    }
+
+    /**
+     * Gets a stack slot for a lock at a given lock nesting depth, allocating it first if necessary.
+     */
+    public StackSlot makeLockSlot(int lockDepth) {
+        if (locks == null) {
+            locks = new StackSlot[lockDepth + 1];
+        } else if (locks.length < lockDepth + 1) {
+            locks = Arrays.copyOf(locks, lockDepth + 1);
+        }
+        if (locks[lockDepth] == null) {
+            locks[lockDepth] = frameMap.allocateSpillSlot(slotKind);
+        }
+        return locks[lockDepth];
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java	Fri Mar 29 12:22:27 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java	Fri Mar 29 12:31:42 2013 +0100
@@ -26,6 +26,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.gen.*;
 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.*;
@@ -37,15 +38,25 @@
  * 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 {
+public final class BeginLockScopeNode extends AbstractStateSplit implements LIRGenLowerable, MonitorEnter, MonitorReference {
 
     private final boolean eliminated;
 
+    private int lockDepth = -1;
+
     public BeginLockScopeNode(boolean eliminated) {
         super(StampFactory.forWord());
         this.eliminated = eliminated;
     }
 
+    public int getLockDepth() {
+        return lockDepth;
+    }
+
+    public void setLockDepth(int lockDepth) {
+        this.lockDepth = lockDepth;
+    }
+
     @Override
     public boolean hasSideEffect() {
         return false;
@@ -58,11 +69,12 @@
 
     @Override
     public void generate(LIRGenerator gen) {
-        gen.lock();
-        StackSlot lockData = gen.peekLock();
+        assert lockDepth != -1;
         assert stateAfter() != null;
+        HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen;
+        StackSlot slot = hsGen.getLockSlot(lockDepth);
         if (!eliminated) {
-            Value result = gen.emitLea(lockData);
+            Value result = gen.emitLea(slot);
             gen.setResult(this, result);
         }
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentLockNode.java	Fri Mar 29 12:22:27 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentLockNode.java	Fri Mar 29 12:31:42 2013 +0100
@@ -22,26 +22,42 @@
  */
 package com.oracle.graal.hotspot.nodes;
 
+import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.gen.*;
 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 {
+public final class CurrentLockNode extends FixedWithNextNode implements LIRGenLowerable, MonitorReference {
+
+    private int lockDepth = -1;
 
     public CurrentLockNode() {
         super(StampFactory.forWord());
     }
 
+    public int getLockDepth() {
+        return lockDepth;
+    }
+
+    public void setLockDepth(int lockDepth) {
+        this.lockDepth = lockDepth;
+    }
+
     @Override
     public void generate(LIRGenerator gen) {
+        assert lockDepth != -1;
+        HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen;
+        StackSlot slot = hsGen.getLockSlot(lockDepth);
         // The register allocator cannot handle stack -> register moves so we use an LEA here
-        Value result = gen.emitMove(gen.emitLea(gen.peekLock()));
+        Value result = gen.emitMove(gen.emitLea(slot));
         gen.setResult(this, result);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EndLockScopeNode.java	Fri Mar 29 12:22:27 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EndLockScopeNode.java	Fri Mar 29 12:31:42 2013 +0100
@@ -50,7 +50,6 @@
 
     @Override
     public void generate(LIRGenerator gen) {
-        gen.unlock();
     }
 
     @NodeIntrinsic
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorExitStubCall.java	Fri Mar 29 12:22:27 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorExitStubCall.java	Fri Mar 29 12:31:42 2013 +0100
@@ -26,16 +26,19 @@
 import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.compiler.gen.*;
 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 FixedWithNextNode implements LIRGenLowerable {
+public class MonitorExitStubCall extends FixedWithNextNode implements LIRGenLowerable, MonitorReference {
 
     @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) {
@@ -43,10 +46,21 @@
         this.object = object;
     }
 
+    public int getLockDepth() {
+        return lockDepth;
+    }
+
+    public void setLockDepth(int lockDepth) {
+        this.lockDepth = lockDepth;
+    }
+
     @Override
     public void generate(LIRGenerator gen) {
+        assert lockDepth != -1;
+        HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen;
+        StackSlot slot = hsGen.getLockSlot(lockDepth);
         RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(MonitorExitStubCall.MONITOREXIT);
-        gen.emitCall(stub, stub.getCallingConvention(), true, gen.operand(object), gen.emitLea(gen.peekLock()));
+        gen.emitCall(stub, stub.getCallingConvention(), true, gen.operand(object), gen.emitLea(slot));
     }
 
     @NodeIntrinsic
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java	Fri Mar 29 12:22:27 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java	Fri Mar 29 12:31:42 2013 +0100
@@ -451,6 +451,9 @@
                     BeginLockScopeNode begin = (BeginLockScopeNode) n;
                     begin.setStateAfter(stateAfter);
                 }
+                if (n instanceof MonitorReference) {
+                    ((MonitorReference) n).setLockDepth(monitorenterNode.getLockDepth());
+                }
             }
         }
 
@@ -474,6 +477,9 @@
                     EndLockScopeNode end = (EndLockScopeNode) n;
                     end.setStateAfter(stateAfter);
                 }
+                if (n instanceof MonitorReference) {
+                    ((MonitorReference) n).setLockDepth(monitorexitNode.getLockDepth());
+                }
             }
         }
 
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java	Fri Mar 29 12:22:27 2013 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java	Fri Mar 29 12:31:42 2013 +0100
@@ -376,10 +376,10 @@
     }
 
     /**
-     * @return true if there are no locks within this frame state.
+     * @return the current lock depth
      */
-    public boolean locksEmpty() {
-        return locks.length == 0;
+    public int lockDepth() {
+        return locks.length;
     }
 
     /**
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Fri Mar 29 12:22:27 2013 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Fri Mar 29 12:31:42 2013 +0100
@@ -1153,18 +1153,18 @@
     }
 
     private MonitorEnterNode genMonitorEnter(ValueNode x) {
+        MonitorEnterNode monitorEnter = currentGraph.add(new MonitorEnterNode(x, frameState.lockDepth()));
         frameState.pushLock(x);
-        MonitorEnterNode monitorEnter = currentGraph.add(new MonitorEnterNode(x));
         appendWithBCI(monitorEnter);
         return monitorEnter;
     }
 
     private MonitorExitNode genMonitorExit(ValueNode x) {
         ValueNode lockedObject = frameState.popLock();
+        MonitorExitNode monitorExit = currentGraph.add(new MonitorExitNode(x, frameState.lockDepth()));
         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 = currentGraph.add(new MonitorExitNode(x));
         appendWithBCI(monitorExit);
         return monitorExit;
     }
@@ -1568,7 +1568,7 @@
         }
 
         synchronizedEpilogue(FrameState.AFTER_BCI);
-        if (!frameState.locksEmpty()) {
+        if (frameState.lockDepth() != 0) {
             throw new BailoutException("unbalanced monitors");
         }
         ReturnNode returnNode = currentGraph.add(new ReturnNode(x));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MonitorReference.java	Fri Mar 29 12:31:42 2013 +0100
@@ -0,0 +1,39 @@
+/*
+ * 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/MonitorEnterNode.java	Fri Mar 29 12:22:27 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java	Fri Mar 29 12:31:42 2013 +0100
@@ -29,15 +29,18 @@
 /**
  * The {@code MonitorEnterNode} represents the acquisition of a monitor.
  */
-public final class MonitorEnterNode extends AccessMonitorNode implements Lowerable, MonitorEnter {
+public final class MonitorEnterNode extends AccessMonitorNode implements Lowerable, MonitorEnter, MonitorReference {
+
+    private int lockDepth;
 
     /**
      * Creates a new MonitorEnterNode.
      * 
      * @param object the instruction producing the object
      */
-    public MonitorEnterNode(ValueNode object) {
+    public MonitorEnterNode(ValueNode object, int lockDepth) {
         super(object);
+        this.lockDepth = lockDepth;
     }
 
     @Override
@@ -48,4 +51,12 @@
     public void lower(LoweringTool tool) {
         tool.getRuntime().lower(this, tool);
     }
+
+    public int getLockDepth() {
+        return lockDepth;
+    }
+
+    public void setLockDepth(int lockDepth) {
+        this.lockDepth = lockDepth;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java	Fri Mar 29 12:22:27 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java	Fri Mar 29 12:31:42 2013 +0100
@@ -30,15 +30,18 @@
 /**
  * The {@code MonitorEnterNode} represents a monitor release.
  */
-public final class MonitorExitNode extends AccessMonitorNode implements Lowerable, Node.IterableNodeType, MonitorExit {
+public final class MonitorExitNode extends AccessMonitorNode implements Lowerable, Node.IterableNodeType, MonitorExit, MonitorReference {
+
+    private int lockDepth;
 
     /**
      * Creates a new MonitorExitNode.
      * 
      * @param object the instruction produces the object value
      */
-    public MonitorExitNode(ValueNode object) {
+    public MonitorExitNode(ValueNode object, int lockDepth) {
         super(object);
+        this.lockDepth = lockDepth;
     }
 
     @Override
@@ -49,4 +52,12 @@
     public void lower(LoweringTool tool) {
         tool.getRuntime().lower(this, tool);
     }
+
+    public int getLockDepth() {
+        return lockDepth;
+    }
+
+    public void setLockDepth(int lockDepth) {
+        this.lockDepth = lockDepth;
+    }
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Fri Mar 29 12:22:27 2013 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Fri Mar 29 12:31:42 2013 +0100
@@ -1095,6 +1095,7 @@
 
         FrameState outerFrameState = null;
         double invokeProbability = invoke.node().probability();
+        int callerLockDepth = stateAfter.locksSize();
         for (Node node : duplicates.values()) {
             if (GraalOptions.ProbabilityAnalysis) {
                 if (node instanceof FixedNode) {
@@ -1138,6 +1139,10 @@
                     }
                 }
             }
+            if (callerLockDepth != 0 && node instanceof MonitorReference) {
+                MonitorReference monitor = (MonitorReference) node;
+                monitor.setLockDepth(monitor.getLockDepth() + callerLockDepth);
+            }
         }
 
         Node returnValue = null;