changeset 6386:abeeb57b655d

added MonitorSnippets which passes MonitorTest but is not yet enabled for general lowering
author Doug Simon <doug.simon@oracle.com>
date Thu, 13 Sep 2012 17:43:18 +0200
parents 077fd901d7c7
children d44835610b52
files graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FloatingReadTest.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.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/DirectCompareAndSwapNode.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/MonitorEnterStubCall.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorExitStubCall.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/HotSpotSnippetUtils.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/MonitorSnippets.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/amd64/AMD64MonitorEnterStubCallOp.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/amd64/AMD64MonitorExitStubCallOp.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MonitorEnter.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MonitorExit.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.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java src/share/vm/graal/graalCompilerToVM.cpp
diffstat 20 files changed, 1116 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FloatingReadTest.java	Thu Sep 13 17:35:43 2012 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FloatingReadTest.java	Thu Sep 13 17:43:18 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 17:35:43 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java	Thu Sep 13 17:43:18 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.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Thu Sep 13 17:35:43 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Thu Sep 13 17:43:18 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 17:35:43 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Thu Sep 13 17:43:18 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 17:43:18 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 17:43:18 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 17:43:18 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 17:43:18 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 17:43:18 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 17:43:18 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 17:35:43 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/HotSpotSnippetUtils.java	Thu Sep 13 17:43:18 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 17:43:18 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 17:43:18 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 17:43:18 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;
+    }
+}
--- /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 17:43:18 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 17:43:18 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 17:35:43 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java	Thu Sep 13 17:43:18 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 17:35:43 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java	Thu Sep 13 17:43:18 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 17:35:43 2012 +0200
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java	Thu Sep 13 17:43:18 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/graal/graalCompilerToVM.cpp	Thu Sep 13 17:35:43 2012 +0200
+++ b/src/share/vm/graal/graalCompilerToVM.cpp	Thu Sep 13 17:43:18 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()));