changeset 6396:2ba1f4cdecd0

Merge.
author Lukas Stadler <lukas.stadler@jku.at>
date Thu, 13 Sep 2012 18:17:05 +0200
parents 69e94aa204b7 (current diff) d44835610b52 (diff)
children b30dde62f44c
files graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java
diffstat 25 files changed, 1184 insertions(+), 33 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FloatingReadTest.java	Thu Sep 13 18:12:54 2012 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FloatingReadTest.java	Thu Sep 13 18:17:05 2012 +0200
@@ -29,7 +29,6 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.java.*;
 
 public class FloatingReadTest extends GraphScheduleTest {
 
@@ -59,23 +58,25 @@
                 new FloatingReadPhase().apply(graph);
 
                 ReturnNode returnNode = null;
-                MonitorExitNode monitor = null;
+                MonitorExit monitorexit = null;
 
                 for (Node n : graph.getNodes()) {
                     if (n instanceof ReturnNode) {
                         returnNode = (ReturnNode) n;
-                    } else if (n instanceof MonitorExitNode) {
-                        monitor = (MonitorExitNode) n;
+                    } else if (n instanceof MonitorExit) {
+                        monitorexit = (MonitorExit) n;
                     }
                 }
 
+                Debug.dump(graph, "After lowering");
+
                 Assert.assertNotNull(returnNode);
-                Assert.assertNotNull(monitor);
+                Assert.assertNotNull(monitorexit);
                 Assert.assertTrue(returnNode.result() instanceof FloatingReadNode);
 
                 FloatingReadNode read = (FloatingReadNode) returnNode.result();
 
-                assertOrderedAfterSchedule(graph, read, monitor);
+                assertOrderedAfterSchedule(graph, read, (Node) monitorexit);
             }
         });
     }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java	Thu Sep 13 18:12:54 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java	Thu Sep 13 18:17:05 2012 +0200
@@ -268,6 +268,7 @@
     public static String HIRLowerInstanceOf = "";
     public static String HIRLowerNewInstance = "";
     public static String HIRLowerNewArray = "";
+    public static String HIRLowerMonitors = "MonitorTest";
 
     /**
      * Use XIR to lower {@link Invoke} nodes.
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Thu Sep 13 18:12:54 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Thu Sep 13 18:17:05 2012 +0200
@@ -122,9 +122,9 @@
         for (int i = numLocks - 1; i >= 0; i--) {
             assert locks != null && nextLock.inliningIdentifier == state.inliningIdentifier() && nextLock.stateDepth == i;
 
-            Value owner = toValue(nextLock.monitor.object());
-            Value lockData = nextLock.lockData;
-            boolean eliminated = nextLock.monitor.eliminated();
+            Value owner = toValue(nextLock.object);
+            StackSlot lockData = nextLock.lockData;
+            boolean eliminated = nextLock.eliminated;
             values[numLocals + numStack + nextLock.stateDepth] = new MonitorValue(owner, lockData, eliminated);
 
             nextLock = nextLock.outer;
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Thu Sep 13 18:12:54 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Thu Sep 13 18:17:05 2012 +0200
@@ -107,19 +107,25 @@
         public final int stateDepth;
 
         /**
-         * The monitor enter node, with information about the object that is locked and the elimination status.
+         * The object that is locked.
          */
-        public final MonitorEnterNode monitor;
+        public final ValueNode object;
+
+        /**
+         * Whether or not the lock is eliminated.
+         */
+        public final boolean eliminated;
 
         /**
          * Space in the stack frame needed by the VM to perform the locking.
          */
         public final StackSlot lockData;
 
-        public LockScope(LockScope outer, InliningIdentifier inliningIdentifier, MonitorEnterNode monitor, StackSlot lockData) {
+        public LockScope(LockScope outer, InliningIdentifier inliningIdentifier, ValueNode object, boolean eliminated, StackSlot lockData) {
             this.outer = outer;
             this.inliningIdentifier = inliningIdentifier;
-            this.monitor = monitor;
+            this.object = object;
+            this.eliminated = eliminated;
             this.lockData = lockData;
             if (outer != null && outer.inliningIdentifier == inliningIdentifier) {
                 this.stateDepth = outer.stateDepth + 1;
@@ -127,6 +133,23 @@
                 this.stateDepth = 0;
             }
         }
+
+        @Override
+        public String toString() {
+            InliningIdentifier identifier = inliningIdentifier;
+            StringBuilder sb = new StringBuilder().append(identifier).append(": ");
+            for (LockScope scope = this; scope != null; scope = scope.outer) {
+                if (scope.inliningIdentifier != identifier) {
+                    identifier = scope.inliningIdentifier;
+                    sb.append('\n').append(identifier).append(": ");
+                }
+                if (scope.eliminated) {
+                    sb.append('!');
+                }
+                sb.append(scope.object).append(' ');
+            }
+            return sb.toString();
+        }
     }
 
     /**
@@ -526,13 +549,30 @@
         setResult(x, operand(x.object()));
     }
 
+    public void lock(ValueNode object, boolean eliminated, StackSlot lock, InliningIdentifier inliningIdentifier) {
+        assert lastState != null : "must have state before instruction";
+        curLocks = new LockScope(curLocks, inliningIdentifier, object, eliminated, lock);
+    }
+
+    public StackSlot peekLock() {
+        assert curLocks.lockData != null;
+        return curLocks.lockData;
+    }
+
+    public void unlock(ValueNode object, boolean eliminated) {
+        if (curLocks == null || curLocks.object != object || curLocks.eliminated != eliminated) {
+            throw new BailoutException("unbalanced monitors: attempting to unlock an object that is not on top of the locking stack");
+        }
+        curLocks = curLocks.outer;
+    }
+
     @Override
     public void visitMonitorEnter(MonitorEnterNode x) {
         StackSlot lockData = frameMap.allocateStackBlock(runtime.sizeOfLockData(), false);
         if (x.eliminated()) {
             // No code is emitted for eliminated locks, but for proper debug information generation we need to
             // register the monitor and its lock data.
-            curLocks = new LockScope(curLocks, x.stateAfter().inliningIdentifier(), x, lockData);
+            lock(x.object(), true, lockData, x.stateAfter().inliningIdentifier());
             return;
         }
 
@@ -541,7 +581,7 @@
 
         LIRFrameState stateBefore = state();
         // The state before the monitor enter is used for null checks, so it must not contain the newly locked object.
-        curLocks = new LockScope(curLocks, x.stateAfter().inliningIdentifier(), x, lockData);
+        lock(x.object(), false, lockData, x.stateAfter().inliningIdentifier());
         // The state after the monitor enter is used for deoptimization, after the monitor has blocked, so it must contain the newly locked object.
         LIRFrameState stateAfter = stateFor(x.stateAfter(), -1);
 
@@ -551,20 +591,17 @@
 
     @Override
     public void visitMonitorExit(MonitorExitNode x) {
-        if (curLocks == null || curLocks.monitor.object() != x.object() || curLocks.monitor.eliminated() != x.eliminated()) {
-            throw new BailoutException("unbalanced monitors: attempting to unlock an object that is not on top of the locking stack");
-        }
         if (x.eliminated()) {
-            curLocks = curLocks.outer;
+            unlock(x.object(), true);
             return;
         }
 
-        StackSlot lockData = curLocks.lockData;
+        Value lockData = peekLock();
         XirArgument obj = toXirArgument(x.object());
         XirArgument lockAddress = lockData == null ? null : toXirArgument(emitLea(lockData));
 
         LIRFrameState stateBefore = state();
-        curLocks = curLocks.outer;
+        unlock(x.object(), false);
 
         XirSnippet snippet = xir.genMonitorExit(site(x, x.object()), obj, lockAddress);
         emitXir(snippet, x, stateBefore, true);
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/InliningUtil.java	Thu Sep 13 18:12:54 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/InliningUtil.java	Thu Sep 13 18:17:05 2012 +0200
@@ -802,7 +802,7 @@
      * @param receiverNullCheck true if a null check needs to be generated for non-static inlinings, false if no such check is required
      */
     public static void inline(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck) {
-        InliningIdentifier identifier = new InliningIdentifier(inlineGraph.method(), invoke.toString());
+        InliningIdentifier identifier = new InliningIdentifier(inlineGraph.method(), invoke);
         NodeInputList<ValueNode> parameters = invoke.callTarget().arguments();
         StructuredGraph graph = (StructuredGraph) invoke.node().graph();
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Thu Sep 13 18:12:54 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Thu Sep 13 18:17:05 2012 +0200
@@ -25,7 +25,6 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.max.asm.target.amd64.*;
 
-
 /**
  * Used to communicate configuration details, runtime offsets, etc. to graal upon compileMethod.
  */
@@ -44,6 +43,7 @@
     public boolean useFastNewObjectArray;
     public boolean useFastNewTypeArray;
     public boolean useTLAB;
+    public boolean useBiasedLocking;
 
     // offsets, ...
     public int vmPageSize;
@@ -111,6 +111,31 @@
 
     public int threadObjectOffset;
 
+    /**
+     * The value of markOopDesc::unlocked_value.
+     */
+    public int unlockedMask;
+
+    /**
+     * The value of markOopDesc::biased_lock_mask_in_place.
+     */
+    public int biasedLockMaskInPlace;
+
+    /**
+     * The value of markOopDesc::age_mask_in_place.
+     */
+    public int ageMaskInPlace;
+
+    /**
+     * The value of markOopDesc::epoch_mask_in_place.
+     */
+    public int epochMaskInPlace;
+
+    /**
+     * The value of markOopDesc::biased_lock_pattern.
+     */
+    public int biasedLockPattern;
+
     public int threadExceptionOopOffset;
     public int threadExceptionPcOffset;
     public int threadMultiNewArrayStorageOffset;
@@ -125,6 +150,8 @@
     public int graalMirrorKlassOffset;
     public int nmethodEntryOffset;
     public int methodCompiledEntryOffset;
+    public int basicLockSize;
+    public int basicLockDisplacedHeaderOffset;
 
     // methodData information
     public int methodDataOopDataOffset;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Thu Sep 13 18:12:54 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Thu Sep 13 18:17:05 2012 +0200
@@ -63,6 +63,7 @@
     private CheckCastSnippets.Templates checkcastSnippets;
     private InstanceOfSnippets.Templates instanceofSnippets;
     private NewObjectSnippets.Templates newObjectSnippets;
+    private MonitorSnippets.Templates monitorSnippets;
 
     public HotSpotRuntime(HotSpotVMConfig config, HotSpotGraalRuntime graalRuntime) {
         this.config = config;
@@ -77,12 +78,16 @@
         installer.install(SystemSnippets.class);
         installer.install(UnsafeSnippets.class);
         installer.install(ArrayCopySnippets.class);
+
         installer.install(CheckCastSnippets.class);
         installer.install(InstanceOfSnippets.class);
         installer.install(NewObjectSnippets.class);
+        installer.install(MonitorSnippets.class);
+
         checkcastSnippets = new CheckCastSnippets.Templates(this);
         instanceofSnippets = new InstanceOfSnippets.Templates(this);
         newObjectSnippets = new NewObjectSnippets.Templates(this, graalRuntime.getTarget(), config.useTLAB);
+        monitorSnippets = new MonitorSnippets.Templates(this, config.useFastLocking);
     }
 
 
@@ -195,8 +200,7 @@
 
     @Override
     public int sizeOfLockData() {
-        // TODO shouldn't be hard coded
-        return 8;
+        return config.basicLockSize;
     }
 
     @Override
@@ -422,6 +426,14 @@
             if (matches(graph, GraalOptions.HIRLowerNewArray)) {
                 newObjectSnippets.lower((NewArrayNode) n, tool);
             }
+        } else if (n instanceof MonitorEnterNode) {
+            if (matches(graph, GraalOptions.HIRLowerMonitors)) {
+                monitorSnippets.lower((MonitorEnterNode) n, tool);
+            }
+        } else if (n instanceof MonitorExitNode) {
+            if (matches(graph, GraalOptions.HIRLowerMonitors)) {
+                monitorSnippets.lower((MonitorExitNode) n, tool);
+            }
         } else if (n instanceof TLABAllocateNode) {
             newObjectSnippets.lower((TLABAllocateNode) n, tool);
         } else if (n instanceof InitializeObjectNode) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java	Thu Sep 13 18:17:05 2012 +0200
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.nodes;
+
+import com.oracle.graal.api.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.snippets.*;
+
+
+/**
+ * Intrinsic for opening a scope binding a stack-based lock with an object.
+ * A lock scope must be closed with an {@link EndLockScopeNode}.
+ * The frame state after this node denotes that the object 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 {
+
+    @Input private ValueNode object;
+    private final boolean eliminated;
+
+    public BeginLockScopeNode(ValueNode object, boolean eliminated, Kind wordKind) {
+        super(StampFactory.forWord(wordKind, true));
+        this.object = object;
+        this.eliminated = eliminated;
+    }
+
+    @Override
+    public boolean hasSideEffect() {
+        return false;
+    }
+
+    @Override
+    public void generate(LIRGenerator gen) {
+        int size = HotSpotGraalRuntime.getInstance().getConfig().basicLockSize;
+        StackSlot lock = gen.frameMap().allocateStackBlock(size, false);
+        Value result = eliminated ? new Constant(gen.target().wordKind, 0L) : gen.emitLea(lock);
+        FrameState stateAfter = stateAfter();
+        assert stateAfter != null;
+        gen.lock(object, eliminated, lock, stateAfter.inliningIdentifier());
+        gen.setResult(this, result);
+    }
+
+    @SuppressWarnings("unused")
+    @NodeIntrinsic
+    public static Word beginLockScope(Object object, @ConstantNodeParameter boolean eliminated, @ConstantNodeParameter Kind wordKind) {
+        throw new UnsupportedOperationException();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentLockNode.java	Thu Sep 13 18:17:05 2012 +0200
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.nodes;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.compiler.target.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.snippets.*;
+
+
+/**
+ * Intrinsic for getting the lock in the current {@linkplain BeginLockScopeNode lock scope}.
+ */
+public final class CurrentLockNode extends FixedWithNextNode implements LIRGenLowerable {
+
+    public CurrentLockNode(Kind wordKind) {
+        super(StampFactory.forWord(wordKind, true));
+    }
+
+    @Override
+    public void generate(LIRGenerator gen) {
+        // The register allocator cannot handle stack -> register moves so we use an LEA here
+        Value result = gen.emitMove(gen.emitLea(gen.peekLock()));
+        gen.setResult(this, result);
+    }
+
+    @SuppressWarnings("unused")
+    @NodeIntrinsic
+    public static Word currentLock(@ConstantNodeParameter Kind wordKind) {
+        throw new UnsupportedOperationException();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DirectCompareAndSwapNode.java	Thu Sep 13 18:17:05 2012 +0200
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.nodes;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.compiler.target.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.amd64.AMD64Move.CompareAndSwapOp;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.snippets.*;
+import com.oracle.max.asm.*;
+import com.oracle.max.asm.target.amd64.*;
+
+/**
+ * A special purpose store node that differs from {@link CompareAndSwapNode} in that
+ * it is not a {@link StateSplit} and it {@linkplain #compareAndSwap(Object, long, Word, Word) returns}
+ * either the expected value or the compared against value instead of a boolean.
+ */
+public class DirectCompareAndSwapNode extends FixedWithNextNode implements LIRGenLowerable, MemoryCheckpoint {
+
+    @Input private ValueNode object;
+    @Input private ValueNode offset;
+    @Input private ValueNode expectedValue;
+    @Input private ValueNode newValue;
+
+    public DirectCompareAndSwapNode(ValueNode object, ValueNode offset, ValueNode expected, ValueNode newValue) {
+        super(expected.stamp());
+        this.object = object;
+        this.offset = offset;
+        this.expectedValue = expected;
+        this.newValue = newValue;
+    }
+
+
+    @Override
+    public void generate(LIRGenerator gen) {
+        Kind kind = newValue.kind();
+        assert kind == expectedValue.kind();
+
+        Value expected = gen.loadNonConst(gen.operand(expectedValue));
+        Variable newVal = gen.load(gen.operand(newValue));
+
+        int disp = 0;
+        Address address;
+        Value index = gen.operand(this.offset);
+        if (ValueUtil.isConstant(index) && NumUtil.isInt(ValueUtil.asConstant(index).asLong() + disp)) {
+            disp += (int) ValueUtil.asConstant(index).asLong();
+            address = new Address(kind, gen.load(gen.operand(this.object)), disp);
+        } else {
+            address = new Address(kind, gen.load(gen.operand(this.object)), gen.load(index), Address.Scale.Times1, disp);
+        }
+
+        RegisterValue rax = AMD64.rax.asValue(kind);
+        gen.emitMove(expected, rax);
+        gen.append(new CompareAndSwapOp(rax, address, rax, newVal));
+
+        Variable result = gen.newVariable(kind());
+        gen.emitMove(rax, result);
+        gen.setResult(this, result);
+    }
+
+    /**
+     * Compares an expected value with the actual value in a location denoted by an object and a given offset.
+     * Iff they are same, {@code newValue} is placed into the location and the {@code expectedValue} is returned.
+     * Otherwise, the actual value is returned.
+     * All of the above is performed in one atomic hardware transaction.
+     *
+     * @param object the object containing a field to be atomically tested and updated
+     * @param offset offset from {@code object} of the field
+     * @param expectedValue if this value is currently in the field, perform the swap
+     * @param newValue the new value to put into the field
+     * @return either {@code expectedValue} or the actual value
+     */
+    @NodeIntrinsic
+    public static Word compareAndSwap(Object object, long offset, Word expectedValue, Word newValue) {
+        throw new UnsupportedOperationException();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EndLockScopeNode.java	Thu Sep 13 18:17:05 2012 +0200
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.nodes;
+
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.compiler.target.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.type.*;
+
+
+/**
+ * Intrinsic for closing a {@linkplain BeginLockScopeNode scope} binding a stack-based lock with an object.
+ */
+public final class EndLockScopeNode extends AbstractStateSplit implements LIRGenLowerable, MonitorExit {
+
+    @Input private ValueNode object;
+    private final boolean eliminated;
+
+    public EndLockScopeNode(ValueNode object, boolean eliminated) {
+        super(StampFactory.forVoid());
+        this.object = object;
+        this.eliminated = eliminated;
+    }
+
+    @Override
+    public boolean hasSideEffect() {
+        return false;
+    }
+
+    @Override
+    public void generate(LIRGenerator gen) {
+        gen.unlock(object, eliminated);
+    }
+
+    @SuppressWarnings("unused")
+    @NodeIntrinsic
+    public static void endLockScope(Object object, @ConstantNodeParameter boolean eliminated) {
+        throw new UnsupportedOperationException();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorEnterStubCall.java	Thu Sep 13 18:17:05 2012 +0200
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.nodes;
+
+import static com.oracle.graal.hotspot.target.amd64.AMD64MonitorEnterStubCallOp.*;
+
+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.target.amd64.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.snippets.*;
+
+/**
+ * Node implementing a call to HotSpot's {@code graal_monitorenter} stub.
+ *
+ * @see AMD64MonitorEnterStubCallOp
+ */
+public class MonitorEnterStubCall extends FixedWithNextNode implements LIRGenLowerable {
+
+    @Input private final ValueNode object;
+    @Input private final ValueNode lock;
+
+    public MonitorEnterStubCall(ValueNode object, ValueNode lock) {
+        super(StampFactory.forVoid());
+        this.object = object;
+        this.lock = lock;
+    }
+
+    @Override
+    public void generate(LIRGenerator gen) {
+        RegisterValue objectFixed = OBJECT.asValue(Kind.Object);
+        RegisterValue lockFixed = LOCK.asValue(gen.target().wordKind);
+        gen.emitMove(gen.operand(lock), lockFixed);
+        gen.emitMove(gen.operand(object), objectFixed);
+        gen.append(new AMD64MonitorEnterStubCallOp(objectFixed, lockFixed, gen.state()));
+    }
+
+    @SuppressWarnings("unused")
+    @NodeIntrinsic
+    public static void call(Object hub, Word lock) {
+        throw new UnsupportedOperationException();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorExitStubCall.java	Thu Sep 13 18:17:05 2012 +0200
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.nodes;
+
+import static com.oracle.graal.hotspot.target.amd64.AMD64MonitorEnterStubCallOp.*;
+
+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.target.amd64.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.type.*;
+
+/**
+ * Node implementing a call to HotSpot's {@code graal_monitorexit} stub.
+ *
+ * @see AMD64MonitorExitStubCallOp
+ */
+public class MonitorExitStubCall extends FixedWithNextNode implements LIRGenLowerable {
+
+    @Input private final ValueNode object;
+
+    public MonitorExitStubCall(ValueNode object) {
+        super(StampFactory.forVoid());
+        this.object = object;
+    }
+
+    @Override
+    public void generate(LIRGenerator gen) {
+        RegisterValue objectFixed = OBJECT.asValue(Kind.Object);
+        RegisterValue lockFixed = LOCK.asValue(gen.target().wordKind);
+        // The register allocator cannot handle stack -> register moves so we use an LEA here
+        gen.emitMove(gen.emitLea(gen.peekLock()), lockFixed);
+        gen.emitMove(gen.operand(object), objectFixed);
+        gen.append(new AMD64MonitorExitStubCallOp(objectFixed, lockFixed, gen.state()));
+    }
+
+    @SuppressWarnings("unused")
+    @NodeIntrinsic
+    public static void call(Object hub) {
+        throw new UnsupportedOperationException();
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/HotSpotSnippetUtils.java	Thu Sep 13 18:12:54 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/HotSpotSnippetUtils.java	Thu Sep 13 18:17:05 2012 +0200
@@ -92,6 +92,31 @@
     }
 
     @Fold
+    static int unlockedMask() {
+        return HotSpotGraalRuntime.getInstance().getConfig().unlockedMask;
+    }
+
+    @Fold
+    static int biasedLockMaskInPlace() {
+        return HotSpotGraalRuntime.getInstance().getConfig().biasedLockMaskInPlace;
+    }
+
+    @Fold
+    static int epochMaskInPlace() {
+        return HotSpotGraalRuntime.getInstance().getConfig().epochMaskInPlace;
+    }
+
+    @Fold
+    static int biasedLockPattern() {
+        return HotSpotGraalRuntime.getInstance().getConfig().biasedLockPattern;
+    }
+
+    @Fold
+    static int ageMaskInPlace() {
+        return HotSpotGraalRuntime.getInstance().getConfig().ageMaskInPlace;
+    }
+
+    @Fold
     static int hubOffset() {
         return HotSpotGraalRuntime.getInstance().getConfig().hubOffset;
     }
@@ -136,6 +161,16 @@
         return HotSpotGraalRuntime.getInstance().getConfig().secondarySupersOffset;
     }
 
+    @Fold
+    static int lockDisplacedMarkOffset() {
+        return HotSpotGraalRuntime.getInstance().getConfig().basicLockDisplacedHeaderOffset;
+    }
+
+    @Fold
+    static boolean useBiasedLocking() {
+        return HotSpotGraalRuntime.getInstance().getConfig().useBiasedLocking;
+    }
+
     /**
      * Loads the hub from a object, null checking it first.
      */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/MonitorSnippets.java	Thu Sep 13 18:17:05 2012 +0200
@@ -0,0 +1,350 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.snippets;
+
+import static com.oracle.graal.hotspot.nodes.BeginLockScopeNode.*;
+import static com.oracle.graal.hotspot.nodes.DirectCompareAndSwapNode.*;
+import static com.oracle.graal.hotspot.nodes.EndLockScopeNode.*;
+import static com.oracle.graal.hotspot.nodes.RegisterNode.*;
+import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*;
+import static com.oracle.graal.nodes.extended.UnsafeLoadNode.*;
+import static com.oracle.graal.snippets.SnippetTemplate.Arguments.*;
+import static com.oracle.graal.snippets.nodes.DirectObjectStoreNode.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.snippets.*;
+import com.oracle.graal.snippets.Snippet.*;
+import com.oracle.graal.snippets.SnippetTemplate.AbstractTemplates;
+import com.oracle.graal.snippets.SnippetTemplate.Arguments;
+import com.oracle.graal.snippets.SnippetTemplate.Key;
+
+/**
+ * Snippets used for implementing the monitorenter and monitorexit instructions.
+ *
+ * The locking algorithm used is described in the paper <a href="http://dl.acm.org/citation.cfm?id=1167515.1167496">
+ * Eliminating synchronization-related atomic operations with biased locking and bulk rebiasing</a>
+ * by Kenneth Russell and David Detlefs.
+ */
+public class MonitorSnippets implements SnippetsInterface {
+
+    private static final boolean LOG = Boolean.getBoolean("graal.monitorsnippets.log");
+
+    private static void log(String action, Object object) {
+        if (LOG) {
+            Log.print(action);
+            Log.print(' ');
+            Log.printlnAddress(object);
+        }
+    }
+
+    @Snippet
+    public static void monitorenter(@Parameter("object") Object object) {
+        verifyOop(object);
+
+        // Load the mark word - this includes a null-check on object
+        final Word mark = asWord(loadObject(object, 0, markOffset(), false));
+
+        final Word lock = beginLockScope(object, false, wordKind());
+
+        if (useBiasedLocking()) {
+            // See whether the lock is currently biased toward our thread and
+            // whether the epoch is still valid.
+            // Note that the runtime guarantees sufficient alignment of JavaThread
+            // pointers to allow age to be placed into low bits.
+            final Word biasedLockMark = mark.and(biasedLockMaskInPlace());
+
+            // First check to see whether biasing is enabled for this object
+            if (biasedLockMark.toLong() != biasedLockPattern()) {
+                // Biasing not enabled -> fall through to lightweight locking
+            } else {
+                // The bias pattern is present in the object's mark word. Need to check
+                // whether the bias owner and the epoch are both still current.
+                Object hub = loadHub(object);
+                final Word prototypeMarkWord = asWord(loadObject(hub, 0, prototypeMarkWordOffset(), true));
+                final Word thread = asWord(register(threadReg(), wordKind()));
+                final Word tmp = prototypeMarkWord.or(thread).xor(mark).and(~ageMaskInPlace());
+                if (tmp == Word.zero()) {
+                    // Object is already biased to current thread -> done
+                    log("+lock{bias}", object);
+                    return;
+                }
+
+                // At this point we know that the mark word has the bias pattern and
+                // that we are not the bias owner in the current epoch. We need to
+                // figure out more details about the state of the mark word in order to
+                // know what operations can be legally performed on the object's
+                // mark word.
+                if (tmp.and(biasedLockMaskInPlace()) == Word.zero()) {
+                    // Biasing is still enabled for object's type. See whether the
+                    // epoch of the current bias is still valid, meaning that the epoch
+                    // bits of the mark word are equal to the epoch bits of the
+                    // prototype mark word. (Note that the prototype mark word's epoch bits
+                    // only change at a safepoint.) If not, attempt to rebias the object
+                    // toward the current thread. Note that we must be absolutely sure
+                    // that the current epoch is invalid in order to do this because
+                    // otherwise the manipulations it performs on the mark word are
+                    // illegal.
+                    if (tmp.and(epochMaskInPlace()) != Word.zero()) {
+                        // The epoch of the current bias is still valid but we know nothing
+                        // about the owner; it might be set or it might be clear. Try to
+                        // acquire the bias of the object using an atomic operation. If this
+                        // fails we will go in to the runtime to revoke the object's bias.
+                        // Note that we first construct the presumed unbiased header so we
+                        // don't accidentally blow away another thread's valid bias.
+                        Word unbiasedMark = mark.and(biasedLockMaskInPlace() | ageMaskInPlace() | epochMaskInPlace());
+                        Word biasedMark = unbiasedMark.or(thread);
+                        if (compareAndSwap(object, markOffset(), unbiasedMark, biasedMark) == unbiasedMark) {
+                            // Object is now biased to current thread -> done
+                            log("+lock{bias}", object);
+                            return;
+                        }
+                        // If the biasing toward our thread failed, this means that
+                        // another thread succeeded in biasing it toward itself and we
+                        // need to revoke that bias. The revocation will occur in the
+                        // interpreter runtime in the slow case.
+                        log("+lock{stub}", object);
+                        MonitorEnterStubCall.call(object, lock);
+                        return;
+                    } else {
+                        // At this point we know the epoch has expired, meaning that the
+                        // current "bias owner", if any, is actually invalid. Under these
+                        // circumstances _only_, we are allowed to use the current mark word
+                        // value as the comparison value when doing the CAS to acquire the
+                        // bias in the current epoch. In other words, we allow transfer of
+                        // the bias from one thread to another directly in this situation.
+                        Word biasedMark = prototypeMarkWord.or(thread);
+                        if (compareAndSwap(object, markOffset(), mark, biasedMark) == mark) {
+                            // Object is now biased to current thread -> done
+                            log("+lock{bias}", object);
+                            return;
+                        }
+                        // If the biasing toward our thread failed, then another thread
+                        // succeeded in biasing it toward itself and we need to revoke that
+                        // bias. The revocation will occur in the runtime in the slow case.
+                        log("+lock{stub}", object);
+                        MonitorEnterStubCall.call(object, lock);
+                        return;
+                    }
+                } else {
+                    // The prototype mark word doesn't have the bias bit set any
+                    // more, indicating that objects of this data type are not supposed
+                    // to be biased any more. We are going to try to reset the mark of
+                    // this object to the prototype value and fall through to the
+                    // CAS-based locking scheme. Note that if our CAS fails, it means
+                    // that another thread raced us for the privilege of revoking the
+                    // bias of this particular object, so it's okay to continue in the
+                    // normal locking code.
+                    compareAndSwap(object, markOffset(), mark, tmp);
+
+                    // Fall through to the normal CAS-based lock, because no matter what
+                    // the result of the above CAS, some thread must have succeeded in
+                    // removing the bias bit from the object's header.
+                }
+            }
+        }
+
+        // Create the unlocked mark word pattern
+        Word unlockedMark = mark.or(unlockedMask());
+
+        // Copy this unlocked mark word into the lock slot on the stack
+        storeWord(lock, lockDisplacedMarkOffset(), 0, unlockedMark);
+
+        // Test if the object's mark word is unlocked, and if so, store the
+        // (address of) the lock slot into the object's mark word.
+        Word currentMark = compareAndSwap(object, markOffset(), unlockedMark, lock);
+        if (currentMark != unlockedMark) {
+            // The mark word in the object header was not the same.
+            // Either the object is locked by another thread or is already locked
+            // by the current thread. The latter is true if the mark word
+            // is a stack pointer into the current thread's stack, i.e.:
+            //
+            //   1) (currentMark & aligned_mask) == 0
+            //   2)  rsp <= currentMark
+            //   3)  currentMark <= rsp + page_size
+            //
+            // These 3 tests can be done by evaluating the following expression:
+            //
+            //   (currentMark - rsp) & (aligned_mask - page_size)
+            //
+            // assuming both the stack pointer and page_size have their least
+            // significant 2 bits cleared and page_size is a power of 2
+            final Word alignedMask = Word.fromInt(wordSize() - 1);
+            final Word stackPointer = asWord(register(stackPointerReg(), wordKind()));
+            if (currentMark.minus(stackPointer).and(alignedMask.minus(pageSize())) != Word.zero()) {
+                // Most likely not a recursive lock, go into a slow runtime call
+                log("+lock{stub}", object);
+                MonitorEnterStubCall.call(object, lock);
+                return;
+            } else {
+                // Recursively locked => write 0 to the lock slot
+                storeWord(lock, lockDisplacedMarkOffset(), 0, Word.zero());
+                log("+lock{recursive}", object);
+            }
+        } else {
+            log("+lock{cas}", object);
+        }
+    }
+
+    @Snippet
+    public static void monitorenterEliminated(@Parameter("object") Object object) {
+        beginLockScope(object, true, wordKind());
+    }
+
+    /**
+     * Calls straight out to the monitorenter stub.
+     */
+    @Snippet
+    public static void monitorenterStub(@Parameter("object") Object object, @ConstantParameter("checkNull") boolean checkNull) {
+        verifyOop(object);
+        if (checkNull && object == null) {
+            DeoptimizeNode.deopt(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.NullCheckException);
+        }
+        // BeginLockScope nodes do not read from object so a use of object
+        // cannot float about the null check above
+        final Word lock = beginLockScope(object, false, wordKind());
+        log("+lock{stub}", object);
+        MonitorEnterStubCall.call(object, lock);
+    }
+
+    @Snippet
+    public static void monitorexit(@Parameter("object") Object object) {
+        if (useBiasedLocking()) {
+            // Check for biased locking unlock case, which is a no-op
+            // Note: we do not have to check the thread ID for two reasons.
+            // First, the interpreter checks for IllegalMonitorStateException at
+            // a higher level. Second, if the bias was revoked while we held the
+            // lock, the object could not be rebiased toward another thread, so
+            // the bias bit would be clear.
+            final Word mark = asWord(loadObject(object, 0, markOffset(), true));
+            if (mark.and(biasedLockMaskInPlace()).toLong() == biasedLockPattern()) {
+                endLockScope(object, false);
+                log("-lock{bias}", object);
+                return;
+            }
+        }
+
+        final Word lock = CurrentLockNode.currentLock(wordKind());
+
+        // Load displaced mark
+        final Word displacedMark = loadWord(lock, lockDisplacedMarkOffset());
+
+        if (displacedMark == Word.zero()) {
+            // Recursive locking => done
+            log("-lock{recursive}", object);
+        } else {
+            verifyOop(object);
+            // Test if object's mark word is pointing to the displaced mark word, and if so, restore
+            // the displaced mark in the object - if the object's mark word is not pointing to
+            // the displaced mark word, get the object mark word instead
+            if (DirectCompareAndSwapNode.compareAndSwap(object, markOffset(), lock, displacedMark) != lock) {
+              // The object's mark word was not pointing to the displaced header,
+              // we do unlocking via runtime call
+                log("-lock{stub}", object);
+                MonitorExitStubCall.call(object);
+            } else {
+                log("-lock{cas}", object);
+            }
+        }
+        endLockScope(object, false);
+    }
+
+    /**
+     * Calls straight out to the monitorexit stub.
+     */
+    @Snippet
+    public static void monitorexitStub(@Parameter("object") Object object) {
+        verifyOop(object);
+        log("-lock{stub}", object);
+        MonitorExitStubCall.call(object);
+        endLockScope(object, false);
+    }
+
+    @Snippet
+    public static void monitorexitEliminated(@Parameter("object") Object object) {
+        endLockScope(object, true);
+    }
+
+    public static class Templates extends AbstractTemplates<MonitorSnippets> {
+
+        private final ResolvedJavaMethod monitorenter;
+        private final ResolvedJavaMethod monitorexit;
+        private final ResolvedJavaMethod monitorenterStub;
+        private final ResolvedJavaMethod monitorexitStub;
+        private final ResolvedJavaMethod monitorenterEliminated;
+        private final ResolvedJavaMethod monitorexitEliminated;
+        private final boolean useFastLocking;
+
+        public Templates(CodeCacheProvider runtime, boolean useFastLocking) {
+            super(runtime, MonitorSnippets.class);
+            monitorenter = snippet("monitorenter", Object.class);
+            monitorexit = snippet("monitorexit", Object.class);
+            monitorenterStub = snippet("monitorenterStub", Object.class, boolean.class);
+            monitorexitStub = snippet("monitorexitStub", Object.class);
+            monitorenterEliminated = snippet("monitorenterEliminated", Object.class);
+            monitorexitEliminated = snippet("monitorexitEliminated", Object.class);
+            this.useFastLocking = useFastLocking;
+        }
+
+        public void lower(MonitorEnterNode monitorenterNode, @SuppressWarnings("unused") LoweringTool tool) {
+            FrameState stateAfter = monitorenterNode.stateAfter();
+            ResolvedJavaMethod method = monitorenterNode.eliminated() ? monitorenterEliminated : useFastLocking ? monitorenter : monitorenterStub;
+            boolean checkNull = !monitorenterNode.object().stamp().nonNull();
+            Key key = new Key(method);
+            if (method == monitorenterStub) {
+                key.add("checkNull", checkNull);
+            }
+            Arguments arguments = arguments("object", monitorenterNode.object());
+            SnippetTemplate template = cache.get(key);
+            Map<Node, Node> nodes = template.instantiate(runtime, monitorenterNode, arguments);
+            for (Node n : nodes.values()) {
+                if (n instanceof BeginLockScopeNode) {
+                    BeginLockScopeNode begin = (BeginLockScopeNode) n;
+                    begin.setStateAfter(stateAfter);
+                }
+            }
+        }
+
+        public void lower(MonitorExitNode monitorexitNode, @SuppressWarnings("unused") LoweringTool tool) {
+            FrameState stateAfter = monitorexitNode.stateAfter();
+            ResolvedJavaMethod method = monitorexitNode.eliminated() ? monitorexitEliminated : useFastLocking ? monitorexit : monitorexitStub;
+            Key key = new Key(method);
+            Arguments arguments = arguments("object", monitorexitNode.object());
+            SnippetTemplate template = cache.get(key);
+            Map<Node, Node> nodes = template.instantiate(runtime, monitorexitNode, arguments);
+            for (Node n : nodes.values()) {
+                if (n instanceof EndLockScopeNode) {
+                    EndLockScopeNode end = (EndLockScopeNode) n;
+                    end.setStateAfter(stateAfter);
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/amd64/AMD64MonitorEnterStubCallOp.java	Thu Sep 13 18:17:05 2012 +0200
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.target.amd64;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.LIRInstruction.Opcode;
+import com.oracle.graal.lir.amd64.*;
+import com.oracle.graal.lir.asm.*;
+import com.oracle.max.asm.target.amd64.*;
+
+/**
+ * LIR instruction for calling HotSpot's {@code graal_monitorenter} stub.
+ */
+@Opcode("MONITORENTER_STUB")
+public class AMD64MonitorEnterStubCallOp extends AMD64LIRInstruction {
+
+    /**
+     * The stub expects the object in the first stub ABI register.
+     */
+    public static final Register OBJECT = getStubParameterRegister(0);
+
+    /**
+     * The stub expects the lock in the second stub ABI register.
+     */
+    public static final Register LOCK = getStubParameterRegister(1);
+
+    /**
+     * The stub uses RAX, RBX and the first two ABI parameter registers.
+     */
+    public static final Register[] TEMPS = {AMD64.rax, AMD64.rbx};
+
+    @Use protected Value object;
+    @Use protected Value lock;
+    @Temp protected Value[] temps;
+
+    @State protected LIRFrameState state;
+
+    public AMD64MonitorEnterStubCallOp(Value object, Value lock, LIRFrameState state) {
+        this.object = object;
+        this.lock = lock;
+        this.temps = new Value[TEMPS.length];
+        for (int i = 0; i < temps.length; i++) {
+            temps[i] = TEMPS[i].asValue(Kind.Long);
+        }
+        this.state = state;
+    }
+
+    @Override
+    public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
+        HotSpotVMConfig config = HotSpotGraalRuntime.getInstance().getConfig();
+        long stub = config.fastMonitorEnterStub;
+        AMD64Call.directCall(tasm, masm, stub, state);
+    }
+
+    @Override
+    protected void verify() {
+        super.verify();
+        assert asRegister(object) == OBJECT : "stub expects object in " + OBJECT;
+        assert asRegister(lock) == LOCK : "stub expect lock in " + LOCK;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/amd64/AMD64MonitorExitStubCallOp.java	Thu Sep 13 18:17:05 2012 +0200
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.target.amd64;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.LIRInstruction.Opcode;
+import com.oracle.graal.lir.amd64.*;
+import com.oracle.graal.lir.asm.*;
+import com.oracle.max.asm.target.amd64.*;
+
+/**
+ * LIR instruction for calling HotSpot's {@code graal_monitorexit} stub.
+ */
+@Opcode("MONITOREXIT_STUB")
+public class AMD64MonitorExitStubCallOp extends AMD64LIRInstruction {
+
+    /**
+     * The stub expects the object in the first stub ABI register.
+     */
+    public static final Register OBJECT = getStubParameterRegister(0);
+
+    /**
+     * The stub expects the lock in the second stub ABI register.
+     */
+    public static final Register LOCK = getStubParameterRegister(1);
+
+    /**
+     * The stub uses RAX, RBX and the first two ABI parameter registers.
+     */
+    public static final Register[] TEMPS = {AMD64.rax, AMD64.rbx};
+
+    @Use protected Value object;
+    @Use protected Value lock;
+    @Temp protected Value[] temps;
+
+    @State protected LIRFrameState state;
+
+    public AMD64MonitorExitStubCallOp(Value object, Value lock, LIRFrameState state) {
+        this.object = object;
+        this.lock = lock;
+        this.temps = new Value[TEMPS.length];
+        for (int i = 0; i < temps.length; i++) {
+            temps[i] = TEMPS[i].asValue(Kind.Long);
+        }
+        this.state = state;
+    }
+
+    @Override
+    public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
+        HotSpotVMConfig config = HotSpotGraalRuntime.getInstance().getConfig();
+        long stub = config.fastMonitorExitStub;
+        AMD64Call.directCall(tasm, masm, stub, state);
+    }
+
+    @Override
+    protected void verify() {
+        super.verify();
+        assert asRegister(object) == OBJECT : "stub expects object in " + OBJECT;
+        assert asRegister(lock) == LOCK : "stub expect lock in " + LOCK;
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Thu Sep 13 18:12:54 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Thu Sep 13 18:17:05 2012 +0200
@@ -44,16 +44,20 @@
      */
     public static final class InliningIdentifier {
         private final ResolvedJavaMethod method;
-        private final String context;
+        private final Object context;
 
-        public InliningIdentifier(ResolvedJavaMethod method, String context) {
+        public InliningIdentifier(ResolvedJavaMethod method, Object context) {
             this.method = method;
             this.context = context;
         }
 
         @Override
         public String toString() {
-            return method + "@" + context;
+            try {
+                return method + "@" + context;
+            } catch (Exception e) {
+                return super.toString();
+            }
         }
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MonitorEnter.java	Thu Sep 13 18:17:05 2012 +0200
@@ -0,0 +1,31 @@
+/*
+ * 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 monitor locking transition.
+ */
+public interface MonitorEnter extends MemoryCheckpoint {
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MonitorExit.java	Thu Sep 13 18:17:05 2012 +0200
@@ -0,0 +1,31 @@
+/*
+ * 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 monitor unlocking transition.
+ */
+public interface MonitorExit extends MemoryCheckpoint {
+
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java	Thu Sep 13 18:12:54 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java	Thu Sep 13 18:17:05 2012 +0200
@@ -23,12 +23,13 @@
 package com.oracle.graal.nodes.java;
 
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 
 /**
  * The {@code MonitorEnterNode} represents the acquisition of a monitor.
  */
-public final class MonitorEnterNode extends AccessMonitorNode implements LIRLowerable {
+public final class MonitorEnterNode extends AccessMonitorNode implements LIRLowerable, Lowerable, MonitorEnter {
 
     /**
      * Creates a new MonitorEnterNode.
@@ -39,8 +40,11 @@
         super(object);
     }
 
-    @Override
     public void generate(LIRGeneratorTool gen) {
         gen.visitMonitorEnter(this);
     }
+
+    public void lower(LoweringTool tool) {
+        tool.getRuntime().lower(this, tool);
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java	Thu Sep 13 18:12:54 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java	Thu Sep 13 18:17:05 2012 +0200
@@ -23,13 +23,14 @@
 package com.oracle.graal.nodes.java;
 
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.graph.*;
 
 /**
  * The {@code MonitorEnterNode} represents a monitor release.
  */
-public final class MonitorExitNode extends AccessMonitorNode implements LIRLowerable, Node.IterableNodeType {
+public final class MonitorExitNode extends AccessMonitorNode implements Lowerable, LIRLowerable, Node.IterableNodeType, MonitorExit {
 
     /**
      * Creates a new MonitorExitNode.
@@ -44,4 +45,8 @@
     public void generate(LIRGeneratorTool gen) {
         gen.visitMonitorExit(this);
     }
+
+    public void lower(LoweringTool tool) {
+        tool.getRuntime().lower(this, tool);
+    }
 }
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java	Thu Sep 13 18:12:54 2012 +0200
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java	Thu Sep 13 18:17:05 2012 +0200
@@ -493,8 +493,9 @@
      * @param runtime
      * @param replacee the node that will be replaced
      * @param args the arguments to be bound to the flattened positional parameters of the snippet
+     * @return the map of duplicated nodes (original -> duplicate)
      */
-    public void instantiate(CodeCacheProvider runtime,
+    public Map<Node, Node> instantiate(CodeCacheProvider runtime,
                     FixedWithNextNode replacee, SnippetTemplate.Arguments args) {
 
         // Inline the snippet nodes, replacing parameters with the given args in the process
@@ -535,6 +536,7 @@
             GraphUtil.killCFG(replacee);
 
         Debug.dump(replaceeGraph, "After lowering %s with %s", replacee, this);
+        return duplicates;
     }
 
     /**
--- a/src/share/vm/c1/c1_Runtime1.cpp	Thu Sep 13 18:12:54 2012 +0200
+++ b/src/share/vm/c1/c1_Runtime1.cpp	Thu Sep 13 18:17:05 2012 +0200
@@ -687,7 +687,9 @@
   NOT_PRODUCT(_monitorenter_slowcase_cnt++;)
 #ifdef ASSERT
   if (TraceGraal >= 3) {
-    tty->print_cr("entered locking slow case with obj=" INTPTR_FORMAT " and lock= " INTPTR_FORMAT, obj, lock);
+    markOop mark = obj->mark();
+    markOop dmw = mark->has_displaced_mark_helper() ? mark->displaced_mark_helper() : (markOop) (int*) 0xFFFFFFFF;
+    tty->print_cr("entered locking slow case with obj=" INTPTR_FORMAT ", mark=" INTPTR_FORMAT ", dmw=" INTPTR_FORMAT " and lock= " INTPTR_FORMAT, obj, mark, dmw , lock);
   }
   if (PrintBiasedLockingStatistics) {
     Atomic::inc(BiasedLocking::slow_path_entry_count_addr());
@@ -741,6 +743,11 @@
   } else {
     ObjectSynchronizer::fast_exit(obj, lock, THREAD);
   }
+#ifdef ASSERT
+  if (TraceGraal >= 3) {
+    tty->print_cr("exited locking slow case with obj=" INTPTR_FORMAT ", mark=" INTPTR_FORMAT " and lock= " INTPTR_FORMAT, obj, obj->mark(), lock);
+  }
+#endif
 JRT_END
 
 JRT_ENTRY(void, Runtime1::graal_log_object(JavaThread* thread, oop obj, jboolean newline, jboolean string))
--- a/src/share/vm/graal/graalCompilerToVM.cpp	Thu Sep 13 18:12:54 2012 +0200
+++ b/src/share/vm/graal/graalCompilerToVM.cpp	Thu Sep 13 18:17:05 2012 +0200
@@ -658,6 +658,7 @@
   set_boolean(env, config, "verifyOops", VerifyOops);
   set_boolean(env, config, "useFastLocking", UseFastLocking);
   set_boolean(env, config, "useFastNewObjectArray", UseFastNewObjectArray);
+  set_boolean(env, config, "useBiasedLocking", UseBiasedLocking);
   set_boolean(env, config, "useFastNewTypeArray", UseFastNewTypeArray);
   set_boolean(env, config, "useTLAB", UseTLAB);
   set_int(env, config, "codeEntryAlignment", CodeEntryAlignment);
@@ -675,6 +676,11 @@
   set_int(env, config, "threadTlabTopOffset", in_bytes(JavaThread::tlab_top_offset()));
   set_int(env, config, "threadTlabEndOffset", in_bytes(JavaThread::tlab_end_offset()));
   set_int(env, config, "threadObjectOffset", in_bytes(JavaThread::threadObj_offset()));
+  set_int(env, config, "unlockedMask", (int) markOopDesc::unlocked_value);
+  set_int(env, config, "biasedLockMaskInPlace", (int) markOopDesc::biased_lock_mask_in_place);
+  set_int(env, config, "ageMaskInPlace", (int) markOopDesc::age_mask_in_place);
+  set_int(env, config, "epochMaskInPlace", (int) markOopDesc::epoch_mask_in_place);
+  set_int(env, config, "biasedLockPattern", (int) markOopDesc::biased_lock_pattern);
   set_int(env, config, "threadExceptionOopOffset", in_bytes(JavaThread::exception_oop_offset()));
   set_int(env, config, "threadExceptionPcOffset", in_bytes(JavaThread::exception_pc_offset()));
   set_int(env, config, "threadMultiNewArrayStorageOffset", in_bytes(JavaThread::graal_multinewarray_storage_offset()));
@@ -687,6 +693,8 @@
   set_int(env, config, "graalMirrorKlassOffset", in_bytes(Klass::graal_mirror_offset()));
   set_int(env, config, "nmethodEntryOffset", nmethod::verified_entry_point_offset());
   set_int(env, config, "methodCompiledEntryOffset", in_bytes(methodOopDesc::from_compiled_offset()));
+  set_int(env, config, "basicLockSize", sizeof(BasicLock));
+  set_int(env, config, "basicLockDisplacedHeaderOffset", BasicLock::displaced_header_offset_in_bytes());
   
   set_int(env, config, "methodDataOopDataOffset", in_bytes(methodDataOopDesc::data_offset()));
   set_int(env, config, "methodDataOopTrapHistoryOffset", in_bytes(methodDataOopDesc::trap_history_offset()));