Mercurial > hg > graal-compiler
changeset 6387:d44835610b52
Merge.
author | Doug Simon <doug.simon@oracle.com> |
---|---|
date | Thu, 13 Sep 2012 17:45:04 +0200 |
parents | abeeb57b655d (diff) c61ce6bac1df (current diff) |
children | 6b74f44c5059 2ba1f4cdecd0 |
files | graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java src/share/vm/graal/graalCompilerToVM.cpp |
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 12:59:27 2012 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FloatingReadTest.java Thu Sep 13 17:45:04 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 12:59:27 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java Thu Sep 13 17:45:04 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 12:59:27 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java Thu Sep 13 17:45:04 2012 +0200 @@ -120,9 +120,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 12:59:27 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Thu Sep 13 17:45:04 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 12:59:27 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/InliningUtil.java Thu Sep 13 17:45:04 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 12:59:27 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Thu Sep 13 17:45:04 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 12:59:27 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Thu Sep 13 17:45:04 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:45:04 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:45:04 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:45:04 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:45:04 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:45:04 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:45:04 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 12:59:27 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/HotSpotSnippetUtils.java Thu Sep 13 17:45:04 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:45:04 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:45:04 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:45:04 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 12:59:27 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java Thu Sep 13 17:45:04 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 17:45:04 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:45:04 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 12:59:27 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java Thu Sep 13 17:45:04 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 12:59:27 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java Thu Sep 13 17:45:04 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 12:59:27 2012 +0200 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java Thu Sep 13 17:45:04 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 12:59:27 2012 +0200 +++ b/src/share/vm/c1/c1_Runtime1.cpp Thu Sep 13 17:45:04 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 12:59:27 2012 +0200 +++ b/src/share/vm/graal/graalCompilerToVM.cpp Thu Sep 13 17:45:04 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()));