From: <pi...@us...> - 2009-02-15 01:23:41
|
Revision: 15443 http://jikesrvm.svn.sourceforge.net/jikesrvm/?rev=15443&view=rev Author: pizlo Date: 2009-02-15 01:23:37 +0000 (Sun, 15 Feb 2009) Log Message: ----------- adding some forgotten files Added Paths: ----------- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/LockConfigs.java rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/Locking.java rvmroot/branches/RVM-791/working-15440/rvm/src-generated/vm-configuration/LockConfig.template Added: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/LockConfigs.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/LockConfigs.java (rev 0) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/LockConfigs.java 2009-02-15 01:23:37 UTC (rev 15443) @@ -0,0 +1,20 @@ +/* + * This file is part of the Jikes RVM project (http://jikesrvm.org). + * + * This file is licensed to You under the Common Public License (CPL); + * You may not use this file except in compliance with the License. You + * may obtain a copy of the License at + * + * http://www.opensource.org/licenses/cpl1.0.php + * + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. + */ +package org.jikesrvm.scheduler; + +public class LockConfigs { + public static final int ThinEagerDeflate = 1; +} + + + Added: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/Locking.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/Locking.java (rev 0) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/Locking.java 2009-02-15 01:23:37 UTC (rev 15443) @@ -0,0 +1,158 @@ +/* + * This file is part of the Jikes RVM project (http://jikesrvm.org). + * + * This file is licensed to You under the Common Public License (CPL); + * You may not use this file except in compliance with the License. You + * may obtain a copy of the License at + * + * http://www.opensource.org/licenses/cpl1.0.php + * + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. + */ +package org.jikesrvm.scheduler; + +import org.jikesrvm.VM; +import org.jikesrvm.Services; +import org.jikesrvm.classloader.RVMMethod; +import org.jikesrvm.compilers.common.CompiledMethods; +import org.jikesrvm.objectmodel.ThinLockConstants; +import org.jikesrvm.runtime.Magic; +import org.vmmagic.pragma.Entrypoint; +import org.vmmagic.pragma.Inline; +import org.vmmagic.pragma.NoInline; +import org.vmmagic.pragma.Uninterruptible; +import org.vmmagic.pragma.Unpreemptible; +import org.vmmagic.unboxed.Address; +import org.vmmagic.unboxed.Offset; +import org.vmmagic.unboxed.Word; + +/** + * Public entrypoints for locking + */ +@Uninterruptible +public final class Locking implements ThinLockConstants { + /** + * Obtains a lock on the indicated object. Abbreviated light-weight + * locking sequence inlined by the optimizing compiler for the + * prologue of synchronized methods and for the + * <code>monitorenter</code> bytecode. + * + * @param o the object to be locked + * @param lockOffset the offset of the thin lock word in the object. + * @see org.jikesrvm.compilers.opt.hir2lir.ExpandRuntimeServices + */ + @Inline + @Entrypoint + @Unpreemptible("Become another thread when lock is contended, don't preempt in other cases") + static void inlineLock(Object o, Offset lockOffset) { + switch (LockConfig.SELECTED) { + case LockConfig.ThinEagerDeflate: + ThinLock.inlineLock(o,lockOffset); + break; + default: VM.sysFail("bad configuration"); + } + } + + /** + * Releases the lock on the indicated object. Abreviated + * light-weight unlocking sequence inlined by the optimizing + * compiler for the epilogue of synchronized methods and for the + * <code>monitorexit</code> bytecode. + * + * @param o the object to be unlocked + * @param lockOffset the offset of the thin lock word in the object. + * @see org.jikesrvm.compilers.opt.hir2lir.ExpandRuntimeServices + */ + @Inline + @Entrypoint + @Unpreemptible("No preemption normally, but may raise exceptions") + static void inlineUnlock(Object o, Offset lockOffset) { + switch (LockConfig.SELECTED) { + case LockConfig.ThinEagerDeflate: + ThinLock.inlineUnlock(o,lockOffset); + break; + default: VM.sysFail("bad configuration"); + } + } + + /** + * Obtains a lock on the indicated object. Light-weight locking + * sequence for the prologue of synchronized methods and for the + * <code>monitorenter</code> bytecode. + * + * @param o the object to be locked + * @param lockOffset the offset of the thin lock word in the object. + */ + @NoInline + @Unpreemptible("Become another thread when lock is contended, don't preempt in other cases") + public static void lock(Object o, Offset lockOffset) { + switch (LockConfig.SELECTED) { + case LockConfig.ThinEagerDeflate: + ThinLock.lock(o,lockOffset); + break; + default: VM.sysFail("bad configuration"); + } + } + + /** + * Releases the lock on the indicated object. Light-weight unlocking + * sequence for the epilogue of synchronized methods and for the + * <code>monitorexit</code> bytecode. + * + * @param o the object to be locked + * @param lockOffset the offset of the thin lock word in the object. + */ + @NoInline + @Unpreemptible("No preemption normally, but may raise exceptions") + public static void unlock(Object o, Offset lockOffset) { + switch (LockConfig.SELECTED) { + case LockConfig.ThinEagerDeflate: + ThinLock.unlock(o,lockOffset); + break; + default: VM.sysFail("bad configuration"); + } + } + + /** + * @param obj an object + * @param lockOffset the offset of the thin lock word in the object. + * @param thread a thread + * @return <code>true</code> if the lock on obj at offset lockOffset is currently owned + * by thread <code>false</code> if it is not. + */ + public static boolean holdsLock(Object obj, Offset lockOffset, RVMThread thread) { + switch (LockConfig.SELECTED) { + case LockConfig.ThinEagerDeflate: + return ThinLock.holdsLock(obj,lockOffset,thread); + default: + VM.sysFail("bad configuration"); + return false; // never get here + } + } + + /** + * Obtains the heavy-weight lock, if there is one, associated with the + * indicated object. Returns <code>null</code>, if there is no + * heavy-weight lock associated with the object. + * + * @param o the object from which a lock is desired + * @param lockOffset the offset of the thin lock word in the object. + * @param create if true, create heavy lock if none found + * @return the heavy-weight lock on the object (if any) + */ + @Unpreemptible + public static Lock getHeavyLock(Object o, Offset lockOffset, boolean create) { + switch (LockConfig.SELECTED) { + case LockConfig.ThinEagerDeflate: + return ThinLock.getHeavyLock(o,lockOffset,create); + default: + VM.sysFail("bad configuration"); + return null; + } + } + +} + + + Added: rvmroot/branches/RVM-791/working-15440/rvm/src-generated/vm-configuration/LockConfig.template =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src-generated/vm-configuration/LockConfig.template (rev 0) +++ rvmroot/branches/RVM-791/working-15440/rvm/src-generated/vm-configuration/LockConfig.template 2009-02-15 01:23:37 UTC (rev 15443) @@ -0,0 +1,17 @@ +/* + * This file is part of the Jikes RVM project (http://jikesrvm.org). + * + * This file is licensed to You under the Common Public License (CPL); + * You may not use this file except in compliance with the License. You + * may obtain a copy of the License at + * + * http://www.opensource.org/licenses/cpl1.0.php + * + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. + */ +package org.jikesrvm.scheduler; + +public final class LockConfig extends LockConfigs { + public static final int SELECTED = @_SELECTED_@; +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <pi...@us...> - 2009-02-15 02:46:38
|
Revision: 15444 http://jikesrvm.svn.sourceforge.net/jikesrvm/?rev=15444&view=rev Author: pizlo Date: 2009-02-15 02:46:33 +0000 (Sun, 15 Feb 2009) Log Message: ----------- working on refactoring ... still not there yet and the code will probably not build Modified Paths: -------------- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/Lock.java rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/LockConfigs.java rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/Locking.java rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/RVMThread.java rvmroot/branches/RVM-791/working-15440/rvm/src-generated/vm-configuration/LockConfig.template Added Paths: ----------- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/AbstractLock.java rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/CommonLock.java rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/ThinEagerDeflateLock.java Removed Paths: ------------- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/ThinLock.java Added: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/AbstractLock.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/AbstractLock.java (rev 0) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/AbstractLock.java 2009-02-15 02:46:33 UTC (rev 15444) @@ -0,0 +1,112 @@ +/* + * This file is part of the Jikes RVM project (http://jikesrvm.org). + * + * This file is licensed to You under the Common Public License (CPL); + * You may not use this file except in compliance with the License. You + * may obtain a copy of the License at + * + * http://www.opensource.org/licenses/cpl1.0.php + * + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. + */ +package org.jikesrvm.scheduler; + +import org.jikesrvm.VM; +import org.jikesrvm.Callbacks; +import org.jikesrvm.Constants; +import org.jikesrvm.Services; +import org.jikesrvm.objectmodel.ObjectModel; +import org.jikesrvm.objectmodel.ThinLockConstants; +import org.jikesrvm.runtime.Magic; +import org.vmmagic.pragma.Inline; +import org.vmmagic.pragma.Interruptible; +import org.vmmagic.pragma.Uninterruptible; +import org.vmmagic.pragma.UnpreemptibleNoWarn; +import org.vmmagic.pragma.Unpreemptible; +import org.vmmagic.unboxed.Word; +import org.vmmagic.unboxed.Offset; + +/** + * Abstract baseclass for all locks. + */ +public abstract class AbstractLock implements Constants { + + public abstract boolean isActive(); + + public abstract int getLockId(); + + public abstract boolean lockHeavy(Object o); + + public abstract void unlockHeavy(); + + public abstract int enqueueWaitingAndUnlockCompletely(RVMThread toWait); + + public abstract boolean isWaiting(RVMThread t); + + public abstract void removeFromWaitQueue(RVMThread wasWaiting); + + public abstract void setOwnerId(int id); + + public abstract int getOwnerId(); + + public abstract void setRecursionCount(int c); + + public abstract int getRecursionCount(); + + public int unlockHeavyCompletely() { + int result=getRecursionCount(); + setRecursionCount(1); + unlockHeavy(); + return result; + } + + public static void relock(Object o,int recCount) { + ObjectModel.genericLock(o); + if (recCount!=1) { + ObjectModel.getHeavyLock(o,true).setRecursionCount(recCount); + } + } + + public abstract Object getLockedObject(); + + public abstract void setLockedObject(Object o); + + public abstract void dumpBlockedThreads(); + public abstract void dumpWaitingThreads(); + + public abstract void dumpImplementationSpecific(); + + public void dump() { + if (!isActive()) { + return; + } + VM.sysWrite("Lock "); + VM.sysWriteInt(getLockId()); + VM.sysWrite(":\n"); + VM.sysWrite(" lockedObject: "); + VM.sysWriteHex(Magic.objectAsAddress(getLockedObject())); + VM.sysWrite(" thin lock = "); + VM.sysWriteHex(Magic.objectAsAddress(getLockedObject()).loadAddress(ObjectModel.defaultThinLockOffset())); + VM.sysWrite(" object type = "); + VM.sysWrite(Magic.getObjectType(getLockedObject()).getDescriptor()); + VM.sysWriteln(); + + VM.sysWrite(" ownerId: "); + VM.sysWriteInt(getOwnerId()); + VM.sysWrite(" ("); + VM.sysWriteInt(getOwnerId() >>> ThinLockConstants.TL_THREAD_ID_SHIFT); + VM.sysWrite(") recursionCount: "); + VM.sysWriteInt(getRecursionCount()); + VM.sysWriteln(); + dumpBlockedThreads(); + dumpWaitingThreads(); + dumpImplementationSpecific(); + } + + @UnpreemptibleNoWarn + protected static void raiseIllegalMonitorStateException(String msg, Object o) { + throw new IllegalMonitorStateException(msg + o); + } +} + Added: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/CommonLock.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/CommonLock.java (rev 0) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/CommonLock.java 2009-02-15 02:46:33 UTC (rev 15444) @@ -0,0 +1,97 @@ +/* + * This file is part of the Jikes RVM project (http://jikesrvm.org). + * + * This file is licensed to You under the Common Public License (CPL); + * You may not use this file except in compliance with the License. You + * may obtain a copy of the License at + * + * http://www.opensource.org/licenses/cpl1.0.php + * + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. + */ +package org.jikesrvm.scheduler; + +import org.jikesrvm.VM; +import org.jikesrvm.Callbacks; +import org.jikesrvm.Constants; +import org.jikesrvm.Services; +import org.jikesrvm.objectmodel.ObjectModel; +import org.jikesrvm.objectmodel.ThinLockConstants; +import org.jikesrvm.runtime.Magic; +import org.vmmagic.pragma.Inline; +import org.vmmagic.pragma.Interruptible; +import org.vmmagic.pragma.Uninterruptible; +import org.vmmagic.pragma.UnpreemptibleNoWarn; +import org.vmmagic.pragma.Unpreemptible; +import org.vmmagic.unboxed.Word; +import org.vmmagic.unboxed.Offset; + +/** + * The typically not implementation-specific common to all locks. Most + * locks inheric from this. + */ +public abstract class CommonLock extends AbstractLock { + protected Object lockedObject; + protected int ownerId; + protected int recursionCount; + protected boolean active; + protected int id; + protected ThreadQueue waiting; + + protected CommonLock() { + waiting=new ThreadQueue(); + } + + protected abstract void lockWaiting(); + protected abstract void unlockWaiting(); + + public int enqueueWaitingAndUnlockCompletely(RVMThread toWait) { + lockWaiting(); + waiting.enqueue(toWait); + unlockWaiting(); + return unlockHeavyCompletely(); + } + + public boolean isWaiting(RVMThread t) { + return waiting.isQueued(t); + } + + public void removeFromWaitQueue(RVMThread wasWaiting) { + if (isWaiting(wasWaiting)) { + lockWaiting(); + waiting.remove(wasWaiting); + unlockWaiting(); + } + } + + public void setOwnerId(int id) { + ownerId=id; + } + + public int getOwnerId() { + return ownerId; + } + + public void setRecursionCount(int c) { + recursionCount=c; + } + + public int getRecursionCount() { + return recursionCount; + } + + public void setLockedObject(Object o) { + lockedObject=o; + } + + public Object getLockedObject() { + return lockedObject; + } + + protected void dumpWaitingThreads() { + VM.sysWrite(" waiting: "); + waiting.dump(); + } +} + Modified: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/Lock.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/Lock.java 2009-02-15 01:23:37 UTC (rev 15443) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/Lock.java 2009-02-15 02:46:33 UTC (rev 15444) @@ -170,34 +170,34 @@ // Statistics /** Number of lock operations */ - public static int lockOperations; + private static int lockOperations; /** Number of unlock operations */ - public static int unlockOperations; + private static int unlockOperations; /** Number of deflations */ - public static int deflations; + private static int deflations; /**************************************************************************** * Instance */ /** The object being locked (if any). */ - protected Object lockedObject; + private Object lockedObject; /** The id of the thread that owns this lock (if any). */ - protected int ownerId; + private int ownerId; /** The number of times the owning thread (if any) has acquired this lock. */ - protected int recursionCount; + private int recursionCount; /** A spin lock to handle contention for the data structures of this lock. */ - public final SpinLock mutex; + final SpinLock mutex; /** Is this lock currently being used? */ - protected boolean active; + private boolean active; /** The next free lock on the free lock list */ private Lock nextFreeLock; /** This lock's index in the lock table*/ protected int index; /** Queue for entering the lock, guarded by mutex. */ - ThreadQueue entering; + private ThreadQueue entering; /** Queue for waiting on a notify, guarded by mutex as well. */ - ThreadQueue waiting; + private ThreadQueue waiting; /** * A heavy weight lock to handle extreme contention and wait/notify @@ -326,6 +326,43 @@ lockedObject = null; free(this); } + + public int enqueueWaitingAndUnlockCompletely(RVMThread toWait) { + int result; + mutex.lock(); + RVMThread toAwaken = entering.dequeue(); + result = getRecursionCount(); + setOwnerId(0); + waiting.enqueue(toWait); + mutex.unlock(); + + // if there was a thread waiting, awaken it + if (toAwaken != null) { + // is this where the problem is coming from? + toAwaken.monitor().lockedBroadcast(); + } + + return result; + } + + public boolean isWaiting(RVMThread t) { + return l.waiting.isQueued(t); + } + + public void removeFromWaitQueue(RVMThread wasWaiting) { + if (waiting.isQueued(wasWaiting)) { + mutex.lock(); + waiting.remove(wasWaiting); /* + * in case we got here due to an interrupt or a + * stop() rather than a notify + */ + mutex.unlock(); + // Note that the above must be done before attempting to acquire + // the lock, since acquiring the lock may require queueing the thread. + // But we cannot queue the thread if it is already on another + // queue. + } + } /** * Set the owner of a lock Modified: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/LockConfigs.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/LockConfigs.java 2009-02-15 01:23:37 UTC (rev 15443) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/LockConfigs.java 2009-02-15 02:46:33 UTC (rev 15444) @@ -12,7 +12,7 @@ */ package org.jikesrvm.scheduler; -public class LockConfigs { +public final class LockConfigs { public static final int ThinEagerDeflate = 1; } Modified: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/Locking.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/Locking.java 2009-02-15 01:23:37 UTC (rev 15443) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/Locking.java 2009-02-15 02:46:33 UTC (rev 15444) @@ -46,12 +46,7 @@ @Entrypoint @Unpreemptible("Become another thread when lock is contended, don't preempt in other cases") static void inlineLock(Object o, Offset lockOffset) { - switch (LockConfig.SELECTED) { - case LockConfig.ThinEagerDeflate: - ThinLock.inlineLock(o,lockOffset); - break; - default: VM.sysFail("bad configuration"); - } + LockConfig.Selected.inlineLock(o,lockOffset); } /** @@ -68,12 +63,7 @@ @Entrypoint @Unpreemptible("No preemption normally, but may raise exceptions") static void inlineUnlock(Object o, Offset lockOffset) { - switch (LockConfig.SELECTED) { - case LockConfig.ThinEagerDeflate: - ThinLock.inlineUnlock(o,lockOffset); - break; - default: VM.sysFail("bad configuration"); - } + LockConfig.Selected.inlineUnlock(o,lockOffset); } /** @@ -87,12 +77,7 @@ @NoInline @Unpreemptible("Become another thread when lock is contended, don't preempt in other cases") public static void lock(Object o, Offset lockOffset) { - switch (LockConfig.SELECTED) { - case LockConfig.ThinEagerDeflate: - ThinLock.lock(o,lockOffset); - break; - default: VM.sysFail("bad configuration"); - } + LockConfig.Selected.lock(o,lockOffset); } /** @@ -106,12 +91,7 @@ @NoInline @Unpreemptible("No preemption normally, but may raise exceptions") public static void unlock(Object o, Offset lockOffset) { - switch (LockConfig.SELECTED) { - case LockConfig.ThinEagerDeflate: - ThinLock.unlock(o,lockOffset); - break; - default: VM.sysFail("bad configuration"); - } + LockConfig.Selected.unlock(o,lockOffset); } /** @@ -122,13 +102,7 @@ * by thread <code>false</code> if it is not. */ public static boolean holdsLock(Object obj, Offset lockOffset, RVMThread thread) { - switch (LockConfig.SELECTED) { - case LockConfig.ThinEagerDeflate: - return ThinLock.holdsLock(obj,lockOffset,thread); - default: - VM.sysFail("bad configuration"); - return false; // never get here - } + return LockConfig.Selected.holdsLock(obj,lockOffset,thread); } /** @@ -143,15 +117,8 @@ */ @Unpreemptible public static Lock getHeavyLock(Object o, Offset lockOffset, boolean create) { - switch (LockConfig.SELECTED) { - case LockConfig.ThinEagerDeflate: - return ThinLock.getHeavyLock(o,lockOffset,create); - default: - VM.sysFail("bad configuration"); - return null; - } + return LockConfig.Selected.getHeavyLock(o,lockOffset,create); } - } Modified: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/RVMThread.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/RVMThread.java 2009-02-15 01:23:37 UTC (rev 15443) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/RVMThread.java 2009-02-15 02:46:33 UTC (rev 15444) @@ -622,15 +622,6 @@ */ /** - * Place to save/restore this thread's monitor state during - * {@link Object#wait} and {@link Object#notify}. - */ - protected Object waitObject; - - /** Lock recursion count for this thread's monitor. */ - protected int waitCount; - - /** * Should the thread suspend? */ boolean shouldSuspend; @@ -2749,23 +2740,12 @@ if (VM.VerifyAssertions) VM._assert(l.getOwnerId() == getLockingId()); - // release the lock - l.mutex.lock(); - RVMThread toAwaken = l.entering.dequeue(); - waitObject = l.getLockedObject(); - waitCount = l.getRecursionCount(); - l.setOwnerId(0); - l.waiting.enqueue(this); - l.mutex.unlock(); + // release the lock and enqueue waiting + int waitCount=l.enqueueWaitingAndUnlockCompletely(this); - // if there was a thread waiting, awaken it - if (toAwaken != null) { - // is this where the problem is coming from? - toAwaken.monitor().lockedBroadcast(); - } // block monitor().lock(); - while (l.waiting.isQueued(this) && !hasInterrupt && asyncThrowable == null && + while (l.isWaiting(this) && !hasInterrupt && asyncThrowable == null && (!hasTimeout || sysCall.sysNanoTime() < whenWakeupNanos)) { if (hasTimeout) { monitor().timedWaitAbsoluteNicely(whenWakeupNanos); @@ -2783,19 +2763,10 @@ asyncThrowable = null; } monitor().unlock(); - if (l.waiting.isQueued(this)) { - l.mutex.lock(); - l.waiting.remove(this); /* - * in case we got here due to an interrupt or a - * stop() rather than a notify - */ - l.mutex.unlock(); - // Note that the above must be done before attempting to acquire - // the lock, since acquiring the lock may require queueing the thread. - // But we cannot queue the thread if it is already on another - // queue. - } - // reacquire the lock, restoring the recursion count + l.removeFromWaitQueue(this); + // reacquire the lock, restoring the recursion count. note that the + // lock associated with the object may have changed (been deflated and + // reinflated) so we must start anew ObjectModel.genericLock(o); waitObject = null; if (waitCount != 1) { // reset recursion count Copied: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/ThinEagerDeflateLock.java (from rev 15442, rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/ThinLock.java) =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/ThinEagerDeflateLock.java (rev 0) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/ThinEagerDeflateLock.java 2009-02-15 02:46:33 UTC (rev 15444) @@ -0,0 +1,432 @@ +/* + * This file is part of the Jikes RVM project (http://jikesrvm.org). + * + * This file is licensed to You under the Common Public License (CPL); + * You may not use this file except in compliance with the License. You + * may obtain a copy of the License at + * + * http://www.opensource.org/licenses/cpl1.0.php + * + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. + */ +package org.jikesrvm.scheduler; + +import org.jikesrvm.VM; +import org.jikesrvm.Services; +import org.jikesrvm.classloader.RVMMethod; +import org.jikesrvm.compilers.common.CompiledMethods; +import org.jikesrvm.objectmodel.ThinLockConstants; +import org.jikesrvm.runtime.Magic; +import org.vmmagic.pragma.Inline; +import org.vmmagic.pragma.NoInline; +import org.vmmagic.pragma.Uninterruptible; +import org.vmmagic.pragma.Unpreemptible; +import org.vmmagic.unboxed.Address; +import org.vmmagic.unboxed.Offset; +import org.vmmagic.unboxed.Word; + +/** + * Implementation of thin locks. + */ +@Uninterruptible +final class ThinEagerDeflateLock implements ThinLockConstants { + + //////////////////////////////////////// + /// Support for light-weight locking /// + //////////////////////////////////////// + + /** + * Return the lock index for a given lock word. Assert valid index + * ranges, that the fat lock bit is set, and that the lock entry + * exists. + * + * @param lockWord The lock word whose lock index is being established + * @return the lock index corresponding to the lock workd. + */ + @Inline + private static int getLockIndex(Word lockWord) { + int index = lockWord.and(TL_LOCK_ID_MASK).rshl(TL_LOCK_ID_SHIFT).toInt(); + if (VM.VerifyAssertions) { + if (!(index > 0 && index < Lock.numLocks())) { + VM.sysWrite("Lock index out of range! Word: "); VM.sysWrite(lockWord); + VM.sysWrite(" index: "); VM.sysWrite(index); + VM.sysWrite(" locks: "); VM.sysWrite(Lock.numLocks()); + VM.sysWriteln(); + } + VM._assert(index > 0 && index < Lock.numLocks()); // index is in range + VM._assert(!lockWord.and(TL_FAT_LOCK_MASK).isZero()); // fat lock bit is set + VM._assert(Lock.getLock(index) != null); // the lock is actually there + } + return index; + } + + /** + * Obtains a lock on the indicated object. Abbreviated light-weight + * locking sequence inlined by the optimizing compiler for the + * prologue of synchronized methods and for the + * <code>monitorenter</code> bytecode. + * + * @param o the object to be locked + * @param lockOffset the offset of the thin lock word in the object. + * @see org.jikesrvm.compilers.opt.hir2lir.ExpandRuntimeServices + */ + @Inline + @Unpreemptible("Become another thread when lock is contended, don't preempt in other cases") + static void inlineLock(Object o, Offset lockOffset) { + Word old = Magic.prepareWord(o, lockOffset); + if (old.rshl(TL_THREAD_ID_SHIFT).isZero()) { + // implies that fatbit == 0 & threadid == 0 + int threadId = RVMThread.getCurrentThread().getLockingId(); + if (Magic.attemptWord(o, lockOffset, old, old.or(Word.fromIntZeroExtend(threadId)))) { + Magic.isync(); // don't use stale prefetched data in monitor + if (STATS) fastLocks++; + return; // common case: o is now locked + } + } + lock(o, lockOffset); // uncommon case: default to out-of-line lock() + } + + /** + * Releases the lock on the indicated object. Abreviated + * light-weight unlocking sequence inlined by the optimizing + * compiler for the epilogue of synchronized methods and for the + * <code>monitorexit</code> bytecode. + * + * @param o the object to be unlocked + * @param lockOffset the offset of the thin lock word in the object. + * @see org.jikesrvm.compilers.opt.hir2lir.ExpandRuntimeServices + */ + @Inline + @Unpreemptible("No preemption normally, but may raise exceptions") + static void inlineUnlock(Object o, Offset lockOffset) { + Word old = Magic.prepareWord(o, lockOffset); + Word threadId = Word.fromIntZeroExtend(RVMThread.getCurrentThread().getLockingId()); + if (old.xor(threadId).rshl(TL_LOCK_COUNT_SHIFT).isZero()) { // implies that fatbit == 0 && count == 0 && lockid == me + Magic.sync(); // memory barrier: subsequent locker will see previous writes + if (Magic.attemptWord(o, lockOffset, old, old.and(TL_UNLOCK_MASK))) { + return; // common case: o is now unlocked + } + } + unlock(o, lockOffset); // uncommon case: default to non inlined unlock() + } + + /** + * Obtains a lock on the indicated object. Light-weight locking + * sequence for the prologue of synchronized methods and for the + * <code>monitorenter</code> bytecode. + * + * @param o the object to be locked + * @param lockOffset the offset of the thin lock word in the object. + */ + @NoInline + @Unpreemptible("Become another thread when lock is contended, don't preempt in other cases") + static void lock(Object o, Offset lockOffset) { + major: + while (true) { // repeat only if attempt to lock a promoted lock fails + int retries = retryLimit; + Word threadId = Word.fromIntZeroExtend(RVMThread.getCurrentThread().getLockingId()); + while (0 != retries--) { // repeat if there is contention for thin lock + Word old = Magic.prepareWord(o, lockOffset); + Word id = old.and(TL_THREAD_ID_MASK.or(TL_FAT_LOCK_MASK)); + if (id.isZero()) { // o isn't locked + if (Magic.attemptWord(o, lockOffset, old, old.or(threadId))) { + Magic.isync(); // don't use stale prefetched data in monitor + if (STATS) slowLocks++; + break major; // lock succeeds + } + continue; // contention, possibly spurious, try again + } + if (id.EQ(threadId)) { // this thread has o locked already + Word changed = old.toAddress().plus(TL_LOCK_COUNT_UNIT).toWord(); // update count + if (changed.and(TL_LOCK_COUNT_MASK).isZero()) { // count wrapped around (most unlikely), make heavy lock + while (!inflateAndLock(o, lockOffset)) { // wait for a lock to become available + RVMThread.yield(); + } + break major; // lock succeeds (note that lockHeavy has issued an isync) + } + if (Magic.attemptWord(o, lockOffset, old, changed)) { + Magic.isync(); // don't use stale prefetched data in monitor !!TODO: is this isync required? + if (STATS) slowLocks++; + break major; // lock succeeds + } + continue; // contention, probably spurious, try again (TODO!! worry about this) + } + + if (!(old.and(TL_FAT_LOCK_MASK).isZero())) { // o has a heavy lock + int index = getLockIndex(old); + if (Lock.getLock(index).lockHeavy(o)) { + break major; // lock succeeds (note that lockHeavy has issued an isync) + } + // heavy lock failed (deflated or contention for system lock) + RVMThread.yield(); + continue major; // try again + } + // real contention: wait (hope other thread unlocks o), try again + if (traceContention) { // for performance tuning only (see section 5) + Address fp = Magic.getFramePointer(); + fp = Magic.getCallerFramePointer(fp); + int mid = Magic.getCompiledMethodID(fp); + RVMMethod m1 = CompiledMethods.getCompiledMethod(mid).getMethod(); + fp = Magic.getCallerFramePointer(fp); + mid = Magic.getCompiledMethodID(fp); + RVMMethod m2 = CompiledMethods.getCompiledMethod(mid).getMethod(); + String s = m1.getDeclaringClass() + "." + m1.getName() + " " + m2.getDeclaringClass() + "." + m2.getName(); + RVMThread.trace(Magic.getObjectType(o).toString(), s, -2 - retries); + } + if (0 != retries) { + RVMThread.yield(); // wait, hope o gets unlocked + } + } + // create a heavy lock for o and lock it + if (inflateAndLock(o, lockOffset)) break; + } + // o has been locked, must return before an exception can be thrown + } + + /** + * Releases the lock on the indicated object. Light-weight unlocking + * sequence for the epilogue of synchronized methods and for the + * <code>monitorexit</code> bytecode. + * + * @param o the object to be locked + * @param lockOffset the offset of the thin lock word in the object. + */ + @NoInline + @Unpreemptible("No preemption normally, but may raise exceptions") + static void unlock(Object o, Offset lockOffset) { + Magic.sync(); // prevents stale data from being seen by next owner of the lock + while (true) { // spurious contention detected + Word old = Magic.prepareWord(o, lockOffset); + Word id = old.and(TL_THREAD_ID_MASK.or(TL_FAT_LOCK_MASK)); + Word threadId = Word.fromIntZeroExtend(RVMThread.getCurrentThread().getLockingId()); + if (id.NE(threadId)) { // not normal case + if (!(old.and(TL_FAT_LOCK_MASK).isZero())) { // o has a heavy lock + Lock.getLock(getLockIndex(old)).unlockHeavy(o); + // note that unlockHeavy has issued a sync + return; + } + RVMThread.trace("Lock", "unlock error: thin lock word = ", old.toAddress()); + RVMThread.trace("Lock", "unlock error: thin lock word = ", Magic.objectAsAddress(o)); + // RVMThread.trace("Lock", RVMThread.getCurrentThread().toString(), 0); + RVMThread.raiseIllegalMonitorStateException("thin unlocking", o); + } + if (old.and(TL_LOCK_COUNT_MASK).isZero()) { // get count, 0 is the last lock + Word changed = old.and(TL_UNLOCK_MASK); + if (Magic.attemptWord(o, lockOffset, old, changed)) { + return; // unlock succeeds + } + continue; + } + // more than one lock + // decrement recursion count + Word changed = old.toAddress().minus(TL_LOCK_COUNT_UNIT).toWord(); + if (Magic.attemptWord(o, lockOffset, old, changed)) { + return; // unlock succeeds + } + } + } + + //////////////////////////////////////////////////////////////// + /// Support for inflating (and deflating) heavy-weight locks /// + //////////////////////////////////////////////////////////////// + + /** + * Promotes a light-weight lock to a heavy-weight lock. Note: the + * object is question will normally be locked by another thread, + * or it may be unlocked. If there is already a heavy-weight lock + * on this object, that lock is returned. + * + * @param o the object to get a heavy-weight lock + * @param lockOffset the offset of the thin lock word in the object. + * @return the heavy-weight lock on this object + */ + @Unpreemptible + private static Lock inflate(Object o, Offset lockOffset) { + RVMThread.enterLockingPath(); + if (VM.VerifyAssertions) { + VM._assert(holdsLock(o, lockOffset, RVMThread.getCurrentThread())); + // this assertions is just plain wrong. + //VM._assert((Magic.getWordAtOffset(o, lockOffset).and(TL_FAT_LOCK_MASK).isZero())); + } + Lock l = Lock.allocate(); + if (VM.VerifyAssertions) { + VM._assert(l != null); // inflate called by wait (or notify) which shouldn't be called during GC + } + Lock rtn = attemptToInflate(o, lockOffset, l); + if (rtn == l) + l.mutex.unlock(); + RVMThread.leaveLockingPath(); + return rtn; + } + + /** + * Promotes a light-weight lock to a heavy-weight lock and locks it. + * Note: the object in question will normally be locked by another + * thread, or it may be unlocked. If there is already a + * heavy-weight lock on this object, that lock is returned. + * + * @param o the object to get a heavy-weight lock + * @param lockOffset the offset of the thin lock word in the object. + * @return whether the object was successfully locked + */ + @Unpreemptible + private static boolean inflateAndLock(Object o, Offset lockOffset) { + Lock l = Lock.allocate(); + if (l == null) return false; // can't allocate locks during GC + Lock rtn = attemptToInflate(o, lockOffset, l); + if (l != rtn) { + l = rtn; + l.mutex.lock(); + } + return l.lockHeavyLocked(o); + } + + /** + * Promotes a light-weight lock to a heavy-weight lock. + * + * @param o the object to get a heavy-weight lock + * @param lockOffset the offset of the thin lock word in the object. + * @return whether the object was successfully locked + */ + private static Lock attemptToInflate(Object o, Offset lockOffset, Lock l) { + RVMThread.enterLockingPath(); + Word old; + l.mutex.lock(); + do { + old = Magic.prepareWord(o, lockOffset); + // check to see if another thread has already created a fat lock + if (!(old.and(TL_FAT_LOCK_MASK).isZero())) { // already a fat lock in place + if (Lock.trace) { + VM.sysWriteln("Thread #",RVMThread.getCurrentThreadSlot(), + ": freeing lock ",Magic.objectAsAddress(l), + " because we had a double-inflate"); + } + Lock.free(l); + l.mutex.unlock(); + l = Lock.getLock(getLockIndex(old)); + RVMThread.leaveLockingPath(); + return l; + } + Word locked = TL_FAT_LOCK_MASK.or(Word.fromIntZeroExtend(l.index).lsh(TL_LOCK_ID_SHIFT)); + Word changed = locked.or(old.and(TL_UNLOCK_MASK)); + if (VM.VerifyAssertions) VM._assert(getLockIndex(changed) == l.index); + if (Magic.attemptWord(o, lockOffset, old, changed)) { + l.setLockedObject(o); + l.setOwnerId(old.and(TL_THREAD_ID_MASK).toInt()); + if (l.getOwnerId() != 0) { + l.setRecursionCount(old.and(TL_LOCK_COUNT_MASK).rshl(TL_LOCK_COUNT_SHIFT).toInt() + 1); + } + RVMThread.leaveLockingPath(); + return l; + } + // contention detected, try again + } while (true); + } + + static void deflate(Object o, Offset lockOffset, Lock l) { + if (VM.VerifyAssertions) { + Word old = Magic.getWordAtOffset(o, lockOffset); + VM._assert(!(old.and(TL_FAT_LOCK_MASK).isZero())); + VM._assert(l == Lock.getLock(getLockIndex(old))); + } + Word old; + do { + old = Magic.prepareWord(o, lockOffset); + } while (!Magic.attemptWord(o, lockOffset, old, old.and(TL_UNLOCK_MASK))); + } + + /** + * @param obj an object + * @param lockOffset the offset of the thin lock word in the object. + * @param thread a thread + * @return <code>true</code> if the lock on obj at offset lockOffset is currently owned + * by thread <code>false</code> if it is not. + */ + static boolean holdsLock(Object obj, Offset lockOffset, RVMThread thread) { + int tid = thread.getLockingId(); + Word bits = Magic.getWordAtOffset(obj, lockOffset); + if (bits.and(TL_FAT_LOCK_MASK).isZero()) { + // if locked, then it is locked with a thin lock + return (bits.and(ThinLockConstants.TL_THREAD_ID_MASK).toInt() == tid); + } else { + // if locked, then it is locked with a fat lock + int index = getLockIndex(bits); + Lock l = Lock.getLock(index); + return l != null && l.getOwnerId() == tid; + } + } + + //////////////////////////////////////////////////////////////////////////// + /// Get heavy-weight lock for an object; if thin, inflate it. + //////////////////////////////////////////////////////////////////////////// + + /** + * Obtains the heavy-weight lock, if there is one, associated with the + * indicated object. Returns <code>null</code>, if there is no + * heavy-weight lock associated with the object. + * + * @param o the object from which a lock is desired + * @param lockOffset the offset of the thin lock word in the object. + * @param create if true, create heavy lock if none found + * @return the heavy-weight lock on the object (if any) + */ + @Unpreemptible + static Lock getHeavyLock(Object o, Offset lockOffset, boolean create) { + Word old = Magic.getWordAtOffset(o, lockOffset); + if (!(old.and(TL_FAT_LOCK_MASK).isZero())) { // already a fat lock in place + return Lock.getLock(getLockIndex(old)); + } else if (create) { + return inflate(o, lockOffset); + } else { + return null; + } + + } + + /////////////////////////////////////////////////////////////// + /// Support for debugging and performance tuning /// + /////////////////////////////////////////////////////////////// + + /** + * Number of times a thread yields before inflating the lock on a + * object to a heavy-weight lock. The current value was for the + * portBOB benchmark on a 12-way SMP (AIX) in the Fall of '99. This + * is almost certainly not the optimal value. + */ + private static final int retryLimit = 40; // (-1 is effectively infinity) + + /** + * Should we trace lockContention to enable debugging? + */ + private static final boolean traceContention = false; + + ////////////////////////////////////////////// + // Statistics // + ////////////////////////////////////////////// + + static final boolean STATS = Lock.STATS; + + static int fastLocks; + static int slowLocks; + + static void notifyAppRunStart(String app, int value) { + if (!STATS) return; + fastLocks = 0; + slowLocks = 0; + } + + static void notifyExit(int value) { + if (!STATS) return; + VM.sysWrite("ThinLocks: "); + VM.sysWrite(fastLocks); + VM.sysWrite(" fast locks"); + Services.percentage(fastLocks, value, "all lock operations"); + VM.sysWrite("ThinLocks: "); + VM.sysWrite(slowLocks); + VM.sysWrite(" slow locks"); + Services.percentage(slowLocks, value, "all lock operations"); + } + +} + Deleted: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/ThinLock.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/ThinLock.java 2009-02-15 01:23:37 UTC (rev 15443) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/ThinLock.java 2009-02-15 02:46:33 UTC (rev 15444) @@ -1,432 +0,0 @@ -/* - * This file is part of the Jikes RVM project (http://jikesrvm.org). - * - * This file is licensed to You under the Common Public License (CPL); - * You may not use this file except in compliance with the License. You - * may obtain a copy of the License at - * - * http://www.opensource.org/licenses/cpl1.0.php - * - * See the COPYRIGHT.txt file distributed with this work for information - * regarding copyright ownership. - */ -package org.jikesrvm.scheduler; - -import org.jikesrvm.VM; -import org.jikesrvm.Services; -import org.jikesrvm.classloader.RVMMethod; -import org.jikesrvm.compilers.common.CompiledMethods; -import org.jikesrvm.objectmodel.ThinLockConstants; -import org.jikesrvm.runtime.Magic; -import org.vmmagic.pragma.Inline; -import org.vmmagic.pragma.NoInline; -import org.vmmagic.pragma.Uninterruptible; -import org.vmmagic.pragma.Unpreemptible; -import org.vmmagic.unboxed.Address; -import org.vmmagic.unboxed.Offset; -import org.vmmagic.unboxed.Word; - -/** - * Implementation of thin locks. - */ -@Uninterruptible -final class ThinLock implements ThinLockConstants { - - //////////////////////////////////////// - /// Support for light-weight locking /// - //////////////////////////////////////// - - /** - * Return the lock index for a given lock word. Assert valid index - * ranges, that the fat lock bit is set, and that the lock entry - * exists. - * - * @param lockWord The lock word whose lock index is being established - * @return the lock index corresponding to the lock workd. - */ - @Inline - private static int getLockIndex(Word lockWord) { - int index = lockWord.and(TL_LOCK_ID_MASK).rshl(TL_LOCK_ID_SHIFT).toInt(); - if (VM.VerifyAssertions) { - if (!(index > 0 && index < Lock.numLocks())) { - VM.sysWrite("Lock index out of range! Word: "); VM.sysWrite(lockWord); - VM.sysWrite(" index: "); VM.sysWrite(index); - VM.sysWrite(" locks: "); VM.sysWrite(Lock.numLocks()); - VM.sysWriteln(); - } - VM._assert(index > 0 && index < Lock.numLocks()); // index is in range - VM._assert(!lockWord.and(TL_FAT_LOCK_MASK).isZero()); // fat lock bit is set - VM._assert(Lock.getLock(index) != null); // the lock is actually there - } - return index; - } - - /** - * Obtains a lock on the indicated object. Abbreviated light-weight - * locking sequence inlined by the optimizing compiler for the - * prologue of synchronized methods and for the - * <code>monitorenter</code> bytecode. - * - * @param o the object to be locked - * @param lockOffset the offset of the thin lock word in the object. - * @see org.jikesrvm.compilers.opt.hir2lir.ExpandRuntimeServices - */ - @Inline - @Unpreemptible("Become another thread when lock is contended, don't preempt in other cases") - static void inlineLock(Object o, Offset lockOffset) { - Word old = Magic.prepareWord(o, lockOffset); - if (old.rshl(TL_THREAD_ID_SHIFT).isZero()) { - // implies that fatbit == 0 & threadid == 0 - int threadId = RVMThread.getCurrentThread().getLockingId(); - if (Magic.attemptWord(o, lockOffset, old, old.or(Word.fromIntZeroExtend(threadId)))) { - Magic.isync(); // don't use stale prefetched data in monitor - if (STATS) fastLocks++; - return; // common case: o is now locked - } - } - lock(o, lockOffset); // uncommon case: default to out-of-line lock() - } - - /** - * Releases the lock on the indicated object. Abreviated - * light-weight unlocking sequence inlined by the optimizing - * compiler for the epilogue of synchronized methods and for the - * <code>monitorexit</code> bytecode. - * - * @param o the object to be unlocked - * @param lockOffset the offset of the thin lock word in the object. - * @see org.jikesrvm.compilers.opt.hir2lir.ExpandRuntimeServices - */ - @Inline - @Unpreemptible("No preemption normally, but may raise exceptions") - static void inlineUnlock(Object o, Offset lockOffset) { - Word old = Magic.prepareWord(o, lockOffset); - Word threadId = Word.fromIntZeroExtend(RVMThread.getCurrentThread().getLockingId()); - if (old.xor(threadId).rshl(TL_LOCK_COUNT_SHIFT).isZero()) { // implies that fatbit == 0 && count == 0 && lockid == me - Magic.sync(); // memory barrier: subsequent locker will see previous writes - if (Magic.attemptWord(o, lockOffset, old, old.and(TL_UNLOCK_MASK))) { - return; // common case: o is now unlocked - } - } - unlock(o, lockOffset); // uncommon case: default to non inlined unlock() - } - - /** - * Obtains a lock on the indicated object. Light-weight locking - * sequence for the prologue of synchronized methods and for the - * <code>monitorenter</code> bytecode. - * - * @param o the object to be locked - * @param lockOffset the offset of the thin lock word in the object. - */ - @NoInline - @Unpreemptible("Become another thread when lock is contended, don't preempt in other cases") - static void lock(Object o, Offset lockOffset) { - major: - while (true) { // repeat only if attempt to lock a promoted lock fails - int retries = retryLimit; - Word threadId = Word.fromIntZeroExtend(RVMThread.getCurrentThread().getLockingId()); - while (0 != retries--) { // repeat if there is contention for thin lock - Word old = Magic.prepareWord(o, lockOffset); - Word id = old.and(TL_THREAD_ID_MASK.or(TL_FAT_LOCK_MASK)); - if (id.isZero()) { // o isn't locked - if (Magic.attemptWord(o, lockOffset, old, old.or(threadId))) { - Magic.isync(); // don't use stale prefetched data in monitor - if (STATS) slowLocks++; - break major; // lock succeeds - } - continue; // contention, possibly spurious, try again - } - if (id.EQ(threadId)) { // this thread has o locked already - Word changed = old.toAddress().plus(TL_LOCK_COUNT_UNIT).toWord(); // update count - if (changed.and(TL_LOCK_COUNT_MASK).isZero()) { // count wrapped around (most unlikely), make heavy lock - while (!inflateAndLock(o, lockOffset)) { // wait for a lock to become available - RVMThread.yield(); - } - break major; // lock succeeds (note that lockHeavy has issued an isync) - } - if (Magic.attemptWord(o, lockOffset, old, changed)) { - Magic.isync(); // don't use stale prefetched data in monitor !!TODO: is this isync required? - if (STATS) slowLocks++; - break major; // lock succeeds - } - continue; // contention, probably spurious, try again (TODO!! worry about this) - } - - if (!(old.and(TL_FAT_LOCK_MASK).isZero())) { // o has a heavy lock - int index = getLockIndex(old); - if (Lock.getLock(index).lockHeavy(o)) { - break major; // lock succeeds (note that lockHeavy has issued an isync) - } - // heavy lock failed (deflated or contention for system lock) - RVMThread.yield(); - continue major; // try again - } - // real contention: wait (hope other thread unlocks o), try again - if (traceContention) { // for performance tuning only (see section 5) - Address fp = Magic.getFramePointer(); - fp = Magic.getCallerFramePointer(fp); - int mid = Magic.getCompiledMethodID(fp); - RVMMethod m1 = CompiledMethods.getCompiledMethod(mid).getMethod(); - fp = Magic.getCallerFramePointer(fp); - mid = Magic.getCompiledMethodID(fp); - RVMMethod m2 = CompiledMethods.getCompiledMethod(mid).getMethod(); - String s = m1.getDeclaringClass() + "." + m1.getName() + " " + m2.getDeclaringClass() + "." + m2.getName(); - RVMThread.trace(Magic.getObjectType(o).toString(), s, -2 - retries); - } - if (0 != retries) { - RVMThread.yield(); // wait, hope o gets unlocked - } - } - // create a heavy lock for o and lock it - if (inflateAndLock(o, lockOffset)) break; - } - // o has been locked, must return before an exception can be thrown - } - - /** - * Releases the lock on the indicated object. Light-weight unlocking - * sequence for the epilogue of synchronized methods and for the - * <code>monitorexit</code> bytecode. - * - * @param o the object to be locked - * @param lockOffset the offset of the thin lock word in the object. - */ - @NoInline - @Unpreemptible("No preemption normally, but may raise exceptions") - static void unlock(Object o, Offset lockOffset) { - Magic.sync(); // prevents stale data from being seen by next owner of the lock - while (true) { // spurious contention detected - Word old = Magic.prepareWord(o, lockOffset); - Word id = old.and(TL_THREAD_ID_MASK.or(TL_FAT_LOCK_MASK)); - Word threadId = Word.fromIntZeroExtend(RVMThread.getCurrentThread().getLockingId()); - if (id.NE(threadId)) { // not normal case - if (!(old.and(TL_FAT_LOCK_MASK).isZero())) { // o has a heavy lock - Lock.getLock(getLockIndex(old)).unlockHeavy(o); - // note that unlockHeavy has issued a sync - return; - } - RVMThread.trace("Lock", "unlock error: thin lock word = ", old.toAddress()); - RVMThread.trace("Lock", "unlock error: thin lock word = ", Magic.objectAsAddress(o)); - // RVMThread.trace("Lock", RVMThread.getCurrentThread().toString(), 0); - RVMThread.raiseIllegalMonitorStateException("thin unlocking", o); - } - if (old.and(TL_LOCK_COUNT_MASK).isZero()) { // get count, 0 is the last lock - Word changed = old.and(TL_UNLOCK_MASK); - if (Magic.attemptWord(o, lockOffset, old, changed)) { - return; // unlock succeeds - } - continue; - } - // more than one lock - // decrement recursion count - Word changed = old.toAddress().minus(TL_LOCK_COUNT_UNIT).toWord(); - if (Magic.attemptWord(o, lockOffset, old, changed)) { - return; // unlock succeeds - } - } - } - - //////////////////////////////////////////////////////////////// - /// Support for inflating (and deflating) heavy-weight locks /// - //////////////////////////////////////////////////////////////// - - /** - * Promotes a light-weight lock to a heavy-weight lock. Note: the - * object is question will normally be locked by another thread, - * or it may be unlocked. If there is already a heavy-weight lock - * on this object, that lock is returned. - * - * @param o the object to get a heavy-weight lock - * @param lockOffset the offset of the thin lock word in the object. - * @return the heavy-weight lock on this object - */ - @Unpreemptible - private static Lock inflate(Object o, Offset lockOffset) { - RVMThread.enterLockingPath(); - if (VM.VerifyAssertions) { - VM._assert(holdsLock(o, lockOffset, RVMThread.getCurrentThread())); - // this assertions is just plain wrong. - //VM._assert((Magic.getWordAtOffset(o, lockOffset).and(TL_FAT_LOCK_MASK).isZero())); - } - Lock l = Lock.allocate(); - if (VM.VerifyAssertions) { - VM._assert(l != null); // inflate called by wait (or notify) which shouldn't be called during GC - } - Lock rtn = attemptToInflate(o, lockOffset, l); - if (rtn == l) - l.mutex.unlock(); - RVMThread.leaveLockingPath(); - return rtn; - } - - /** - * Promotes a light-weight lock to a heavy-weight lock and locks it. - * Note: the object in question will normally be locked by another - * thread, or it may be unlocked. If there is already a - * heavy-weight lock on this object, that lock is returned. - * - * @param o the object to get a heavy-weight lock - * @param lockOffset the offset of the thin lock word in the object. - * @return whether the object was successfully locked - */ - @Unpreemptible - private static boolean inflateAndLock(Object o, Offset lockOffset) { - Lock l = Lock.allocate(); - if (l == null) return false; // can't allocate locks during GC - Lock rtn = attemptToInflate(o, lockOffset, l); - if (l != rtn) { - l = rtn; - l.mutex.lock(); - } - return l.lockHeavyLocked(o); - } - - /** - * Promotes a light-weight lock to a heavy-weight lock. - * - * @param o the object to get a heavy-weight lock - * @param lockOffset the offset of the thin lock word in the object. - * @return whether the object was successfully locked - */ - private static Lock attemptToInflate(Object o, Offset lockOffset, Lock l) { - RVMThread.enterLockingPath(); - Word old; - l.mutex.lock(); - do { - old = Magic.prepareWord(o, lockOffset); - // check to see if another thread has already created a fat lock - if (!(old.and(TL_FAT_LOCK_MASK).isZero())) { // already a fat lock in place - if (Lock.trace) { - VM.sysWriteln("Thread #",RVMThread.getCurrentThreadSlot(), - ": freeing lock ",Magic.objectAsAddress(l), - " because we had a double-inflate"); - } - Lock.free(l); - l.mutex.unlock(); - l = Lock.getLock(getLockIndex(old)); - RVMThread.leaveLockingPath(); - return l; - } - Word locked = TL_FAT_LOCK_MASK.or(Word.fromIntZeroExtend(l.index).lsh(TL_LOCK_ID_SHIFT)); - Word changed = locked.or(old.and(TL_UNLOCK_MASK)); - if (VM.VerifyAssertions) VM._assert(getLockIndex(changed) == l.index); - if (Magic.attemptWord(o, lockOffset, old, changed)) { - l.setLockedObject(o); - l.setOwnerId(old.and(TL_THREAD_ID_MASK).toInt()); - if (l.getOwnerId() != 0) { - l.setRecursionCount(old.and(TL_LOCK_COUNT_MASK).rshl(TL_LOCK_COUNT_SHIFT).toInt() + 1); - } - RVMThread.leaveLockingPath(); - return l; - } - // contention detected, try again - } while (true); - } - - static void deflate(Object o, Offset lockOffset, Lock l) { - if (VM.VerifyAssertions) { - Word old = Magic.getWordAtOffset(o, lockOffset); - VM._assert(!(old.and(TL_FAT_LOCK_MASK).isZero())); - VM._assert(l == Lock.getLock(getLockIndex(old))); - } - Word old; - do { - old = Magic.prepareWord(o, lockOffset); - } while (!Magic.attemptWord(o, lockOffset, old, old.and(TL_UNLOCK_MASK))); - } - - /** - * @param obj an object - * @param lockOffset the offset of the thin lock word in the object. - * @param thread a thread - * @return <code>true</code> if the lock on obj at offset lockOffset is currently owned - * by thread <code>false</code> if it is not. - */ - static boolean holdsLock(Object obj, Offset lockOffset, RVMThread thread) { - int tid = thread.getLockingId(); - Word bits = Magic.getWordAtOffset(obj, lockOffset); - if (bits.and(TL_FAT_LOCK_MASK).isZero()) { - // if locked, then it is locked with a thin lock - return (bits.and(ThinLockConstants.TL_THREAD_ID_MASK).toInt() == tid); - } else { - // if locked, then it is locked with a fat lock - int index = getLockIndex(bits); - Lock l = Lock.getLock(index); - return l != null && l.getOwnerId() == tid; - } - } - - //////////////////////////////////////////////////////////////////////////// - /// Get heavy-weight lock for an object; if thin, inflate it. - //////////////////////////////////////////////////////////////////////////// - - /** - * Obtains the heavy-weight lock, if there is one, associated with the - * indicated object. Returns <code>null</code>, if there is no - * heavy-weight lock associated with the object. - * - * @param o the object from which a lock is desired - * @param lockOffset the offset of the thin lock word in the object. - * @param create if true, create heavy lock if none found - * @return the heavy-weight lock on the object (if any) - */ - @Unpreemptible - static Lock getHeavyLock(Object o, Offset lockOffset, boolean create) { - Word old = Magic.getWordAtOffset(o, lockOffset); - if (!(old.and(TL_FAT_LOCK_MASK).isZero())) { // already a fat lock in place - return Lock.getLock(getLockIndex(old)); - } else if (create) { - return inflate(o, lockOffset); - } else { - return null; - } - - } - - /////////////////////////////////////////////////////////////// - /// Support for debugging and performance tuning /// - /////////////////////////////////////////////////////////////// - - /** - * Number of times a thread yields before inflating the lock on a - * object to a heavy-weight lock. The current value was for the - * portBOB benchmark on a 12-way SMP (AIX) in the Fall of '99. This - * is almost certainly not the optimal value. - */ - private static final int retryLimit = 40; // (-1 is effectively infinity) - - /** - * Should we trace lockContention to enable debugging? - */ - private static final boolean traceContention = false; - - ////////////////////////////////////////////// - // Statistics // - ////////////////////////////////////////////// - - static final boolean STATS = Lock.STATS; - - static int fastLocks; - static int slowLocks; - - static void notifyAppRunStart(String app, int value) { - if (!STATS) return; - fastLocks = 0; - slowLocks = 0; - } - - static void notifyExit(int value) { - if (!STATS) return; - VM.sysWrite("ThinLocks: "); - VM.sysWrite(fastLocks); - VM.sysWrite(" fast locks"); - Services.percentage(fastLocks, value, "all lock operations"); - VM.sysWrite("ThinLocks: "); - VM.sysWrite(slowLocks); - VM.sysWrite(" slow locks"); - Services.percentage(slowLocks, value, "all lock operations"); - } - -} - Modified: rvmroot/branches/RVM-791/working-15440/rvm/src-generated/vm-configuration/LockConfig.template =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src-generated/vm-configuration/LockConfig.template 2009-02-15 01:23:37 UTC (rev 15443) +++ rvmroot/branches/RVM-791/working-15440/rvm/src-generated/vm-configuration/LockConfig.template 2009-02-15 02:46:33 UTC (rev 15444) @@ -12,6 +12,8 @@ */ package org.jikesrvm.scheduler; -public final class LockConfig extends LockConfigs { - public static final int SELECTED = @_SELECTED_@; +public final class LockConfig { + public static final int SELECTED = LockConfigs.@_SELECTED_@; + + public static final class Selected extends @_SELECTED_@Lock; } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <pi...@us...> - 2009-02-15 08:03:28
|
Revision: 15445 http://jikesrvm.svn.sourceforge.net/jikesrvm/?rev=15445&view=rev Author: pizlo Date: 2009-02-15 08:03:23 +0000 (Sun, 15 Feb 2009) Log Message: ----------- committing work for the night. still working on implementing a good class hierarchy to support different lock configurations. Modified Paths: -------------- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/AbstractLock.java rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/CommonLock.java rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/Locking.java rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/RVMThread.java rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/ThinEagerDeflateLock.java rvmroot/branches/RVM-791/working-15440/rvm/src-generated/vm-configuration/LockConfig.template Added Paths: ----------- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/AbstractLockPlan.java rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/CommonLockPlan.java rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/CommonThinLock.java rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/CommonThinLockPlan.java rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/EagerDeflateThinLockPlan.java Modified: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/AbstractLock.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/AbstractLock.java 2009-02-15 02:46:33 UTC (rev 15444) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/AbstractLock.java 2009-02-15 08:03:23 UTC (rev 15445) @@ -30,7 +30,7 @@ /** * Abstract baseclass for all locks. */ -public abstract class AbstractLock implements Constants { +public abstract class AbstractLock implements Constants, ThinLockConstants { public abstract boolean isActive(); @@ -40,12 +40,6 @@ public abstract void unlockHeavy(); - public abstract int enqueueWaitingAndUnlockCompletely(RVMThread toWait); - - public abstract boolean isWaiting(RVMThread t); - - public abstract void removeFromWaitQueue(RVMThread wasWaiting); - public abstract void setOwnerId(int id); public abstract int getOwnerId(); @@ -54,20 +48,6 @@ public abstract int getRecursionCount(); - public int unlockHeavyCompletely() { - int result=getRecursionCount(); - setRecursionCount(1); - unlockHeavy(); - return result; - } - - public static void relock(Object o,int recCount) { - ObjectModel.genericLock(o); - if (recCount!=1) { - ObjectModel.getHeavyLock(o,true).setRecursionCount(recCount); - } - } - public abstract Object getLockedObject(); public abstract void setLockedObject(Object o); Added: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/AbstractLockPlan.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/AbstractLockPlan.java (rev 0) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/AbstractLockPlan.java 2009-02-15 08:03:23 UTC (rev 15445) @@ -0,0 +1,57 @@ +/* + * This file is part of the Jikes RVM project (http://jikesrvm.org). + * + * This file is licensed to You under the Common Public License (CPL); + * You may not use this file except in compliance with the License. You + * may obtain a copy of the License at + * + * http://www.opensource.org/licenses/cpl1.0.php + * + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. + */ +package org.jikesrvm.scheduler; + +import org.jikesrvm.VM; +import org.jikesrvm.Services; +import org.jikesrvm.classloader.RVMMethod; +import org.jikesrvm.compilers.common.CompiledMethods; +import org.jikesrvm.objectmodel.ThinLockConstants; +import org.jikesrvm.runtime.Magic; +import org.vmmagic.pragma.Inline; +import org.vmmagic.pragma.NoInline; +import org.vmmagic.pragma.Uninterruptible; +import org.vmmagic.pragma.Unpreemptible; +import org.vmmagic.unboxed.Address; +import org.vmmagic.unboxed.Offset; +import org.vmmagic.unboxed.Word; + +/** + * Abstract base-class for the global state of the current lock implementation. + */ +@Uninterruptible +public abstract class AbstractLockPlan implements Constants, ThinLockConstants { + public abstract void init(); + + public abstract void boot(); + + public abstract void inlineLock(Object o,int lockOffset); + + public abstract void inlineUnlock(Object o,int lockOffset); + + public abstract void lock(Object o,int lockOffset); + + public abstract void unlock(Object o,int lockOffset); + + public abstract boolean holdsLock(Ojbect o,Offset lockOffset,RVMThread thread); + + public abstract AbstractLock getHeavyLock(Object o,Offset lockOffset,boolean create); + + public abstract void waitImpl(Object o, boolean hasTimeout, long whenWakeupNanos); + public abstract void notify(Object o); + public abstract void notifyAll(Object o); + + public abstract int countLocksHeldByThread(RVMThread t); +} + + Modified: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/CommonLock.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/CommonLock.java 2009-02-15 02:46:33 UTC (rev 15444) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/CommonLock.java 2009-02-15 08:03:23 UTC (rev 15445) @@ -46,18 +46,21 @@ protected abstract void lockWaiting(); protected abstract void unlockWaiting(); - public int enqueueWaitingAndUnlockCompletely(RVMThread toWait) { + protected abstract boolean isWaiting(RVMThread t); + protected abstract void removeFromWaitQueue(RVMThread wasWaiting); + + protected int enqueueWaitingAndUnlockCompletely(RVMThread toWait) { lockWaiting(); waiting.enqueue(toWait); unlockWaiting(); return unlockHeavyCompletely(); } - public boolean isWaiting(RVMThread t) { + protected boolean isWaiting(RVMThread t) { return waiting.isQueued(t); } - public void removeFromWaitQueue(RVMThread wasWaiting) { + protected void removeFromWaitQueue(RVMThread wasWaiting) { if (isWaiting(wasWaiting)) { lockWaiting(); waiting.remove(wasWaiting); @@ -65,6 +68,13 @@ } } + protected int unlockHeavyCompletely() { + int result=getRecursionCount(); + setRecursionCount(1); + unlockHeavy(); + return result; + } + public void setOwnerId(int id) { ownerId=id; } Added: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/CommonLockPlan.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/CommonLockPlan.java (rev 0) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/CommonLockPlan.java 2009-02-15 08:03:23 UTC (rev 15445) @@ -0,0 +1,198 @@ +/* + * This file is part of the Jikes RVM project (http://jikesrvm.org). + * + * This file is licensed to You under the Common Public License (CPL); + * You may not use this file except in compliance with the License. You + * may obtain a copy of the License at + * + * http://www.opensource.org/licenses/cpl1.0.php + * + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. + */ +package org.jikesrvm.scheduler; + +import org.jikesrvm.VM; +import org.jikesrvm.Services; +import org.jikesrvm.classloader.RVMMethod; +import org.jikesrvm.compilers.common.CompiledMethods; +import org.jikesrvm.objectmodel.ThinLockConstants; +import org.jikesrvm.runtime.Magic; +import org.vmmagic.pragma.Inline; +import org.vmmagic.pragma.NoInline; +import org.vmmagic.pragma.Uninterruptible; +import org.vmmagic.pragma.Unpreemptible; +import org.vmmagic.unboxed.Address; +import org.vmmagic.unboxed.Offset; +import org.vmmagic.unboxed.Word; + +@Uninterruptible +public abstract class CommonLockPlan extends AbstractLockPlan { + public static final boolean STATS = false; + + // Statistics + + /** Number of lock operations */ + protected static int lockOperations; + /** Number of unlock operations */ + protected static int unlockOperations; + /** Number of deflations */ + protected static int deflations; + + protected static int fastLocks; + protected static int slowLocks; + + public void init() { + // do nothing ... real action happens in subclasses + } + + protected void relock(Object o,int recCount) { + ObjectModel.genericLock(o); + if (recCount!=1) { + ObjectModel.getHeavyLock(o,true).setRecursionCount(recCount); + } + } + + // FIXME: why the fuck are we passing lockOffsets around? + public abstract CommonLock getHeavyLock(Object o, Offset lockOffset, boolean create); + + public void waitImpl(Object o, boolean hasTimeout, long whenWakeupNanos) { + RVMThread t=RVMThread.getCurrentThread(); + boolean throwInterrupt = false; + Throwable throwThis = null; + if (t.asyncThrowable != null) { + throwThis = t.asyncThrowable; + t.asyncThrowable = null; + } else if (!holdsLock(o, this)) { + throw new IllegalMonitorStateException("waiting on " + o); + } else if (t.hasInterrupt) { + throwInterrupt = true; + t.hasInterrupt = false; + } else { + waiting = hasTimeout ? Waiting.TIMED_WAITING : Waiting.WAITING; + // get lock for object + Lock l = (CommonLock)getHeavyLock(o, true); + // this thread is supposed to own the lock on o + if (VM.VerifyAssertions) + VM._assert(l.getOwnerId() == getLockingId()); + + // release the lock and enqueue waiting + int waitCount=l.enqueueWaitingAndUnlockCompletely(this); + + // block + monitor().lock(); + while (l.isWaiting(this) && !hasInterrupt && asyncThrowable == null && + (!hasTimeout || sysCall.sysNanoTime() < whenWakeupNanos)) { + if (hasTimeout) { + monitor().timedWaitAbsoluteNicely(whenWakeupNanos); + } else { + monitor().waitNicely(); + } + } + // figure out if anything special happened while we were blocked + if (hasInterrupt) { + throwInterrupt = true; + hasInterrupt = false; + } + if (asyncThrowable != null) { + throwThis = asyncThrowable; + asyncThrowable = null; + } + monitor().unlock(); + l.removeFromWaitQueue(this); + // reacquire the lock, restoring the recursion count. note that the + // lock associated with the object may have changed (been deflated and + // reinflated) so we must start anew + ObjectModel.genericLock(o); + waitObject = null; + if (waitCount != 1) { // reset recursion count + Lock l2 = ObjectModel.getHeavyLock(o, true); + l2.setRecursionCount(waitCount); + } + waiting = Waiting.RUNNABLE; + } + // check if we should exit in a special way + if (throwThis != null) { + RuntimeEntrypoints.athrow(throwThis); + } + if (throwInterrupt) { + RuntimeEntrypoints.athrow(new InterruptedException("sleep interrupted")); + } + } + + /**************************************************************************** + * Statistics + */ + + @Interruptible + public void boot() { + if (STATS) { + Callbacks.addExitMonitor(new Lock.ExitMonitor()); + Callbacks.addAppRunStartMonitor(new Lock.AppRunStartMonitor()); + } + } + + protected void initStats() { + lockOperations = 0; + unlockOperations = 0; + deflations = 0; + fastLocks = 0; + slowLocks = 0; + } + + protected void reportStats() { + int totalLocks = lockOperations + ThinLock.fastLocks + ThinLock.slowLocks; + + RVMThread.dumpStats(); + VM.sysWrite(" notifyAll operations\n"); + VM.sysWrite("FatLocks: "); + VM.sysWrite(lockOperations); + VM.sysWrite(" locks"); + Services.percentage(lockOperations, totalLocks, "all lock operations"); + VM.sysWrite("FatLocks: "); + VM.sysWrite(unlockOperations); + VM.sysWrite(" unlock operations\n"); + VM.sysWrite("FatLocks: "); + VM.sysWrite(deflations); + VM.sysWrite(" deflations\n"); + + VM.sysWrite("ThinLocks: "); + VM.sysWrite(fastLocks); + VM.sysWrite(" fast locks"); + Services.percentage(fastLocks, value, "all lock operations"); + VM.sysWrite("ThinLocks: "); + VM.sysWrite(slowLocks); + VM.sysWrite(" slow locks"); + Services.percentage(slowLocks, value, "all lock operations"); + VM.sysWriteln(); + + // FIXME: move to subclass + VM.sysWrite("lock availability stats: "); + VM.sysWriteInt(globalLocksAllocated); + VM.sysWrite(" locks allocated, "); + VM.sysWriteInt(globalLocksFreed); + VM.sysWrite(" locks freed, "); + VM.sysWriteInt(globalFreeLocks); + VM.sysWrite(" free locks\n"); + } + + /** + * Initialize counts in preparation for gathering statistics + */ + private static final class AppRunStartMonitor implements Callbacks.AppRunStartMonitor { + public void notifyAppRunStart(String app, int value) { + ((CommonLockPlan)LockConfig.selectedPlan).initStats(); + } + } + + /** + * Report statistics at the end of execution. + */ + private static final class ExitMonitor implements Callbacks.ExitMonitor { + public void notifyExit(int value) { + ((CommonLockPlan)LockConfig.selectedPlan).reportStats(); + } + } +} + + Added: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/CommonThinLock.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/CommonThinLock.java (rev 0) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/CommonThinLock.java 2009-02-15 08:03:23 UTC (rev 15445) @@ -0,0 +1,34 @@ +/* + * This file is part of the Jikes RVM project (http://jikesrvm.org). + * + * This file is licensed to You under the Common Public License (CPL); + * You may not use this file except in compliance with the License. You + * may obtain a copy of the License at + * + * http://www.opensource.org/licenses/cpl1.0.php + * + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. + */ +package org.jikesrvm.scheduler; + +import org.jikesrvm.VM; +import org.jikesrvm.Services; +import org.jikesrvm.classloader.RVMMethod; +import org.jikesrvm.compilers.common.CompiledMethods; +import org.jikesrvm.objectmodel.ThinLockConstants; +import org.jikesrvm.runtime.Magic; +import org.vmmagic.pragma.Inline; +import org.vmmagic.pragma.NoInline; +import org.vmmagic.pragma.Uninterruptible; +import org.vmmagic.pragma.Unpreemptible; +import org.vmmagic.unboxed.Address; +import org.vmmagic.unboxed.Offset; +import org.vmmagic.unboxed.Word; + +@Uninterruptible +public abstract class CommonThinLock extends CommonLock { + // nothing here for now +} + + Added: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/CommonThinLockPlan.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/CommonThinLockPlan.java (rev 0) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/CommonThinLockPlan.java 2009-02-15 08:03:23 UTC (rev 15445) @@ -0,0 +1,128 @@ +/* + * This file is part of the Jikes RVM project (http://jikesrvm.org). + * + * This file is licensed to You under the Common Public License (CPL); + * You may not use this file except in compliance with the License. You + * may obtain a copy of the License at + * + * http://www.opensource.org/licenses/cpl1.0.php + * + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. + */ +package org.jikesrvm.scheduler; + +import org.jikesrvm.VM; +import org.jikesrvm.Callbacks; +import org.jikesrvm.Constants; +import org.jikesrvm.Services; +import org.jikesrvm.objectmodel.ObjectModel; +import org.jikesrvm.objectmodel.ThinLockConstants; +import org.jikesrvm.runtime.Magic; +import org.vmmagic.pragma.Inline; +import org.vmmagic.pragma.Interruptible; +import org.vmmagic.pragma.Uninterruptible; +import org.vmmagic.pragma.UnpreemptibleNoWarn; +import org.vmmagic.pragma.Unpreemptible; +import org.vmmagic.unboxed.Word; +import org.vmmagic.unboxed.Offset; + +public abstract class CommonThinLockPlan extends CommonLockPlan { + /** + * Return the lock index for a given lock word. Assert valid index + * ranges, that the fat lock bit is set, and that the lock entry + * exists. + * + * @param lockWord The lock word whose lock index is being established + * @return the lock index corresponding to the lock workd. + */ + @Inline + protected int getLockIndex(Word lockWord) { + int index = lockWord.and(TL_LOCK_ID_MASK).rshl(TL_LOCK_ID_SHIFT).toInt(); + if (VM.VerifyAssertions) { + if (!(index > 0 && index < Lock.numLocks())) { + VM.sysWrite("Lock index out of range! Word: "); VM.sysWrite(lockWord); + VM.sysWrite(" index: "); VM.sysWrite(index); + VM.sysWrite(" locks: "); VM.sysWrite(Lock.numLocks()); + VM.sysWriteln(); + } + VM._assert(index > 0 && index < Lock.numLocks()); // index is in range + VM._assert(!lockWord.and(TL_FAT_LOCK_MASK).isZero()); // fat lock bit is set + VM._assert(Lock.getLock(index) != null); // the lock is actually there + } + return index; + } + + /** + * Obtains a lock on the indicated object. Abbreviated light-weight + * locking sequence inlined by the optimizing compiler for the + * prologue of synchronized methods and for the + * <code>monitorenter</code> bytecode. + * + * @param o the object to be locked + * @param lockOffset the offset of the thin lock word in the object. + * @see org.jikesrvm.compilers.opt.hir2lir.ExpandRuntimeServices + */ + @Inline + @Unpreemptible("Become another thread when lock is contended, don't preempt in other cases") + static void inlineLock(Object o, Offset lockOffset) { + Word old = Magic.prepareWord(o, lockOffset); + if (old.rshl(TL_THREAD_ID_SHIFT).isZero()) { + // implies that fatbit == 0 & threadid == 0 + int threadId = RVMThread.getCurrentThread().getLockingId(); + if (Magic.attemptWord(o, lockOffset, old, old.or(Word.fromIntZeroExtend(threadId)))) { + Magic.isync(); // don't use stale prefetched data in monitor + if (STATS) fastLocks++; + return; // common case: o is now locked + } + } + lock(o, lockOffset); // uncommon case: default to out-of-line lock() + } + + /** + * Releases the lock on the indicated object. Abreviated + * light-weight unlocking sequence inlined by the optimizing + * compiler for the epilogue of synchronized methods and for the + * <code>monitorexit</code> bytecode. + * + * @param o the object to be unlocked + * @param lockOffset the offset of the thin lock word in the object. + * @see org.jikesrvm.compilers.opt.hir2lir.ExpandRuntimeServices + */ + @Inline + @Unpreemptible("No preemption normally, but may raise exceptions") + static void inlineUnlock(Object o, Offset lockOffset) { + Word old = Magic.prepareWord(o, lockOffset); + Word threadId = Word.fromIntZeroExtend(RVMThread.getCurrentThread().getLockingId()); + if (old.xor(threadId).rshl(TL_LOCK_COUNT_SHIFT).isZero()) { // implies that fatbit == 0 && count == 0 && lockid == me + Magic.sync(); // memory barrier: subsequent locker will see previous writes + if (Magic.attemptWord(o, lockOffset, old, old.and(TL_UNLOCK_MASK))) { + return; // common case: o is now unlocked + } + } + unlock(o, lockOffset); // uncommon case: default to non inlined unlock() + } + + /** + * @param obj an object + * @param lockOffset the offset of the thin lock word in the object. + * @param thread a thread + * @return <code>true</code> if the lock on obj at offset lockOffset is currently owned + * by thread <code>false</code> if it is not. + */ + public boolean holdsLock(Object obj, Offset lockOffset, RVMThread thread) { + int tid = thread.getLockingId(); + Word bits = Magic.getWordAtOffset(obj, lockOffset); + if (bits.and(TL_FAT_LOCK_MASK).isZero()) { + // if locked, then it is locked with a thin lock + return (bits.and(ThinLockConstants.TL_THREAD_ID_MASK).toInt() == tid); + } else { + // if locked, then it is locked with a fat lock + int index = getLockIndex(bits); + Lock l = Lock.getLock(index); + return l != null && l.getOwnerId() == tid; + } + } +} + + Added: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/EagerDeflateThinLockPlan.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/EagerDeflateThinLockPlan.java (rev 0) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/EagerDeflateThinLockPlan.java 2009-02-15 08:03:23 UTC (rev 15445) @@ -0,0 +1,573 @@ +/* + * This file is part of the Jikes RVM project (http://jikesrvm.org). + * + * This file is licensed to You under the Common Public License (CPL); + * You may not use this file except in compliance with the License. You + * may obtain a copy of the License at + * + * http://www.opensource.org/licenses/cpl1.0.php + * + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. + */ +package org.jikesrvm.scheduler; + +import org.jikesrvm.VM; +import org.jikesrvm.Services; +import org.jikesrvm.classloader.RVMMethod; +import org.jikesrvm.compilers.common.CompiledMethods; +import org.jikesrvm.objectmodel.ThinLockConstants; +import org.jikesrvm.runtime.Magic; +import org.vmmagic.pragma.Inline; +import org.vmmagic.pragma.NoInline; +import org.vmmagic.pragma.Uninterruptible; +import org.vmmagic.pragma.Unpreemptible; +import org.vmmagic.unboxed.Address; +import org.vmmagic.unboxed.Offset; +import org.vmmagic.unboxed.Word; + +@Uninterruptible +public class EagerDeflateThinLockPlan extends CommonThinLockPlan { + /** do debug tracing? */ + protected static final boolean trace = false; + /** Control the gathering of statistics */ + public static final boolean STATS = false; + + /** The (fixed) number of entries in the lock table spine */ + protected static final int LOCK_SPINE_SIZE = 128; + /** The log size of each chunk in the spine */ + protected static final int LOG_LOCK_CHUNK_SIZE = 11; + /** The size of each chunk in the spine */ + protected static final int LOCK_CHUNK_SIZE = 1 << LOG_LOCK_CHUNK_SIZE; + /** The mask used to get the chunk-level index */ + protected static final int LOCK_CHUNK_MASK = LOCK_CHUNK_SIZE - 1; + /** The maximum possible number of locks */ + protected static final int MAX_LOCKS = LOCK_SPINE_SIZE * LOCK_CHUNK_SIZE; + /** The number of chunks to allocate on startup */ + protected static final int INITIAL_CHUNKS = 1; + + /** + * Should we give up or persist in the attempt to get a heavy-weight lock, + * if its <code>mutex</code> microlock is held by another procesor. + */ + private static final boolean tentativeMicrolocking = false; + + // Heavy lock table. + + /** The table of locks. */ + private static Lock[][] locks; + /** Used during allocation of locks within the table. */ + private static final SpinLock lockAllocationMutex = new SpinLock(); + /** The number of chunks in the spine that have been physically allocated */ + private static int chunksAllocated; + /** The number of locks allocated (these may either be in use, on a global + * freelist, or on a thread's freelist. */ + private static int nextLockIndex; + + // Global free list. + + /** A global lock free list head */ + private static Lock globalFreeLock; + /** the number of locks held on the global free list. */ + private static int globalFreeLocks; + /** the total number of allocation operations. */ + private static int globalLocksAllocated; + /** the total number of free operations. */ + private static int globalLocksFreed; + + // Statistics + + /** Number of lock operations */ + private static int lockOperations; + /** Number of unlock operations */ + private static int unlockOperations; + /** Number of deflations */ + private static int deflations; + + public void init() { + super.init(); + nextLockIndex = 1; + locks = new Lock[LOCK_SPINE_SIZE][]; + for (int i=0; i < INITIAL_CHUNKS; i++) { + chunksAllocated++; + locks[i] = new Lock[LOCK_CHUNK_SIZE]; + } + if (VM.VerifyAssertions) { + // check that each potential lock is addressable + VM._assert(((MAX_LOCKS - 1) <= + ThinLockConstants.TL_LOCK_ID_MASK.rshl(ThinLockConstants.TL_LOCK_ID_SHIFT).toInt()) || + ThinLockConstants.TL_LOCK_ID_MASK.EQ(Word.fromIntSignExtend(-1))); + } + } + + /** + * Delivers up an unassigned heavy-weight lock. Locks are allocated + * from processor specific regions or lists, so normally no synchronization + * is required to obtain a lock. + * + * Collector threads cannot use heavy-weight locks. + * + * @return a free Lock; or <code>null</code>, if garbage collection is not enabled + */ + @UnpreemptibleNoWarn("The caller is prepared to lose control when it allocates a lock") + static Lock allocate() { + RVMThread me=RVMThread.getCurrentThread(); + if (me.cachedFreeLock != null) { + Lock l = me.cachedFreeLock; + me.cachedFreeLock = null; + if (trace) { + VM.sysWriteln("Lock.allocate: returning ",Magic.objectAsAddress(l), + ", a cached free lock from Thread #",me.getThreadSlot()); + } + return l; + } + + Lock l = null; + while (l == null) { + if (globalFreeLock != null) { + lockAllocationMutex.lock(); + l = globalFreeLock; + if (l != null) { + globalFreeLock = l.nextFreeLock; + l.nextFreeLock = null; + l.active = true; + globalFreeLocks--; + } + lockAllocationMutex.unlock(); + if (trace && l!=null) { + VM.sysWriteln("Lock.allocate: returning ",Magic.objectAsAddress(l), + " from the global freelist for Thread #",me.getThreadSlot()); + } + } else { + l = new Lock(); // may cause thread switch (and processor loss) + lockAllocationMutex.lock(); + if (globalFreeLock == null) { + // ok, it's still correct for us to be adding a new lock + if (nextLockIndex >= MAX_LOCKS) { + VM.sysWriteln("Too many fat locks"); // make MAX_LOCKS bigger? we can keep going?? + VM.sysFail("Exiting VM with fatal error"); + } + l.index = nextLockIndex++; + globalLocksAllocated++; + } else { + l = null; // someone added to the freelist, try again + } + lockAllocationMutex.unlock(); + if (l != null) { + if (l.index >= numLocks()) { + /* We need to grow the table */ + growLocks(l.index); + } + addLock(l); + l.active = true; + /* make sure other processors see lock initialization. + * Note: Derek and I BELIEVE that an isync is not required in the other processor because the lock is newly allocated - Bowen */ + Magic.sync(); + } + if (trace && l!=null) { + VM.sysWriteln("Lock.allocate: returning ",Magic.objectAsAddress(l), + ", a freshly allocated lock for Thread #", + me.getThreadSlot()); + } + } + } + return l; + } + + /** + * Recycles an unused heavy-weight lock. Locks are deallocated + * to processor specific lists, so normally no synchronization + * is required to obtain or release a lock. + */ + protected static void free(Lock l) { + l.active = false; + RVMThread me = RVMThread.getCurrentThread(); + if (me.cachedFreeLock == null) { + if (trace) { + VM.sysWriteln("Lock.free: setting ",Magic.objectAsAddress(l), + " as the cached free lock for Thread #", + me.getThreadSlot()); + } + me.cachedFreeLock = l; + } else { + if (trace) { + VM.sysWriteln("Lock.free: returning ",Magic.objectAsAddress(l), + " to the global freelist for Thread #", + me.getThreadSlot()); + } + returnLock(l); + } + } + static void returnLock(Lock l) { + if (trace) { + VM.sysWriteln("Lock.returnLock: returning ",Magic.objectAsAddress(l), + " to the global freelist for Thread #", + RVMThread.getCurrentThreadSlot()); + } + lockAllocationMutex.lock(); + l.nextFreeLock = globalFreeLock; + globalFreeLock = l; + globalFreeLocks++; + globalLocksFreed++; + lockAllocationMutex.unlock(); + } + + /** + * Grow the locks table by allocating a new spine chunk. + */ + @UnpreemptibleNoWarn("The caller is prepared to lose control when it allocates a lock") + static void growLocks(int id) { + int spineId = id >> LOG_LOCK_CHUNK_SIZE; + if (spineId >= LOCK_SPINE_SIZE) { + VM.sysFail("Cannot grow lock array greater than maximum possible index"); + } + for(int i=chunksAllocated; i <= spineId; i++) { + if (locks[i] != null) { + /* We were beaten to it */ + continue; + } + + /* Allocate the chunk */ + Lock[] newChunk = new Lock[LOCK_CHUNK_SIZE]; + + lockAllocationMutex.lock(); + if (locks[i] == null) { + /* We got here first */ + locks[i] = newChunk; + chunksAllocated++; + } + lockAllocationMutex.unlock(); + } + } + + /** + * Return the number of lock slots that have been allocated. This provides + * the range of valid lock ids. + */ + public static int numLocks() { + return chunksAllocated * LOCK_CHUNK_SIZE; + } + + /** + * Read a lock from the lock table by id. + * + * @param id The lock id + * @return The lock object. + */ + @Inline + public static Lock getLock(int id) { + return locks[id >> LOG_LOCK_CHUNK_SIZE][id & LOCK_CHUNK_MASK]; + } + + /** + * Add a lock to the lock table + * + * @param l The lock object + */ + @Uninterruptible + public static void addLock(Lock l) { + Lock[] chunk = locks[l.index >> LOG_LOCK_CHUNK_SIZE]; + int index = l.index & LOCK_CHUNK_MASK; + Services.setArrayUninterruptible(chunk, index, l); + } + + /** + * Dump the lock table. + */ + public static void dumpLocks() { + for (int i = 0; i < numLocks(); i++) { + Lock l = getLock(i); + if (l != null) { + l.dump(); + } + } + VM.sysWrite("\n"); + VM.sysWrite("lock availability stats: "); + VM.sysWriteInt(globalLocksAllocated); + VM.sysWrite(" locks allocated, "); + VM.sysWriteInt(globalLocksFreed); + VM.sysWrite(" locks freed, "); + VM.sysWriteInt(globalFreeLocks); + VM.sysWrite(" free locks\n"); + } + + /** + * Count number of locks held by thread + * @param id the thread locking ID we're counting for + * @return number of locks held + */ + public int countLocksHeldByThread(int id) { + int count=0; + for (int i = 0; i < numLocks(); i++) { + Lock l = getLock(i); + if (l != null && l.active && l.ownerId == id && l.recursionCount > 0) { + count++; + } + } + return count; + } + + /** + * Obtains a lock on the indicated object. Light-weight locking + * sequence for the prologue of synchronized methods and for the + * <code>monitorenter</code> bytecode. + * + * @param o the object to be locked + * @param lockOffset the offset of the thin lock word in the object. + */ + @NoInline + @Unpreemptible("Become another thread when lock is contended, don't preempt in other cases") + public void lock(Object o, Offset lockOffset) { + major: + while (true) { // repeat only if attempt to lock a promoted lock fails + int retries = retryLimit; + Word threadId = Word.fromIntZeroExtend(RVMThread.getCurrentThread().getLockingId()); + while (0 != retries--) { // repeat if there is contention for thin lock + Word old = Magic.prepareWord(o, lockOffset); + Word id = old.and(TL_THREAD_ID_MASK.or(TL_FAT_LOCK_MASK)); + if (id.isZero()) { // o isn't locked + if (Magic.attemptWord(o, lockOffset, old, old.or(threadId))) { + Magic.isync(); // don't use stale prefetched data in monitor + if (STATS) slowLocks++; + break major; // lock succeeds + } + continue; // contention, possibly spurious, try again + } + if (id.EQ(threadId)) { // this thread has o locked already + Word changed = old.toAddress().plus(TL_LOCK_COUNT_UNIT).toWord(); // update count + if (changed.and(TL_LOCK_COUNT_MASK).isZero()) { // count wrapped around (most unlikely), make heavy lock + while (!inflateAndLock(o, lockOffset)) { // wait for a lock to become available + RVMThread.yield(); + } + break major; // lock succeeds (note that lockHeavy has issued an isync) + } + if (Magic.attemptWord(o, lockOffset, old, changed)) { + Magic.isync(); // don't use stale prefetched data in monitor !!TODO: is this isync required? + if (STATS) slowLocks++; + break major; // lock succeeds + } + continue; // contention, probably spurious, try again (TODO!! worry about this) + } + + if (!(old.and(TL_FAT_LOCK_MASK).isZero())) { // o has a heavy lock + int index = getLockIndex(old); + if (getLock(index).lockHeavy(o)) { + break major; // lock succeeds (note that lockHeavy has issued an isync) + } + // heavy lock failed (deflated or contention for system lock) + RVMThread.yield(); + continue major; // try again + } + // real contention: wait (hope other thread unlocks o), try again + if (traceContention) { // for performance tuning only (see section 5) + Address fp = Magic.getFramePointer(); + fp = Magic.getCallerFramePointer(fp); + int mid = Magic.getCompiledMethodID(fp); + RVMMethod m1 = CompiledMethods.getCompiledMethod(mid).getMethod(); + fp = Magic.getCallerFramePointer(fp); + mid = Magic.getCompiledMethodID(fp); + RVMMethod m2 = CompiledMethods.getCompiledMethod(mid).getMethod(); + String s = m1.getDeclaringClass() + "." + m1.getName() + " " + m2.getDeclaringClass() + "." + m2.getName(); + RVMThread.trace(Magic.getObjectType(o).toString(), s, -2 - retries); + } + if (0 != retries) { + RVMThread.yield(); // wait, hope o gets unlocked + } + } + // create a heavy lock for o and lock it + if (inflateAndLock(o, lockOffset)) break; + } + // o has been locked, must return before an exception can be thrown + } + + /** + * Releases the lock on the indicated object. Light-weight unlocking + * sequence for the epilogue of synchronized methods and for the + * <code>monitorexit</code> bytecode. + * + * @param o the object to be locked + * @param lockOffset the offset of the thin lock word in the object. + */ + @NoInline + @Unpreemptible("No preemption normally, but may raise exceptions") + static void unlock(Object o, Offset lockOffset) { + Magic.sync(); // prevents stale data from being seen by next owner of the lock + while (true) { // spurious contention detected + Word old = Magic.prepareWord(o, lockOffset); + Word id = old.and(TL_THREAD_ID_MASK.or(TL_FAT_LOCK_MASK)); + Word threadId = Word.fromIntZeroExtend(RVMThread.getCurrentThread().getLockingId()); + if (id.NE(threadId)) { // not normal case + if (!(old.and(TL_FAT_LOCK_MASK).isZero())) { // o has a heavy lock + Lock.getLock(getLockIndex(old)).unlockHeavy(o); + // note that unlockHeavy has issued a sync + return; + } + RVMThread.trace("Lock", "unlock error: thin lock word = ", old.toAddress()); + RVMThread.trace("Lock", "unlock error: thin lock word = ", Magic.objectAsAddress(o)); + // RVMThread.trace("Lock", RVMThread.getCurrentThread().toString(), 0); + RVMThread.raiseIllegalMonitorStateException("thin unlocking", o); + } + if (old.and(TL_LOCK_COUNT_MASK).isZero()) { // get count, 0 is the last lock + Word changed = old.and(TL_UNLOCK_MASK); + if (Magic.attemptWord(o, lockOffset, old, changed)) { + return; // unlock succeeds + } + continue; + } + // more than one lock + // decrement recursion count + Word changed = old.toAddress().minus(TL_LOCK_COUNT_UNIT).toWord(); + if (Magic.attemptWord(o, lockOffset, old, changed)) { + return; // unlock succeeds + } + } + } + + //////////////////////////////////////////////////////////////// + /// Support for inflating (and deflating) heavy-weight locks /// + //////////////////////////////////////////////////////////////// + + /** + * Promotes a light-weight lock to a heavy-weight lock. Note: the + * object is question will normally be locked by another thread, + * or it may be unlocked. If there is already a heavy-weight lock + * on this object, that lock is returned. + * + * @param o the object to get a heavy-weight lock + * @param lockOffset the offset of the thin lock word in the object. + * @return the heavy-weight lock on this object + */ + @Unpreemptible + private static Lock inflate(Object o, Offset lockOffset) { + RVMThread.enterLockingPath(); + if (VM.VerifyAssertions) { + VM._assert(holdsLock(o, lockOffset, RVMThread.getCurrentThread())); + // this assertions is just plain wrong. + //VM._assert((Magic.getWordAtOffset(o, lockOffset).and(TL_FAT_LOCK_MASK).isZero())); + } + Lock l = Lock.allocate(); + if (VM.VerifyAssertions) { + VM._assert(l != null); // inflate called by wait (or notify) which shouldn't be called during GC + } + Lock rtn = attemptToInflate(o, lockOffset, l); + if (rtn == l) + l.mutex.unlock(); + RVMThread.leaveLockingPath(); + return rtn; + } + + /** + * Promotes a light-weight lock to a heavy-weight lock and locks it. + * Note: the object in question will normally be locked by another + * thread, or it may be unlocked. If there is already a + * heavy-weight lock on this object, that lock is returned. + * + * @param o the object to get a heavy-weight lock + * @param lockOffset the offset of the thin lock word in the object. + * @return whether the object was successfully locked + */ + @Unpreemptible + private static boolean inflateAndLock(Object o, Offset lockOffset) { + Lock l = Lock.allocate(); + if (l == null) return false; // can't allocate locks during GC + Lock rtn = attemptToInflate(o, lockOffset, l); + if (l != rtn) { + l = rtn; + l.mutex.lock(); + } + return l.lockHeavyLocked(o); + } + + /** + * Promotes a light-weight lock to a heavy-weight lock. + * + * @param o the object to get a heavy-weight lock + * @param lockOffset the offset of the thin lock word in the object. + * @return whether the object was successfully locked + */ + private static Lock attemptToInflate(Object o, Offset lockOffset, Lock l) { + RVMThread.enterLockingPath(); + Word old; + l.mutex.lock(); + do { + old = Magic.prepareWord(o, lockOffset); + // check to see if another thread has already created a fat lock + if (!(old.and(TL_FAT_LOCK_MASK).isZero())) { // already a fat lock in place + if (Lock.trace) { + VM.sysWriteln("Thread #",RVMThread.getCurrentThreadSlot(), + ": freeing lock ",Magic.objectAsAddress(l), + " because we had a double-inflate"); + } + Lock.free(l); + l.mutex.unlock(); + l = Lock.getLock(getLockIndex(old)); + RVMThread.leaveLockingPath(); + return l; + } + Word locked = TL_FAT_LOCK_MASK.or(Word.fromIntZeroExtend(l.index).lsh(TL_LOCK_ID_SHIFT)); + Word changed = locked.or(old.and(TL_UNLOCK_MASK)); + if (VM.VerifyAssertions) VM._assert(getLockIndex(changed) == l.index); + if (Magic.attemptWord(o, lockOffset, old, changed)) { + l.setLockedObject(o); + l.setOwnerId(old.and(TL_THREAD_ID_MASK).toInt()); + if (l.getOwnerId() != 0) { + l.setRecursionCount(old.and(TL_LOCK_COUNT_MASK).rshl(TL_LOCK_COUNT_SHIFT).toInt() + 1); + } + RVMThread.leaveLockingPath(); + return l; + } + // contention detected, try again + } while (true); + } + + static void deflate(Object o, Offset lockOffset, Lock l) { + if (VM.VerifyAssertions) { + Word old = Magic.getWordAtOffset(o, lockOffset); + VM._assert(!(old.and(TL_FAT_LOCK_MASK).isZero())); + VM._assert(l == Lock.getLock(getLockIndex(old))); + } + Word old; + do { + old = Magic.prepareWord(o, lockOffset); + } while (!Magic.attemptWord(o, lockOffset, old, old.and(TL_UNLOCK_MASK))); + } + + /** + * Obtains the heavy-weight lock, if there is one, associated with the + * indicated object. Returns <code>null</code>, if there is no + * heavy-weight lock associated with the object. + * + * @param o the object from which a lock is desired + * @param lockOffset the offset of the thin lock word in the object. + * @param create if true, create heavy lock if none found + * @return the heavy-weight lock on the object (if any) + */ + @Unpreemptible + static Lock getHeavyLock(Object o, Offset lockOffset, boolean create) { + Word old = Magic.getWordAtOffset(o, lockOffset); + if (!(old.and(TL_FAT_LOCK_MASK).isZero())) { // already a fat lock in place + return Lock.getLock(getLockIndex(old)); + } else if (create) { + return inflate(o, lockOffset); + } else { + return null; + } + + } + + /** + * Number of times a thread yields before inflating the lock on a + * object to a heavy-weight lock. The current value was for the + * portBOB benchmark on a 12-way SMP (AIX) in the Fall of '99. This + * is almost certainly not the optimal value. + */ + private static final int retryLimit = 40; // (-1 is effectively infinity) + + /** + * Should we trace lockContention to enable debugging? + */ + private static final boolean traceContention = false; + +} + + Modified: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/Locking.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/Locking.java 2009-02-15 02:46:33 UTC (rev 15444) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/Locking.java 2009-02-15 08:03:23 UTC (rev 15445) @@ -46,7 +46,7 @@ @Entrypoint @Unpreemptible("Become another thread when lock is contended, don't preempt in other cases") static void inlineLock(Object o, Offset lockOffset) { - LockConfig.Selected.inlineLock(o,lockOffset); + LockConfig.selectedPlan.inlineLock(o,lockOffset); } /** @@ -63,7 +63,7 @@ @Entrypoint @Unpreemptible("No preemption normally, but may raise exceptions") static void inlineUnlock(Object o, Offset lockOffset) { - LockConfig.Selected.inlineUnlock(o,lockOffset); + LockConfig.selectedPlan.inlineUnlock(o,lockOffset); } /** @@ -77,7 +77,7 @@ @NoInline @Unpreemptible("Become another thread when lock is contended, don't preempt in other cases") public static void lock(Object o, Offset lockOffset) { - LockConfig.Selected.lock(o,lockOffset); + LockConfig.selectedPlan.lock(o,lockOffset); } /** @@ -91,7 +91,7 @@ @NoInline @Unpreemptible("No preemption normally, but may raise exceptions") public static void unlock(Object o, Offset lockOffset) { - LockConfig.Selected.unlock(o,lockOffset); + LockConfig.selectedPlan.unlock(o,lockOffset); } /** @@ -102,7 +102,7 @@ * by thread <code>false</code> if it is not. */ public static boolean holdsLock(Object obj, Offset lockOffset, RVMThread thread) { - return LockConfig.Selected.holdsLock(obj,lockOffset,thread); + return LockConfig.selectedPlan.holdsLock(obj,lockOffset,thread); } /** @@ -116,9 +116,23 @@ * @return the heavy-weight lock on the object (if any) */ @Unpreemptible - public static Lock getHeavyLock(Object o, Offset lockOffset, boolean create) { - return LockConfig.Selected.getHeavyLock(o,lockOffset,create); + public static AbstractLock getHeavyLock(Object o, + Offset lockOffset, + boolean create) { + return LockConfig.selectedPlan.getHeavyLock(o,lockOffset,create); } + + public static int countLocksHeldByThread(RVMThread t) { + return LockConfig.selectedPlan.countLocksHeldByThread(t); + } + + public static void init() { + LockConfig.selectedPlan.init(); + } + + public static void boot() { + LockConfig.selectedPlan.boot(); + } } Modified: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/RVMThread.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/RVMThread.java 2009-02-15 02:46:33 UTC (rev 15444) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/RVMThread.java 2009-02-15 08:03:23 UTC (rev 15445) @@ -1094,7 +1094,7 @@ // long-standing lisp bug) BootRecord.the_boot_record.dumpStackAndDieOffset = Entrypoints.dumpStackAndDieMethod.getOffset(); - Lock.init(); + LockConfig.selectedPlan.init(); } public void assertAcceptableStates(int expected) { @@ -2548,7 +2548,7 @@ } if (VM.VerifyAssertions) VM._assert(cachedFreeLock.mutex.latestContender != this); - Lock.returnLock(cachedFreeLock); + LockConfig.selectedPlan.returnLock(cachedFreeLock); cachedFreeLock = null; } @@ -2722,66 +2722,7 @@ @Interruptible void waitImpl(Object o, boolean hasTimeout, long whenWakeupNanos) { - boolean throwInterrupt = false; - Throwable throwThis = null; - if (asyncThrowable != null) { - throwThis = asyncThrowable; - asyncThrowable = null; - } else if (!ObjectModel.holdsLock(o, this)) { - throw new IllegalMonitorStateException("waiting on " + o); - } else if (hasInterrupt) { - throwInterrupt = true; - hasInterrupt = false; - } else { - waiting = hasTimeout ? Waiting.TIMED_WAITING : Waiting.WAITING; - // get lock for object - Lock l = ObjectModel.getHeavyLock(o, true); - // this thread is supposed to own the lock on o - if (VM.VerifyAssertions) - VM._assert(l.getOwnerId() == getLockingId()); - - // release the lock and enqueue waiting - int waitCount=l.enqueueWaitingAndUnlockCompletely(this); - - // block - monitor().lock(); - while (l.isWaiting(this) && !hasInterrupt && asyncThrowable == null && - (!hasTimeout || sysCall.sysNanoTime() < whenWakeupNanos)) { - if (hasTimeout) { - monitor().timedWaitAbsoluteNicely(whenWakeupNanos); - } else { - monitor().waitNicely(); - } - } - // figure out if anything special happened while we were blocked - if (hasInterrupt) { - throwInterrupt = true; - hasInterrupt = false; - } - if (asyncThrowable != null) { - throwThis = asyncThrowable; - asyncThrowable = null; - } - monitor().unlock(); - l.removeFromWaitQueue(this); - // reacquire the lock, restoring the recursion count. note that the - // lock associated with the object may have changed (been deflated and - // reinflated) so we must start anew - ObjectModel.genericLock(o); - waitObject = null; - if (waitCount != 1) { // reset recursion count - Lock l2 = ObjectModel.getHeavyLock(o, true); - l2.setRecursionCount(waitCount); - } - waiting = Waiting.RUNNABLE; - } - // check if we should exit in a special way - if (throwThis != null) { - RuntimeEntrypoints.athrow(throwThis); - } - if (throwInterrupt) { - RuntimeEntrypoints.athrow(new InterruptedException("sleep interrupted")); - } + LockConfig.selectedPlan.waitImpl(o, hasTimeout, whenWakeupNanos); } /** @@ -4743,7 +4684,7 @@ VM.sysWrite("\n"); VM.sysWrite("\n-- Locks in use --\n"); - Lock.dumpLocks(); + LockConfig.selectedPlan.dumpLocks(); VM.sysWriteln("Dumping stack of active thread\n"); dumpStack(); Modified: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/ThinEagerDeflateLock.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/ThinEagerDeflateLock.java 2009-02-15 02:46:33 UTC (rev 15444) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/ThinEagerDeflateLock.java 2009-02-15 08:03:23 UTC (rev 15445) @@ -418,14 +418,6 @@ static void notifyExit(int value) { if (!STATS) return; - VM.sysWrite("ThinLocks: "); - VM.sysWrite(fastLocks); - VM.sysWrite(" fast locks"); - Services.percentage(fastLocks, value, "all lock operations"); - VM.sysWrite("ThinLocks: "); - VM.sysWrite(slowLocks); - VM.sysWrite(" slow locks"); - Services.percentage(slowLocks, value, "all lock operations"); } } Modified: rvmroot/branches/RVM-791/working-15440/rvm/src-generated/vm-configuration/LockConfig.template =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src-generated/vm-configuration/LockConfig.template 2009-02-15 02:46:33 UTC (rev 15444) +++ rvmroot/branches/RVM-791/working-15440/rvm/src-generated/vm-configuration/LockConfig.template 2009-02-15 08:03:23 UTC (rev 15445) @@ -16,4 +16,7 @@ public static final int SELECTED = LockConfigs.@_SELECTED_@; public static final class Selected extends @_SELECTED_@Lock; + public static final class SelectedPlan extends @_SELECTED_@LockPlan; + + public static final selectedPlan = new SelectedPlan(); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <pi...@us...> - 2009-02-16 01:19:55
|
Revision: 15448 http://jikesrvm.svn.sourceforge.net/jikesrvm/?rev=15448&view=rev Author: pizlo Date: 2009-02-16 01:19:46 +0000 (Mon, 16 Feb 2009) Log Message: ----------- compile error fixes Modified Paths: -------------- rvmroot/branches/RVM-791/working-15440/rvm/src/Dummy.java rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/VM.java rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/objectmodel/JavaHeader.java rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/objectmodel/ObjectModel.java rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/RVMThread.java rvmroot/branches/RVM-791/working-15440/rvm/src-generated/vm-configuration/LockConfig.template Modified: rvmroot/branches/RVM-791/working-15440/rvm/src/Dummy.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/Dummy.java 2009-02-16 01:02:05 UTC (rev 15447) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/Dummy.java 2009-02-16 01:19:46 UTC (rev 15448) @@ -14,7 +14,6 @@ import org.jikesrvm.runtime.DynamicLinker; import org.jikesrvm.runtime.MathConstants; import org.jikesrvm.runtime.Reflection; -import org.jikesrvm.scheduler.Lock; /** * Dummy class containing enough references to force java compiler @@ -29,7 +28,7 @@ static DynamicLinker c; static org.jikesrvm.jni.JNIFunctions d; static Reflection e; - static Lock f; + static org.jikesrvm.scheduler.LockConfig f; static org.vmmagic.pragma.SaveVolatile i; static org.jikesrvm.mm.mminterface.MemoryManager l; static RecompilationManager o; Modified: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/VM.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/VM.java 2009-02-16 01:02:05 UTC (rev 15447) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/VM.java 2009-02-16 01:19:46 UTC (rev 15448) @@ -38,7 +38,7 @@ import org.jikesrvm.runtime.SysCall; import static org.jikesrvm.runtime.SysCall.sysCall; -import org.jikesrvm.scheduler.Lock; +import org.jikesrvm.scheduler.LockConfig; import org.jikesrvm.scheduler.MainThread; import org.jikesrvm.scheduler.Synchronization; import org.jikesrvm.scheduler.RVMThread; @@ -265,7 +265,7 @@ runClassInitializer("java.security.AccessController"); } if (verboseBoot >= 1) VM.sysWriteln("Booting Lock"); - Lock.boot(); + LockConfig.selectedPlan.boot(); // Enable multiprocessing. // Among other things, after this returns, GC and dynamic class loading are enabled. Modified: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/objectmodel/JavaHeader.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/objectmodel/JavaHeader.java 2009-02-16 01:02:05 UTC (rev 15447) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/objectmodel/JavaHeader.java 2009-02-16 01:19:46 UTC (rev 15448) @@ -22,7 +22,7 @@ import org.jikesrvm.mm.mminterface.MemoryManagerConstants; import org.jikesrvm.runtime.Magic; import org.jikesrvm.runtime.Memory; -import org.jikesrvm.scheduler.Lock; +import org.jikesrvm.scheduler.AbstractLock; import org.jikesrvm.scheduler.Locking; import org.jikesrvm.scheduler.RVMThread; import org.vmmagic.pragma.Inline; @@ -610,7 +610,7 @@ * @return the heavy-weight lock on the object (if any) */ @Unpreemptible("May be interrupted for allocations of locks") - public static Lock getHeavyLock(Object o, boolean create) { + public static AbstractLock getHeavyLock(Object o, boolean create) { return Locking.getHeavyLock(o, STATUS_OFFSET, create); } Modified: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/objectmodel/ObjectModel.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/objectmodel/ObjectModel.java 2009-02-16 01:02:05 UTC (rev 15447) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/objectmodel/ObjectModel.java 2009-02-16 01:19:46 UTC (rev 15448) @@ -20,8 +20,8 @@ import org.jikesrvm.classloader.RVMType; import org.jikesrvm.mm.mminterface.MemoryManager; import org.jikesrvm.runtime.Magic; -import org.jikesrvm.scheduler.Lock; import org.jikesrvm.scheduler.RVMThread; +import org.jikesrvm.scheduler.AbstractLock; import org.vmmagic.pragma.Entrypoint; import org.vmmagic.pragma.Inline; import org.vmmagic.pragma.Interruptible; @@ -497,7 +497,7 @@ * @return the heavy-weight lock on the object (if any) */ @Unpreemptible("May be interrupted for allocations of locks") - public static Lock getHeavyLock(Object o, boolean create) { + public static AbstractLock getHeavyLock(Object o, boolean create) { return JavaHeader.getHeavyLock(o, create); } Modified: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/RVMThread.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/RVMThread.java 2009-02-16 01:02:05 UTC (rev 15447) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/RVMThread.java 2009-02-16 01:19:46 UTC (rev 15448) @@ -181,21 +181,6 @@ be set to true. */ private static final boolean neverKillThreads = false; - /** Generate statistics? */ - private static final boolean STATS = Lock.STATS; - - /** Number of wait operations */ - static int waitOperations; - - /** Number of timed wait operations */ - static int timedWaitOperations; - - /** Number of notify operations */ - static int notifyOperations; - - /** Number of notifyAll operations */ - static int notifyAllOperations; - public static final boolean ALWAYS_LOCK_ON_STATE_TRANSITION = false; /* @@ -2778,20 +2763,7 @@ */ @Interruptible public static void notify(Object o) { - if (STATS) - notifyOperations++; - Lock l = ObjectModel.getHeavyLock(o, false); - if (l == null) - return; - if (l.getOwnerId() != getCurrentThread().getLockingId()) { - raiseIllegalMonitorStateException("notifying", o); - } - l.mutex.lock(); - RVMThread toAwaken = l.waiting.dequeue(); - l.mutex.unlock(); - if (toAwaken != null) { - toAwaken.monitor().lockedBroadcast(); - } + LockConfig.selectedPlan.notify(o); } /** @@ -2802,22 +2774,7 @@ */ @UninterruptibleNoWarn("Never blocks except if there was an error") public static void notifyAll(Object o) { - if (STATS) - notifyAllOperations++; - Lock l = ObjectModel.getHeavyLock(o, false); - if (l == null) - return; - if (l.getOwnerId() != getCurrentThread().getLockingId()) { - raiseIllegalMonitorStateException("notifyAll", o); - } - for (;;) { - l.mutex.lock(); - RVMThread toAwaken = l.waiting.dequeue(); - l.mutex.unlock(); - if (toAwaken == null) - break; - toAwaken.monitor().lockedBroadcast(); - } + LockConfig.selectedPlan.notifyAll(o); } public void stop(Throwable cause) { Modified: rvmroot/branches/RVM-791/working-15440/rvm/src-generated/vm-configuration/LockConfig.template =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src-generated/vm-configuration/LockConfig.template 2009-02-16 01:02:05 UTC (rev 15447) +++ rvmroot/branches/RVM-791/working-15440/rvm/src-generated/vm-configuration/LockConfig.template 2009-02-16 01:19:46 UTC (rev 15448) @@ -15,8 +15,8 @@ public final class LockConfig { public static final int SELECTED = LockConfigs.@_SELECTED_@; - public static final class Selected extends @_SELECTED_@Lock; - public static final class SelectedPlan extends @_SELECTED_@LockPlan; + public static final class Selected extends @_SELECTED_@Lock {} + public static final class SelectedPlan extends @_SELECTED_@LockPlan {} public static final selectedPlan = new SelectedPlan(); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <pi...@us...> - 2009-02-16 01:22:59
|
Revision: 15449 http://jikesrvm.svn.sourceforge.net/jikesrvm/?rev=15449&view=rev Author: pizlo Date: 2009-02-16 01:22:55 +0000 (Mon, 16 Feb 2009) Log Message: ----------- more compile error fixes Modified Paths: -------------- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/AbstractLockPlan.java rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/EagerDeflateThinLockPlan.java rvmroot/branches/RVM-791/working-15440/rvm/src-generated/vm-configuration/LockConfig.template Modified: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/AbstractLockPlan.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/AbstractLockPlan.java 2009-02-16 01:19:46 UTC (rev 15448) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/AbstractLockPlan.java 2009-02-16 01:22:55 UTC (rev 15449) @@ -13,6 +13,7 @@ package org.jikesrvm.scheduler; import org.jikesrvm.VM; +import org.jikesrvm.Constants; import org.jikesrvm.Services; import org.jikesrvm.classloader.RVMMethod; import org.jikesrvm.compilers.common.CompiledMethods; Modified: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/EagerDeflateThinLockPlan.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/EagerDeflateThinLockPlan.java 2009-02-16 01:19:46 UTC (rev 15448) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/EagerDeflateThinLockPlan.java 2009-02-16 01:22:55 UTC (rev 15449) @@ -176,18 +176,18 @@ * @return the heavy-weight lock on this object */ @Unpreemptible - private static Lock inflate(Object o, Offset lockOffset) { + private static EagerDeflateThinLock inflate(Object o, Offset lockOffset) { RVMThread.enterLockingPath(); if (VM.VerifyAssertions) { VM._assert(holdsLock(o, lockOffset, RVMThread.getCurrentThread())); // this assertions is just plain wrong. //VM._assert((Magic.getWordAtOffset(o, lockOffset).and(TL_FAT_LOCK_MASK).isZero())); } - Lock l = allocate(); + EagerDeflateThinLock l = (EagerDeflateThinLock)allocate(); if (VM.VerifyAssertions) { VM._assert(l != null); // inflate called by wait (or notify) which shouldn't be called during GC } - Lock rtn = attemptToInflate(o, lockOffset, l); + EagerDeflateThinLock rtn = attemptToInflate(o, lockOffset, l); if (rtn == l) l.mutex.unlock(); RVMThread.leaveLockingPath(); @@ -223,7 +223,9 @@ * @param lockOffset the offset of the thin lock word in the object. * @return whether the object was successfully locked */ - private static Lock attemptToInflate(Object o, Offset lockOffset, Lock l) { + private static EagerDeflateThinLock attemptToInflate(Object o, + Offset lockOffset, + EagerDeflateThinLock l) { RVMThread.enterLockingPath(); Word old; l.mutex.lock(); @@ -258,7 +260,7 @@ } while (true); } - static void deflate(Object o, Offset lockOffset, Lock l) { + static void deflate(Object o, Offset lockOffset, EagerDeflateThinLock l) { if (VM.VerifyAssertions) { Word old = Magic.getWordAtOffset(o, lockOffset); VM._assert(!(old.and(TL_FAT_LOCK_MASK).isZero())); @@ -281,7 +283,7 @@ * @return the heavy-weight lock on the object (if any) */ @Unpreemptible - static Lock getHeavyLock(Object o, Offset lockOffset, boolean create) { + static EagerDeflateThinLock getHeavyLock(Object o, Offset lockOffset, boolean create) { Word old = Magic.getWordAtOffset(o, lockOffset); if (!(old.and(TL_FAT_LOCK_MASK).isZero())) { // already a fat lock in place return getLock(getLockIndex(old)); Modified: rvmroot/branches/RVM-791/working-15440/rvm/src-generated/vm-configuration/LockConfig.template =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src-generated/vm-configuration/LockConfig.template 2009-02-16 01:19:46 UTC (rev 15448) +++ rvmroot/branches/RVM-791/working-15440/rvm/src-generated/vm-configuration/LockConfig.template 2009-02-16 01:22:55 UTC (rev 15449) @@ -18,5 +18,5 @@ public static final class Selected extends @_SELECTED_@Lock {} public static final class SelectedPlan extends @_SELECTED_@LockPlan {} - public static final selectedPlan = new SelectedPlan(); + public static final SelectedPlan selectedPlan = new SelectedPlan(); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <pi...@us...> - 2009-02-23 04:51:55
|
Revision: 15495 http://jikesrvm.svn.sourceforge.net/jikesrvm/?rev=15495&view=rev Author: pizlo Date: 2009-02-23 04:51:52 +0000 (Mon, 23 Feb 2009) Log Message: ----------- figured out where the slow-downs are coming from. now I have to find ways around them. Modified Paths: -------------- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/compilers/opt/bc2ir/BC2IR.java rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/CommonLock.java rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/CommonLockPlan.java rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/CommonThinLockPlan.java rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/EagerDeflateThinLock.java rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/EagerDeflateThinLockPlan.java rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/Locking.java rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/RVMThread.java rvmroot/branches/RVM-791/working-15440/rvm/src-generated/vm-configuration/LockConfig.template Modified: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/compilers/opt/bc2ir/BC2IR.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/compilers/opt/bc2ir/BC2IR.java 2009-02-22 20:49:43 UTC (rev 15494) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/compilers/opt/bc2ir/BC2IR.java 2009-02-23 04:51:52 UTC (rev 15495) @@ -3673,6 +3673,7 @@ */ public boolean do_NullCheck(Operand ref) { if (gc.noNullChecks()) { + setCurrentGuard(new TrueGuardOperand()); return false; } if (ref.isDefinitelyNull()) { @@ -3767,6 +3768,7 @@ public boolean do_BoundsCheck(Operand ref, Operand index) { // Unsafely eliminate all bounds checks if (gc.noBoundsChecks()) { + setCurrentGuard(new TrueGuardOperand()); return false; } RegisterOperand guard = gc.temps.makeTempValidation(); Modified: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/CommonLock.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/CommonLock.java 2009-02-22 20:49:43 UTC (rev 15494) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/CommonLock.java 2009-02-23 04:51:52 UTC (rev 15495) @@ -24,6 +24,7 @@ import org.vmmagic.pragma.Uninterruptible; import org.vmmagic.pragma.UnpreemptibleNoWarn; import org.vmmagic.pragma.Unpreemptible; +import org.vmmagic.pragma.NoNullCheck; import org.vmmagic.unboxed.Word; import org.vmmagic.unboxed.Offset; Modified: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/CommonLockPlan.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/CommonLockPlan.java 2009-02-22 20:49:43 UTC (rev 15494) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/CommonLockPlan.java 2009-02-23 04:51:52 UTC (rev 15495) @@ -31,6 +31,7 @@ import org.vmmagic.pragma.Unpreemptible; import org.vmmagic.pragma.UnpreemptibleNoWarn; import org.vmmagic.pragma.Entrypoint; +import org.vmmagic.pragma.NoNullCheck; import org.vmmagic.unboxed.Address; import org.vmmagic.unboxed.Offset; import org.vmmagic.unboxed.Word; @@ -160,29 +161,40 @@ } @Inline + @NoNullCheck protected final CommonLock allocate() { + if (PROFILE) RVMThread.enterLockingPath(); + RVMThread me=RVMThread.getCurrentThread(); if (VM.VerifyAssertions) { - VM._assert(me.cachedFreeLockID>=-1); + VM._assert(!me.noMoreLocking); // inflating locks from GC would be awkward VM._assert(!me.isGCThread()); } + CommonLock result; + if (STATS) Synchronization.fetchAndAdd( this,Entrypoints.commonLockLocksAllocatedField.getOffset(),1); - CommonLock result=new LockConfig.Selected(); - - if (me.cachedFreeLockID!=-1) { - result.id=me.cachedFreeLockID; - me.cachedFreeLockID=-1; + if (LockConfig.CACHE_LOCKS && me.cachedFreeLock!=null) { + result=me.cachedFreeLock; + me.cachedFreeLock=null; } else { - allocateSlow(result); + result=new LockConfig.Selected(); + + if (!LockConfig.CACHE_LOCKS && me.cachedFreeLockID!=-1) { + result.id=me.cachedFreeLockID; + me.cachedFreeLockID=-1; + } else { + allocateSlow(result); + } } if (VM.VerifyAssertions) VM._assert(result.id>0); + if (PROFILE) RVMThread.leaveLockingPath(); return result; } @@ -230,6 +242,7 @@ } @Unpreemptible + @NoNullCheck protected final void addLock(CommonLock l) { locks[l.id]=l; } @@ -243,16 +256,24 @@ @Inline protected final void free(CommonLock l) { + if (PROFILE) RVMThread.enterLockingPath(); RVMThread me=RVMThread.getCurrentThread(); l.lockedObject=null; locks[l.id]=null; - if (me.cachedFreeLockID==-1) { + if (LockConfig.CACHE_LOCKS && me.cachedFreeLock==null) { + me.cachedFreeLock=l; + } else if (!LockConfig.CACHE_LOCKS && me.cachedFreeLockID==-1) { me.cachedFreeLockID=l.id; } else { returnLockID(l.id); } + if (PROFILE) RVMThread.leaveLockingPath(); } + protected final void returnLock(CommonLock l) { + returnLockID(l.id); + } + @NoInline protected final void returnLockID(int id) { if (STATS) Synchronization.fetchAndAdd( @@ -284,6 +305,7 @@ */ @Inline @Unpreemptible + @NoNullCheck public final AbstractLock getLock(int id) { return locks[id]; } Modified: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/CommonThinLockPlan.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/CommonThinLockPlan.java 2009-02-22 20:49:43 UTC (rev 15494) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/CommonThinLockPlan.java 2009-02-23 04:51:52 UTC (rev 15495) @@ -24,6 +24,7 @@ import org.vmmagic.pragma.Uninterruptible; import org.vmmagic.pragma.UnpreemptibleNoWarn; import org.vmmagic.pragma.Unpreemptible; +import org.vmmagic.pragma.NoNullCheck; import org.vmmagic.unboxed.Word; import org.vmmagic.unboxed.Offset; @@ -70,27 +71,41 @@ * @see org.jikesrvm.compilers.opt.hir2lir.ExpandRuntimeServices */ @Inline + @NoNullCheck public final void inlineLock(Object o, Offset lockOffset) { - Word old = Magic.prepareWord(o, lockOffset); - Word id = old.and(TL_THREAD_ID_MASK.or(TL_FAT_LOCK_MASK)); - if (id.isZero()) { - // implies that fatbit == 0 & threadid == 0 - int threadId = RVMThread.getCurrentThread().getLockingId(); - if (Magic.attemptWord(o, lockOffset, old, old.or(Word.fromIntZeroExtend(threadId)))) { - Magic.isync(); // don't use stale prefetched data in monitor - if (HEAVY_STATS) fastLocks++; - return; // common case: o is now locked + if (!LockConfig.USE_REC_FASTPATH) { + Word old = Magic.prepareWord(o, lockOffset); + if (old.rshl(TL_THREAD_ID_SHIFT).isZero()) { + // implies that fatbit == 0 & threadid == 0 + int threadId = RVMThread.getCurrentThread().getLockingId(); + if (Magic.attemptWord(o, lockOffset, old, old.or(Word.fromIntZeroExtend(threadId)))) { + Magic.isync(); // don't use stale prefetched data in monitor + if (HEAVY_STATS) fastLocks++; + return; // common case: o is now locked + } } } else { - Word threadId = Word.fromIntSignExtend(RVMThread.getCurrentThread().getLockingId()); - if (id.EQ(threadId)) { - Word changed=old.toAddress().plus(TL_LOCK_COUNT_UNIT).toWord(); - if (!changed.and(TL_LOCK_COUNT_MASK).isZero() && - Magic.attemptWord(o, lockOffset, old, changed)) { - Magic.isync(); + Word old = Magic.prepareWord(o, lockOffset); + Word id = old.and(TL_THREAD_ID_MASK.or(TL_FAT_LOCK_MASK)); + if (id.isZero()) { + // implies that fatbit == 0 & threadid == 0 + int threadId = RVMThread.getCurrentThread().getLockingId(); + if (Magic.attemptWord(o, lockOffset, old, old.or(Word.fromIntZeroExtend(threadId)))) { + Magic.isync(); // don't use stale prefetched data in monitor if (HEAVY_STATS) fastLocks++; - return; + return; // common case: o is now locked } + } else { + Word threadId = Word.fromIntSignExtend(RVMThread.getCurrentThread().getLockingId()); + if (id.EQ(threadId)) { + Word changed=old.toAddress().plus(TL_LOCK_COUNT_UNIT).toWord(); + if (!changed.and(TL_LOCK_COUNT_MASK).isZero() && + Magic.attemptWord(o, lockOffset, old, changed)) { + Magic.isync(); + if (HEAVY_STATS) fastLocks++; + return; + } + } } } lock(o, lockOffset); // uncommon case: default to out-of-line lock() @@ -107,23 +122,35 @@ * @see org.jikesrvm.compilers.opt.hir2lir.ExpandRuntimeServices */ @Inline + @NoNullCheck public final void inlineUnlock(Object o, Offset lockOffset) { - Word old = Magic.prepareWord(o, lockOffset); - Word id = old.and(TL_THREAD_ID_MASK.or(TL_FAT_LOCK_MASK)); - Word threadId = Word.fromIntZeroExtend(RVMThread.getCurrentThread().getLockingId()); - if (id.EQ(threadId)) { - Magic.sync(); - if (old.and(TL_LOCK_COUNT_MASK).isZero()) { - // release lock - Word changed = old.and(TL_UNLOCK_MASK); - if (Magic.attemptWord(o, lockOffset, old, changed)) { - return; + if (!LockConfig.USE_REC_FASTPATH) { + Word old = Magic.prepareWord(o, lockOffset); + Word threadId = Word.fromIntZeroExtend(RVMThread.getCurrentThread().getLockingId()); + if (old.xor(threadId).rshl(TL_LOCK_COUNT_SHIFT).isZero()) { // implies that fatbit == 0 && count == 0 && lockid == me + Magic.sync(); // memory barrier: subsequent locker will see previous writes + if (Magic.attemptWord(o, lockOffset, old, old.and(TL_UNLOCK_MASK))) { + return; // common case: o is now unlocked } - } else { - // decrement count - Word changed = old.toAddress().minus(TL_LOCK_COUNT_UNIT).toWord(); - if (Magic.attemptWord(o, lockOffset, old, changed)) { - return; // unlock succeeds + } + } else { + Word old = Magic.prepareWord(o, lockOffset); + Word id = old.and(TL_THREAD_ID_MASK.or(TL_FAT_LOCK_MASK)); + Word threadId = Word.fromIntZeroExtend(RVMThread.getCurrentThread().getLockingId()); + if (id.EQ(threadId)) { + Magic.sync(); + if (old.and(TL_LOCK_COUNT_MASK).isZero()) { + // release lock + Word changed = old.and(TL_UNLOCK_MASK); + if (Magic.attemptWord(o, lockOffset, old, changed)) { + return; + } + } else { + // decrement count + Word changed = old.toAddress().minus(TL_LOCK_COUNT_UNIT).toWord(); + if (Magic.attemptWord(o, lockOffset, old, changed)) { + return; // unlock succeeds + } } } } @@ -138,6 +165,7 @@ * by thread <code>false</code> if it is not. */ @Unpreemptible + @NoNullCheck public final boolean holdsLock(Object obj, Offset lockOffset, RVMThread thread) { int tid = thread.getLockingId(); Word bits = Magic.getWordAtOffset(obj, lockOffset); Modified: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/EagerDeflateThinLock.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/EagerDeflateThinLock.java 2009-02-22 20:49:43 UTC (rev 15494) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/EagerDeflateThinLock.java 2009-02-23 04:51:52 UTC (rev 15495) @@ -24,6 +24,7 @@ import org.vmmagic.pragma.Uninterruptible; import org.vmmagic.pragma.Unpreemptible; import org.vmmagic.pragma.Entrypoint; +import org.vmmagic.pragma.NoNullCheck; import org.vmmagic.unboxed.Address; import org.vmmagic.unboxed.Offset; import org.vmmagic.unboxed.Word; @@ -52,6 +53,7 @@ * @param o the object to be locked * @return true, if the lock succeeds; false, otherwise */ + @NoNullCheck public final boolean lockHeavy(Object o) { if (CommonLockPlan.PROFILE) RVMThread.enterLockingPath(); if (EagerDeflateThinLockPlan.tentativeMicrolocking) { @@ -70,6 +72,8 @@ /** Complete the task of acquiring the heavy lock, assuming that the mutex is already acquired (locked). */ + @NoNullCheck + @Inline protected final boolean lockHeavyLocked(Object o) { if (CommonLockPlan.PROFILE) RVMThread.enterLockingPath(); if (lockedObject != o) { // lock disappeared before we got here @@ -106,6 +110,7 @@ * * @param o the object to be unlocked */ + @NoNullCheck public final void unlockHeavy() { if (CommonLockPlan.PROFILE) RVMThread.enterLockingPath(); boolean deflated = false; @@ -147,6 +152,7 @@ * * @param o the object from which this lock is to be disassociated */ + @NoNullCheck protected final void deflate(Object o, Offset lockOffset) { if (VM.VerifyAssertions) { VM._assert(lockedObject == o); Modified: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/EagerDeflateThinLockPlan.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/EagerDeflateThinLockPlan.java 2009-02-22 20:49:43 UTC (rev 15494) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/EagerDeflateThinLockPlan.java 2009-02-23 04:51:52 UTC (rev 15495) @@ -23,6 +23,7 @@ import org.vmmagic.pragma.Interruptible; import org.vmmagic.pragma.Uninterruptible; import org.vmmagic.pragma.Unpreemptible; +import org.vmmagic.pragma.NoNullCheck; import org.vmmagic.unboxed.Address; import org.vmmagic.unboxed.Offset; import org.vmmagic.unboxed.Word; @@ -54,6 +55,7 @@ * @param lockOffset the offset of the thin lock word in the object. */ @NoInline + @NoNullCheck public final void lock(Object o, Offset lockOffset) { major: while (true) { // repeat only if attempt to lock a promoted lock fails @@ -128,6 +130,7 @@ * @param lockOffset the offset of the thin lock word in the object. */ @NoInline + @NoNullCheck public final void unlock(Object o, Offset lockOffset) { Magic.sync(); // prevents stale data from being seen by next owner of the lock while (true) { // spurious contention detected @@ -178,6 +181,7 @@ * @param lockOffset the offset of the thin lock word in the object. * @return the heavy-weight lock on this object */ + @NoNullCheck protected final EagerDeflateThinLock inflate(Object o, Offset lockOffset) { if (PROFILE) RVMThread.enterLockingPath(); if (VM.VerifyAssertions) { @@ -206,6 +210,7 @@ * @param lockOffset the offset of the thin lock word in the object. * @return whether the object was successfully locked */ + @NoNullCheck protected final boolean inflateAndLock(Object o, Offset lockOffset) { EagerDeflateThinLock l = (EagerDeflateThinLock)Magic.eatCast(allocateActivateAndAdd()); if (l == null) return false; // can't allocate locks during GC @@ -228,6 +233,7 @@ * @return the inflated lock; either the one you gave, or another one, if the lock * was inflated by some other thread. */ + @NoNullCheck protected final EagerDeflateThinLock attemptToInflate(Object o, Offset lockOffset, EagerDeflateThinLock l) { @@ -272,6 +278,7 @@ } while (true); } + @NoNullCheck protected final void deflate(Object o, Offset lockOffset, EagerDeflateThinLock l) { if (VM.VerifyAssertions) { Word old = Magic.getWordAtOffset(o, lockOffset); @@ -294,6 +301,7 @@ * @param create if true, create heavy lock if none found * @return the heavy-weight lock on the object (if any) */ + @NoNullCheck public final AbstractLock getHeavyLock(Object o, Offset lockOffset, boolean create) { Word old = Magic.getWordAtOffset(o, lockOffset); if (!(old.and(TL_FAT_LOCK_MASK).isZero())) { // already a fat lock in place Modified: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/Locking.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/Locking.java 2009-02-22 20:49:43 UTC (rev 15494) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/Locking.java 2009-02-23 04:51:52 UTC (rev 15495) @@ -23,6 +23,7 @@ import org.vmmagic.pragma.NoInline; import org.vmmagic.pragma.Uninterruptible; import org.vmmagic.pragma.Unpreemptible; +import org.vmmagic.pragma.NoNullCheck; import org.vmmagic.unboxed.Address; import org.vmmagic.unboxed.Offset; import org.vmmagic.unboxed.Word; @@ -43,6 +44,7 @@ */ @Inline @Entrypoint + @NoNullCheck static void inlineLock(Object o, Offset lockOffset) { LockConfig.selectedPlan.inlineLock(o,lockOffset); } @@ -59,6 +61,7 @@ */ @Inline @Entrypoint + @NoNullCheck static void inlineUnlock(Object o, Offset lockOffset) { LockConfig.selectedPlan.inlineUnlock(o,lockOffset); } @@ -72,6 +75,7 @@ * @param lockOffset the offset of the thin lock word in the object. */ @NoInline + @NoNullCheck public static void lock(Object o, Offset lockOffset) { LockConfig.selectedPlan.lock(o,lockOffset); } @@ -85,6 +89,7 @@ * @param lockOffset the offset of the thin lock word in the object. */ @NoInline + @NoNullCheck public static void unlock(Object o, Offset lockOffset) { LockConfig.selectedPlan.unlock(o,lockOffset); } @@ -97,6 +102,7 @@ * by thread <code>false</code> if it is not. */ @Unpreemptible + @NoNullCheck public static boolean holdsLock(Object obj, Offset lockOffset, RVMThread thread) { return LockConfig.selectedPlan.holdsLock(obj,lockOffset,thread); } @@ -111,6 +117,7 @@ * @param create if true, create heavy lock if none found * @return the heavy-weight lock on the object (if any) */ + @NoNullCheck public static AbstractLock getHeavyLock(Object o, Offset lockOffset, boolean create) { Modified: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/RVMThread.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/RVMThread.java 2009-02-22 20:49:43 UTC (rev 15494) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/RVMThread.java 2009-02-23 04:51:52 UTC (rev 15495) @@ -599,8 +599,15 @@ /** * A cached free lock id. */ - public int cachedFreeLockID=-1; + int cachedFreeLockID=-1; + /** + * A cached free lock. + */ + CommonLock cachedFreeLock=null; + + boolean noMoreLocking=false; + /* * Wait/notify fields */ @@ -2499,8 +2506,12 @@ if (LockConfig.selectedPlan instanceof CommonLockPlan && cachedFreeLockID != -1) { ((CommonLockPlan)LockConfig.selectedPlan).returnLockID(cachedFreeLockID); - cachedFreeLockID = -2; } + if (LockConfig.selectedPlan instanceof CommonLockPlan && + cachedFreeLock != null) { + ((CommonLockPlan)LockConfig.selectedPlan).returnLock(cachedFreeLock); + } + noMoreLocking=true; // Switch to uninterruptible portion of termination terminateUnpreemptible(); Modified: rvmroot/branches/RVM-791/working-15440/rvm/src-generated/vm-configuration/LockConfig.template =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src-generated/vm-configuration/LockConfig.template 2009-02-22 20:49:43 UTC (rev 15494) +++ rvmroot/branches/RVM-791/working-15440/rvm/src-generated/vm-configuration/LockConfig.template 2009-02-23 04:51:52 UTC (rev 15495) @@ -15,6 +15,11 @@ public final class LockConfig { public static final int SELECTED = LockConfigs.@_SELECTED_@; + public static final boolean CACHE_LOCKS = + SELECTED==LockConfigs.EagerDeflateThin; + + public static final boolean USE_REC_FASTPATH = false; + public static final class Selected extends @_SELECTED_@Lock {} public static final class SelectedPlan extends @_SELECTED_@LockPlan {} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <pi...@us...> - 2009-02-23 22:30:00
|
Revision: 15498 http://jikesrvm.svn.sourceforge.net/jikesrvm/?rev=15498&view=rev Author: pizlo Date: 2009-02-23 22:29:53 +0000 (Mon, 23 Feb 2009) Log Message: ----------- checkpointing work on further lock refactoring Modified Paths: -------------- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/VM.java rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/AbstractLock.java rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/AbstractLockPlan.java rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/CommonLock.java rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/EagerDeflateThinLock.java rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/EagerDeflateThinLockPlan.java rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/RVMThread.java rvmroot/branches/RVM-791/working-15440/rvm/src-generated/vm-configuration/LockConfig.template Added Paths: ----------- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/AbstractThinLockPlan.java rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/BasicThinLockPlan.java Modified: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/VM.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/VM.java 2009-02-23 22:24:55 UTC (rev 15497) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/VM.java 2009-02-23 22:29:53 UTC (rev 15498) @@ -266,6 +266,7 @@ } if (verboseBoot >= 1) VM.sysWriteln("Booting Lock"); LockConfig.selectedPlan.boot(); + LockConfig.selectedThinPlan.boot(); // Enable multiprocessing. // Among other things, after this returns, GC and dynamic class loading are enabled. @@ -276,6 +277,7 @@ if (verboseBoot >= 1) VM.sysWriteln("Booting Lock"); LockConfig.selectedPlan.lateBoot(); + LockConfig.selectedThinPlan.lateBoot(); if (verboseBoot >= 1) VM.sysWriteln("Setting up boot thread"); RVMThread.getCurrentThread().setupBootJavaThread(); Modified: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/AbstractLock.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/AbstractLock.java 2009-02-23 22:24:55 UTC (rev 15497) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/AbstractLock.java 2009-02-23 22:29:53 UTC (rev 15498) @@ -30,7 +30,7 @@ /** * Abstract baseclass for all locks. */ -public abstract class AbstractLock implements Constants, ThinLockConstants { +public abstract class AbstractLock implements Constants { public abstract boolean isActive(); @@ -62,6 +62,9 @@ public abstract int getRecursionCount(); + @Unpreemptible + public abstract boolean holdsLock(Object o, RVMThread thread); + /** * Get the object currently associated with this lock. This may change * asynchronously and without warning, so you should not rely on this method @@ -100,9 +103,7 @@ VM.sysWrite(" ownerId: "); VM.sysWriteInt(getOwnerId()); - VM.sysWrite(" ("); - VM.sysWriteInt(getOwnerId() >>> ThinLockConstants.TL_THREAD_ID_SHIFT); - VM.sysWrite(") recursionCount: "); + VM.sysWrite(" recursionCount: "); VM.sysWriteInt(getRecursionCount()); VM.sysWriteln(); dumpBlockedThreads(); Modified: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/AbstractLockPlan.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/AbstractLockPlan.java 2009-02-23 22:24:55 UTC (rev 15497) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/AbstractLockPlan.java 2009-02-23 22:29:53 UTC (rev 15498) @@ -31,7 +31,7 @@ /** * Abstract base-class for the global state of the current lock implementation. */ -public abstract class AbstractLockPlan implements Constants, ThinLockConstants { +public abstract class AbstractLockPlan implements Constants { public static AbstractLockPlan instance; public AbstractLockPlan() { @@ -44,52 +44,28 @@ public abstract void lateBoot(); - public abstract void inlineLock(Object o,Offset lockOffset); - public void inlineLock(Object o) { - inlineLock(o, Magic.getObjectType(o).getThinLockOffset()); - } + public abstract AbstractLock inflate(Object o, Offset lockOffset); - public abstract void inlineUnlock(Object o,Offset lockOffset); - public void inlineUnlock(Object o) { - inlineUnlock(o, Magic.getObjectType(o).getThinLockOffset()); + public AbstractLock getLock(Object o, Offset lockOffset) { + Word bits=Magic.getWordAtOffset(o,lockOffset); + if (LockConfig.selectedThinPlan.isFat(bits)) { + int idx=LockConfig.selectedThinPlan.getLockIndex(bits); + if (idx!=0) { + return LockConfig.selectedPlan.getLock(idx); + } + } + return null; } - public abstract void lock(Object o,Offset lockOffset); - public void lock(Object o) { - lock(o, Magic.getObjectType(o).getThinLockOffset()); + public boolean inflateAndLock(Object o, Offset lockOffset) { + LockConfig.Selected l=(LockConfig.Selected)Magic.eatCast(inflate(o, lockOffset)); + if (l!=null) { + return l.lockHeavy(o); + } else { + return false; + } } - - public abstract void unlock(Object o,Offset lockOffset); - public void unlock(Object o) { - unlock(o, Magic.getObjectType(o).getThinLockOffset()); - } - @Unpreemptible - public abstract boolean holdsLock(Object o,Offset lockOffset,RVMThread thread); - @Unpreemptible - public boolean holdsLock(Object o, RVMThread thread) { - return holdsLock(o, Magic.getObjectType(o).getThinLockOffset(), thread); - } - - /** - * Get a heavy lock for an object. Note that it you set create to true, a new heavy - * lock will be created if it did not previously exist. However, some implementations - * may choose to asynchronously deflate locks. The only way to guarantee that a lock - * is not asynchronously deflated is to ensure that it is held, or has someone enqueued - * on its wait list. For this reason, implementations of this method <i>may</i> choose - * to assert that the lock is not "deflatable" (i.e. not held and with nobody enqueued - * for waiting) at the time that the request is made. - */ - public abstract AbstractLock getHeavyLock(Object o,Offset lockOffset,boolean create); - - /** - * Convenience method for getHeavyLock(Object,Offset,boolean), which computes the - * offset automatically. - */ - public AbstractLock getHeavyLock(Object o, boolean create) { - return getHeavyLock(o, Magic.getObjectType(o).getThinLockOffset(), create); - } - public abstract void waitImpl(Object o, boolean hasTimeout, long whenWakeupNanos); public abstract void notify(Object o); Added: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/AbstractThinLockPlan.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/AbstractThinLockPlan.java (rev 0) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/AbstractThinLockPlan.java 2009-02-23 22:29:53 UTC (rev 15498) @@ -0,0 +1,133 @@ +/* + * This file is part of the Jikes RVM project (http://jikesrvm.org). + * + * This file is licensed to You under the Common Public License (CPL); + * You may not use this file except in compliance with the License. You + * may obtain a copy of the License at + * + * http://www.opensource.org/licenses/cpl1.0.php + * + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. + */ +package org.jikesrvm.scheduler; + +import org.jikesrvm.VM; +import org.jikesrvm.Constants; +import org.jikesrvm.Services; +import org.jikesrvm.classloader.RVMMethod; +import org.jikesrvm.compilers.common.CompiledMethods; +import org.jikesrvm.objectmodel.ThinLockConstants; +import org.jikesrvm.runtime.Magic; +import org.vmmagic.pragma.Inline; +import org.vmmagic.pragma.NoInline; +import org.vmmagic.pragma.Uninterruptible; +import org.vmmagic.pragma.Interruptible; +import org.vmmagic.pragma.Unpreemptible; +import org.vmmagic.unboxed.Address; +import org.vmmagic.unboxed.Offset; +import org.vmmagic.unboxed.Word; + +public abstract class AbstractThinLockPlan implements Constants, ThinLockConstants { + public static AbstractThinLockPlan instance; + + public AbstractThinLockPlan() { + instance=this; + } + + public abstract void init(); + + public abstract void boot(); + + public abstract void lateBoot(); + + /** + * Attempt to quickly acquire the lock, and if that fails, call + * lock(). + */ + public abstract void inlineLock(Object o,Offset lockOffset); + public void inlineLock(Object o) { + inlineLock(o, Magic.getObjectType(o).getThinLockOffset()); + } + + /** + * Attempt to quickly release the lock, and if that fails, call + * unlock(). + */ + public abstract void inlineUnlock(Object o,Offset lockOffset); + public void inlineUnlock(Object o) { + inlineUnlock(o, Magic.getObjectType(o).getThinLockOffset()); + } + + // FIXME: just have APIs in AbstractLockPlan for inflating? if we see that + // we have a fat lock, just call AbstractLockPlan.instance.getLock(). if + // we see that we should be inflating, just call + // AbstractLockPlan.instance.inflate(). + + public abstract void lock(Object o, Offset lockOffset); + public void lock(Object o) { + lock(o, Magic.getObjectType(o).getThinLockOffset()); + } + + public abstract void unlock(Object o, Offset lockOffset); + public void unlock(Object o) { + unlock(o, Magic.getObjectType(o).getThinLockOffset()); + } + + @Unpreemptible + public abstract boolean holdsLock(Object o,Offset lockOffset,RVMThread thread); + @Unpreemptible + public boolean holdsLock(Object o, RVMThread thread) { + return holdsLock(o, Magic.getObjectType(o).getThinLockOffset(), thread); + } + + @Unpreemptible + public abstract boolean isFat(Word lockWord); + + /** + * Extract the current fat lock index. This is only valid if the lock + * is fat. + */ + @Unpreemptible + public abstract int getLockIndex(Word lockWord); + + /** + * Extract the current lock owner. This is only valid if the lock is not + * fat. + */ + @Unpreemptible + public abstract int getLockOwner(Word lockWord); + + /** + * Extract the current lock recursion count. This is only valid if the + * lock is held. + */ + @Unpreemptible + public abstract int getRecCount(Word lockWord); + + /** + * Attempt to inflate the thin lock. + */ + @Unpreemptible + public abstract boolean attemptToMarkInflated(Object o, Offset lockOffset, + Word oldLockWord, int lockId); + + /** + * Attempt to deflate the thin lock. This makes the thin lock unlocked + * as well. + */ + @Unpreemptible + public abstract boolean attemptToMarkDeflated(Object o, Offset lockOffset, + Word oldLockWord); + + public final void markDeflated(Object o, Offset lockOffset) { + for (;;) { + Word bits=Magic.getWordAtOffset(o, lockOffset); + if (attemptToMarkDeflated(o, lockOffset, bits)) { + return; + } + } + } +} + + Added: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/BasicThinLockPlan.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/BasicThinLockPlan.java (rev 0) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/BasicThinLockPlan.java 2009-02-23 22:29:53 UTC (rev 15498) @@ -0,0 +1,308 @@ +/* + * This file is part of the Jikes RVM project (http://jikesrvm.org). + * + * This file is licensed to You under the Common Public License (CPL); + * You may not use this file except in compliance with the License. You + * may obtain a copy of the License at + * + * http://www.opensource.org/licenses/cpl1.0.php + * + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. + */ +package org.jikesrvm.scheduler; + +import org.jikesrvm.VM; +import org.jikesrvm.Constants; +import org.jikesrvm.Services; +import org.jikesrvm.classloader.RVMMethod; +import org.jikesrvm.compilers.common.CompiledMethods; +import org.jikesrvm.objectmodel.ThinLockConstants; +import org.jikesrvm.runtime.Magic; +import org.vmmagic.pragma.Inline; +import org.vmmagic.pragma.NoInline; +import org.vmmagic.pragma.Uninterruptible; +import org.vmmagic.pragma.Interruptible; +import org.vmmagic.pragma.Unpreemptible; +import org.vmmagic.unboxed.Address; +import org.vmmagic.unboxed.Offset; +import org.vmmagic.unboxed.Word; + +public class BasicThinLockPlan extends AbstractThinLockPlan { + public static BasicThinLockPlan instance; + + public BasicThinLockPlan() { + instance=this; + } + + public void init() {} + public void boot() {} + public void lateBoot() {} + + /** + * Obtains a lock on the indicated object. Abbreviated light-weight + * locking sequence inlined by the optimizing compiler for the + * prologue of synchronized methods and for the + * <code>monitorenter</code> bytecode. + * + * @param o the object to be locked + * @param lockOffset the offset of the thin lock word in the object. + * @see org.jikesrvm.compilers.opt.hir2lir.ExpandRuntimeServices + */ + @Inline + @NoNullCheck + public final void inlineLock(Object o, Offset lockOffset) { + if (!LockConfig.USE_REC_FASTPATH) { + Word old = Magic.prepareWord(o, lockOffset); + if (old.rshl(TL_THREAD_ID_SHIFT).isZero()) { + // implies that fatbit == 0 & threadid == 0 + int threadId = RVMThread.getCurrentThread().getLockingId(); + if (Magic.attemptWord(o, lockOffset, old, old.or(Word.fromIntZeroExtend(threadId)))) { + Magic.isync(); // don't use stale prefetched data in monitor + if (HEAVY_STATS) fastLocks++; + return; // common case: o is now locked + } + } + } else { + Word old = Magic.prepareWord(o, lockOffset); + Word id = old.and(TL_THREAD_ID_MASK.or(TL_FAT_LOCK_MASK)); + if (id.isZero()) { + // implies that fatbit == 0 & threadid == 0 + int threadId = RVMThread.getCurrentThread().getLockingId(); + if (Magic.attemptWord(o, lockOffset, old, old.or(Word.fromIntZeroExtend(threadId)))) { + Magic.isync(); // don't use stale prefetched data in monitor + if (HEAVY_STATS) fastLocks++; + return; // common case: o is now locked + } + } else { + Word threadId = Word.fromIntSignExtend(RVMThread.getCurrentThread().getLockingId()); + if (id.EQ(threadId)) { + Word changed=old.toAddress().plus(TL_LOCK_COUNT_UNIT).toWord(); + if (!changed.and(TL_LOCK_COUNT_MASK).isZero() && + Magic.attemptWord(o, lockOffset, old, changed)) { + Magic.isync(); + if (HEAVY_STATS) fastLocks++; + return; + } + } + } + } + lock(o, lockOffset); // uncommon case: default to out-of-line lock() + } + + /** + * Releases the lock on the indicated object. Abreviated + * light-weight unlocking sequence inlined by the optimizing + * compiler for the epilogue of synchronized methods and for the + * <code>monitorexit</code> bytecode. + * + * @param o the object to be unlocked + * @param lockOffset the offset of the thin lock word in the object. + * @see org.jikesrvm.compilers.opt.hir2lir.ExpandRuntimeServices + */ + @Inline + @NoNullCheck + public final void inlineUnlock(Object o, Offset lockOffset) { + if (!LockConfig.USE_REC_FASTPATH) { + Word old = Magic.prepareWord(o, lockOffset); + Word threadId = Word.fromIntZeroExtend(RVMThread.getCurrentThread().getLockingId()); + if (old.xor(threadId).rshl(TL_LOCK_COUNT_SHIFT).isZero()) { // implies that fatbit == 0 && count == 0 && lockid == me + Magic.sync(); // memory barrier: subsequent locker will see previous writes + if (Magic.attemptWord(o, lockOffset, old, old.and(TL_UNLOCK_MASK))) { + return; // common case: o is now unlocked + } + } + } else { + Word old = Magic.prepareWord(o, lockOffset); + Word id = old.and(TL_THREAD_ID_MASK.or(TL_FAT_LOCK_MASK)); + Word threadId = Word.fromIntZeroExtend(RVMThread.getCurrentThread().getLockingId()); + if (id.EQ(threadId)) { + Magic.sync(); + if (old.and(TL_LOCK_COUNT_MASK).isZero()) { + // release lock + Word changed = old.and(TL_UNLOCK_MASK); + if (Magic.attemptWord(o, lockOffset, old, changed)) { + return; + } + } else { + // decrement count + Word changed = old.toAddress().minus(TL_LOCK_COUNT_UNIT).toWord(); + if (Magic.attemptWord(o, lockOffset, old, changed)) { + return; // unlock succeeds + } + } + } + } + unlock(o, lockOffset); // uncommon case: default to non inlined unlock() + } + + @NoInline + public void lock(Object o, Offset lockOffset) { + for (;;) { + // the idea: + // - if the lock is uninflated and unclaimed attempt to grab it the thin way + // - if the lock is uninflated and claimed by me, attempt to increase rec count + // - if the lock is uninflated and claimed by someone else, inflate it and + // do the slow path of acquisition + // - if the lock is inflated, grab it. + + Word threadId = Word.fromIntZeroExtend(RVMThread.getCurrentThread().getLockingId()); + Word old = Magic.prepareWord(o, lockOffset); + Word id = old.and(TL_THREAD_ID_MASK.or(TL_FAT_LOCK_MASK)); + if (id.isZero()) { + // lock not held, acquire quickly with rec count == 1 + if (Magic.attemptWord(o, lockOffset, old, old.or(threadId))) { + Magic.isync(); + return; + } + } else if (id.EQ(threadId)) { + // lock held, attempt to increment rec count + Word changed = old.toAddress().plus(TL_LOCK_COUNT_UNIT).toWord(); + if (!changed.and(TL_LOCK_COUNT_MASK).isZero() && + Magic.attemptWord(o, lockOffset, old, changed)) { + Magic.isync(); + return; + } + } else if (!old.and(TL_FAT_LOCK_MASK).isZero()) { + // we have a heavy lock. + LockConfig.Selected l=(LockConfig.Selected) + LockConfig.selectedPlan.getLock(getLockIndexDefinite(old)) + if (l.lockHeavy(o)) { + return; + } // else we grabbed someone else's lock + } else { + // the lock is not fat, is owned by someone else, or else the count wrapped. + // attempt to inflate it (this may fail, in which case we'll just harmlessly + // loop around) and lock it (may also fail, if we get the wrong lock). if it + // succeeds, we're done. + if (LockConfig.selectedPlan.inflateAndLock(o, lockOffset)) { + return; + } + } + } + } + + @NoInline + public void unlock(Object o, Offset lockOffset) { + Magic.sync(); + for (;;) { + Word old = Magic.prepareWord(o, lockOffset); + Word id = old.and(TL_THREAD_ID_MASK.or(TL_FAT_LOCK_MASK)); + Word threadId = Word.fromIntZeroExtend(RVMThread.getCurrentThread().getLockingId()); + if (id.EQ(threadId)) { + if (old.and(TL_LOCK_COUNT_MASK).isZero()) { + // release lock + Word changed = old.and(TL_UNLOCK_MASK); + if (Magic.attemptWord(o, lockOffset, old, changed)) { + return; + } + } else { + // decrement count + Word changed = old.toAddress().minus(TL_LOCK_COUNT_UNIT).toWord(); + if (Magic.attemptWord(o, lockOffset, old, changed)) { + return; // unlock succeeds + } + } + } else { + if (old.and(TL_FAT_LOCK_MASK).isZero()) { + // someone else holds the lock in thin mode and it's not us. that indicates + // bad use of monitorenter/monitorexit + RVMThread.raiseIllegalMonitorStateException("thin unlocking", o); + } + // fat unlock + LockConfig.Selected l=(LockConfig.Selected) + LockConfig.selectedPlan.getLock(getLockIndexDefinite(old)) + l.unlockHeavy(); + return; + } + } + } + + /** + * @param obj an object + * @param lockOffset the offset of the thin lock word in the object. + * @param thread a thread + * @return <code>true</code> if the lock on obj at offset lockOffset is currently owned + * by thread <code>false</code> if it is not. + */ + @Unpreemptible + @NoNullCheck + public final boolean holdsLock(Object obj, Offset lockOffset, RVMThread thread) { + int tid = thread.getLockingId(); + Word bits = Magic.getWordAtOffset(obj, lockOffset); + if (bits.and(TL_FAT_LOCK_MASK).isZero()) { + // if locked, then it is locked with a thin lock + return (bits.and(ThinLockConstants.TL_THREAD_ID_MASK).toInt() == tid); + } else { + // if locked, then it is locked with a fat lock + int index = getLockIndexDefinite(bits); + Lock.Selected l = (Lock.Selected) + Magic.eatCast(LockConfig.selectedPlan.getLock(index)); + return l != null && l.holdsLock(obj, thread); + } + } + + @Inline + @Unpreemptible + public final boolean isFat(Word lockWord) { + return !bits.and(TL_FAT_LOCK_MASK).isZero(); + } + + /** + * Return the lock index for a given lock word. Assert valid index + * ranges, that the fat lock bit is set, and that the lock entry + * exists. + * + * @param lockWord The lock word whose lock index is being established + * @return the lock index corresponding to the lock workd. + */ + @Inline + @Unpreemptible + public final int getLockIndex(Word lockWord) { + int index = lockWord.and(TL_LOCK_ID_MASK).rshl(TL_LOCK_ID_SHIFT).toInt(); + if (VM.VerifyAssertions) { + if (!(index > 0 && index < numLocks())) { + VM.sysWrite("Lock index out of range! Word: "); VM.sysWrite(lockWord); + VM.sysWrite(" index: "); VM.sysWrite(index); + VM.sysWrite(" locks: "); VM.sysWrite(numLocks()); + VM.sysWriteln(); + } + VM._assert(index > 0 && index < numLocks()); // index is in range + VM._assert(!lockWord.and(TL_FAT_LOCK_MASK).isZero()); // fat lock bit is set + } + return index; + } + + @Inline + @Unpreemptible + public final int getLockOwner(Word lockWord) { + return bits.and(ThinLockConstants.TL_THREAD_ID_MASK).toInt(); + } + + @Inline + @Unpreemptible + public final int getRecCount(Word lockWord) { + return old.and(TL_LOCK_COUNT_MASK).rshl(TL_LOCK_COUNT_SHIFT).toInt() + 1; + } + + @Inline + @Unpreemptible + public final boolean attemptToMarkInflated(Object o, Offset lockOffset, + Word oldLockWord, + int lockId) { + Word changed= + TL_FAT_LOCK_MASK.or(Word.fromIntZeroExtend(lockId).lsh(TL_LOCK_ID_SHIFT)) + .or(old.and(TL_UNLOCK_MASK)); + return Synchronization.tryCompareAndSwap(o, lockOffset, oldLockWord, changed); + } + + @Inline + @Unpreemptible + public final boolean attemptToMarkDeflated(Object o, Offset lockOffset, + Word oldLockWord) { + return Synchronization.tryCompareAndSwap( + o, lockOffset, oldLockWord, oldLockWord.and(TL_UNLOCK_MASK)); + } +} + + Modified: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/CommonLock.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/CommonLock.java 2009-02-23 22:24:55 UTC (rev 15497) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/CommonLock.java 2009-02-23 22:29:53 UTC (rev 15498) @@ -126,6 +126,13 @@ return lockedObject; } + public final boolean holdsLock(Object o, RVMThread thread) { + lockState(); + boolean result = (lockedObject == o && thread.getLockingId()==getOwnerId()); + unlockState(); + return result; + } + public final int getLockId() { return id; } Modified: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/EagerDeflateThinLock.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/EagerDeflateThinLock.java 2009-02-23 22:24:55 UTC (rev 15497) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/EagerDeflateThinLock.java 2009-02-23 22:29:53 UTC (rev 15498) @@ -29,7 +29,7 @@ import org.vmmagic.unboxed.Offset; import org.vmmagic.unboxed.Word; -public class EagerDeflateThinLock extends CommonThinLock { +public class EagerDeflateThinLock extends CommonLock { @Entrypoint int mutex; @@ -161,7 +161,7 @@ VM._assert(waitingIsEmpty()); } if (CommonLockPlan.HEAVY_STATS) CommonLockPlan.deflations++; - EagerDeflateThinLockPlan.instance.deflate(o, lockOffset, this); + LockConfig.selectedThinPlan.markDeflated(o, lockOffset); lockedObject = null; EagerDeflateThinLockPlan.instance.free(this); } Modified: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/EagerDeflateThinLockPlan.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/EagerDeflateThinLockPlan.java 2009-02-23 22:24:55 UTC (rev 15497) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/EagerDeflateThinLockPlan.java 2009-02-23 22:29:53 UTC (rev 15498) @@ -28,7 +28,7 @@ import org.vmmagic.unboxed.Offset; import org.vmmagic.unboxed.Word; -public class EagerDeflateThinLockPlan extends CommonThinLockPlan { +public class EagerDeflateThinLockPlan extends CommonLockPlan { public static EagerDeflateThinLockPlan instance; public EagerDeflateThinLockPlan() { @@ -46,127 +46,6 @@ // nothing to do... } - /** - * Obtains a lock on the indicated object. Light-weight locking - * sequence for the prologue of synchronized methods and for the - * <code>monitorenter</code> bytecode. - * - * @param o the object to be locked - * @param lockOffset the offset of the thin lock word in the object. - */ - @NoInline - @NoNullCheck - public final void lock(Object o, Offset lockOffset) { - major: - while (true) { // repeat only if attempt to lock a promoted lock fails - int retries = retryLimit; - Word threadId = Word.fromIntZeroExtend(RVMThread.getCurrentThread().getLockingId()); - while (0 != retries--) { // repeat if there is contention for thin lock - Word old = Magic.prepareWord(o, lockOffset); - Word id = old.and(TL_THREAD_ID_MASK.or(TL_FAT_LOCK_MASK)); - if (id.isZero()) { // o isn't locked - if (Magic.attemptWord(o, lockOffset, old, old.or(threadId))) { - Magic.isync(); // don't use stale prefetched data in monitor - if (HEAVY_STATS) slowLocks++; - break major; // lock succeeds - } - continue; // contention, possibly spurious, try again - } - if (id.EQ(threadId)) { // this thread has o locked already - Word changed = old.toAddress().plus(TL_LOCK_COUNT_UNIT).toWord(); // update count - if (changed.and(TL_LOCK_COUNT_MASK).isZero()) { // count wrapped around (most unlikely), make heavy lock - while (!inflateAndLock(o, lockOffset)) { // wait for a lock to become available - Magic.pause(); - } - break major; // lock succeeds (note that lockHeavy has issued an isync) - } - if (Magic.attemptWord(o, lockOffset, old, changed)) { - Magic.isync(); // don't use stale prefetched data in monitor !!TODO: is this isync required? - if (HEAVY_STATS) slowLocks++; - break major; // lock succeeds - } - continue; // contention, probably spurious, try again (TODO!! worry about this) - } - - if (!(old.and(TL_FAT_LOCK_MASK).isZero())) { // o has a heavy lock - EagerDeflateThinLock l=(EagerDeflateThinLock) - Magic.eatCast(getLock(getLockIndex(old))); - if (l!=null && // could happen if already deflated - l.lockHeavy(o)) { - break major; // lock succeeds (note that lockHeavy has issued an isync) - } - // heavy lock failed (deflated or contention for system lock) - Magic.pause(); - continue major; // try again - } - // real contention: wait (hope other thread unlocks o), try again - if (traceContention) { // for performance tuning only (see section 5) - Address fp = Magic.getFramePointer(); - fp = Magic.getCallerFramePointer(fp); - int mid = Magic.getCompiledMethodID(fp); - RVMMethod m1 = CompiledMethods.getCompiledMethod(mid).getMethod(); - fp = Magic.getCallerFramePointer(fp); - mid = Magic.getCompiledMethodID(fp); - RVMMethod m2 = CompiledMethods.getCompiledMethod(mid).getMethod(); - String s = m1.getDeclaringClass() + "." + m1.getName() + " " + m2.getDeclaringClass() + "." + m2.getName(); - RVMThread.trace(Magic.getObjectType(o).toString(), s, -2 - retries); - } - if (0 != retries) { - Magic.pause(); // wait, hope o gets unlocked - } - } - // create a heavy lock for o and lock it - if (inflateAndLock(o, lockOffset)) break; - } - // o has been locked, must return before an exception can be thrown - } - - /** - * Releases the lock on the indicated object. Light-weight unlocking - * sequence for the epilogue of synchronized methods and for the - * <code>monitorexit</code> bytecode. - * - * @param o the object to be locked - * @param lockOffset the offset of the thin lock word in the object. - */ - @NoInline - @NoNullCheck - public final void unlock(Object o, Offset lockOffset) { - Magic.sync(); // prevents stale data from being seen by next owner of the lock - while (true) { // spurious contention detected - Word old = Magic.prepareWord(o, lockOffset); - Word id = old.and(TL_THREAD_ID_MASK.or(TL_FAT_LOCK_MASK)); - Word threadId = Word.fromIntZeroExtend(RVMThread.getCurrentThread().getLockingId()); - if (id.NE(threadId)) { // not normal case - if (!(old.and(TL_FAT_LOCK_MASK).isZero())) { // o has a heavy lock - // in this case getLock() will return non-null because a lock that is - // held cannot be deflated. ... except if we have illegal use of - // monitorenter/monitorexit. we should do a check anyway. - ((EagerDeflateThinLock)Magic.eatCast(getLock(getLockIndex(old)))).unlockHeavy(); - // note that unlockHeavy has issued a sync - return; - } - RVMThread.trace("Lock", "unlock error: thin lock word = ", old.toAddress()); - RVMThread.trace("Lock", "unlock error: thin lock word = ", Magic.objectAsAddress(o)); - // RVMThread.trace("Lock", RVMThread.getCurrentThread().toString(), 0); - RVMThread.raiseIllegalMonitorStateException("thin unlocking", o); - } - if (old.and(TL_LOCK_COUNT_MASK).isZero()) { // get count, 0 is the last lock - Word changed = old.and(TL_UNLOCK_MASK); - if (Magic.attemptWord(o, lockOffset, old, changed)) { - return; // unlock succeeds - } - continue; - } - // more than one lock - // decrement recursion count - Word changed = old.toAddress().minus(TL_LOCK_COUNT_UNIT).toWord(); - if (Magic.attemptWord(o, lockOffset, old, changed)) { - return; // unlock succeeds - } - } - } - //////////////////////////////////////////////////////////////// /// Support for inflating (and deflating) heavy-weight locks /// //////////////////////////////////////////////////////////////// @@ -182,12 +61,10 @@ * @return the heavy-weight lock on this object */ @NoNullCheck - protected final EagerDeflateThinLock inflate(Object o, Offset lockOffset) { + public final EagerDeflateThinLock inflate(Object o, Offset lockOffset) { if (PROFILE) RVMThread.enterLockingPath(); if (VM.VerifyAssertions) { VM._assert(holdsLock(o, lockOffset, RVMThread.getCurrentThread())); - // this assertions is just plain wrong. - //VM._assert((Magic.getWordAtOffset(o, lockOffset).and(TL_FAT_LOCK_MASK).isZero())); } EagerDeflateThinLock l = (EagerDeflateThinLock)Magic.eatCast(allocateActivateAndAdd()); if (VM.VerifyAssertions) { @@ -241,16 +118,16 @@ Word old; l.lockState(); do { - old = Magic.prepareWord(o, lockOffset); + Word bits = Magic.getWordAtOffset(o, lockOffset); // check to see if another thread has already created a fat lock - if (!(old.and(TL_FAT_LOCK_MASK).isZero())) { // already a fat lock in place + if (LockConfig.selectedThinPlan.isFat(bits)) { if (trace) { VM.sysWriteln("Thread #",RVMThread.getCurrentThreadSlot(), ": freeing lock ",Magic.objectAsAddress(l), " because we had a double-inflate"); } EagerDeflateThinLock result = (EagerDeflateThinLock) - Magic.eatCast(getLock(getLockIndex(old))); + Magic.eatCast(getLock(LockConfig.selectedThinPlan.getLockIndex(old))); if (result==null || result.lockedObject!=o) { continue; /* this is nasty. this will happen when a lock @@ -262,14 +139,12 @@ return result; } if (VM.VerifyAssertions) VM._assert(l!=null); - Word locked = TL_FAT_LOCK_MASK.or(Word.fromIntZeroExtend(l.id).lsh(TL_LOCK_ID_SHIFT)); - Word changed = locked.or(old.and(TL_UNLOCK_MASK)); - if (VM.VerifyAssertions) VM._assert(getLockIndex(changed) == l.id); - if (Magic.attemptWord(o, lockOffset, old, changed)) { + if (LockConfig.selectedThinPlan.attemptToMarkInflated( + o, lockOffset, bits, l.id)) { l.setLockedObject(o); - l.setOwnerId(old.and(TL_THREAD_ID_MASK).toInt()); + l.setOwnerId(LockConfig.selectedThinPlan.getLockOwner(bits)); if (l.getOwnerId() != 0) { - l.setRecursionCount(old.and(TL_LOCK_COUNT_MASK).rshl(TL_LOCK_COUNT_SHIFT).toInt() + 1); + l.setRecursionCount(LockConfig.selectedThinPlan.getRecCount(bits)); } if (PROFILE) RVMThread.leaveLockingPath(); return l; @@ -278,42 +153,7 @@ } while (true); } - @NoNullCheck - protected final void deflate(Object o, Offset lockOffset, EagerDeflateThinLock l) { - if (VM.VerifyAssertions) { - Word old = Magic.getWordAtOffset(o, lockOffset); - VM._assert(!(old.and(TL_FAT_LOCK_MASK).isZero())); - VM._assert(l == getLock(getLockIndex(old))); - } - Word old; - do { - old = Magic.prepareWord(o, lockOffset); - } while (!Magic.attemptWord(o, lockOffset, old, old.and(TL_UNLOCK_MASK))); - } - /** - * Obtains the heavy-weight lock, if there is one, associated with the - * indicated object. Returns <code>null</code>, if there is no - * heavy-weight lock associated with the object. - * - * @param o the object from which a lock is desired - * @param lockOffset the offset of the thin lock word in the object. - * @param create if true, create heavy lock if none found - * @return the heavy-weight lock on the object (if any) - */ - @NoNullCheck - public final AbstractLock getHeavyLock(Object o, Offset lockOffset, boolean create) { - Word old = Magic.getWordAtOffset(o, lockOffset); - if (!(old.and(TL_FAT_LOCK_MASK).isZero())) { // already a fat lock in place - return (EagerDeflateThinLock)Magic.eatCast(getLock(getLockIndex(old))); - } else if (create) { - return inflate(o, lockOffset); - } else { - return null; - } - } - - /** * Number of times a thread yields before inflating the lock on a * object to a heavy-weight lock. The current value was for the * portBOB benchmark on a 12-way SMP (AIX) in the Fall of '99. This Modified: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/RVMThread.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/RVMThread.java 2009-02-23 22:24:55 UTC (rev 15497) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/RVMThread.java 2009-02-23 22:29:53 UTC (rev 15498) @@ -1086,6 +1086,7 @@ BootRecord.the_boot_record.dumpStackAndDieOffset = Entrypoints.dumpStackAndDieMethod.getOffset(); LockConfig.selectedPlan.init(); + LockConfig.selectedThinPlan.init(); } public void assertAcceptableStates(int expected) { Modified: rvmroot/branches/RVM-791/working-15440/rvm/src-generated/vm-configuration/LockConfig.template =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src-generated/vm-configuration/LockConfig.template 2009-02-23 22:24:55 UTC (rev 15497) +++ rvmroot/branches/RVM-791/working-15440/rvm/src-generated/vm-configuration/LockConfig.template 2009-02-23 22:29:53 UTC (rev 15498) @@ -22,6 +22,8 @@ public static final class Selected extends @_SELECTED_@Lock {} public static final class SelectedPlan extends @_SELECTED_@LockPlan {} + public static final class SelectedThinPlan extends @_SELECTED_@ThinLockPlan {} public static final SelectedPlan selectedPlan = new SelectedPlan(); + public static final SelectedThinPlan selectedThinPlan = new SelectedThinPlan(); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <pi...@us...> - 2009-03-12 16:10:38
|
Revision: 15580 http://jikesrvm.svn.sourceforge.net/jikesrvm/?rev=15580&view=rev Author: pizlo Date: 2009-03-12 16:10:06 +0000 (Thu, 12 Mar 2009) Log Message: ----------- added more configurability and improved unbiasing in the hybrid config Modified Paths: -------------- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/AbstractThinLockPlan.java rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/BasicThinLockPlan.java rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/EagerDeflateLockPlan.java rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/ElementaryBiasedLockPlan.java rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/HybridBiasedLockPlan.java rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/RVMThread.java rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/SloppyDeflateLockPlan.java rvmroot/branches/RVM-791/working-15440/rvm/src-generated/options/BooleanOptions.vm.dat rvmroot/branches/RVM-791/working-15440/rvm/src-generated/options/ValueOptions.vm.dat Modified: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/AbstractThinLockPlan.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/AbstractThinLockPlan.java 2009-03-12 04:34:06 UTC (rev 15579) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/AbstractThinLockPlan.java 2009-03-12 16:10:06 UTC (rev 15580) @@ -110,7 +110,8 @@ */ @Unpreemptible public abstract boolean attemptToMarkInflated(Object o, Offset lockOffset, - Word oldLockWord, int lockId); + Word oldLockWord, int lockId, + int cnt); /** * Attempt to deflate the thin lock. This makes the thin lock unlocked @@ -145,6 +146,8 @@ public boolean allowHeaderCAS(Object o, Offset lockOffset) { return true; } + + public void poll(RVMThread t) {} } Modified: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/BasicThinLockPlan.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/BasicThinLockPlan.java 2009-03-12 04:34:06 UTC (rev 15579) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/BasicThinLockPlan.java 2009-03-12 16:10:06 UTC (rev 15580) @@ -184,7 +184,7 @@ if (l!=null && l.lockHeavy(o)) { return; } // else we grabbed someone else's lock - } else if (cnt>LockConfig.RETRY_LIMIT) { + } else if (cnt>VM.thinRetryLimit) { attemptToInflate=true; } @@ -196,7 +196,7 @@ if (LockConfig.selectedPlan.inflateAndLock(o, lockOffset)) { return; } - } else { + } else if (VM.thinYieldOnContention) { RVMThread.yield(); } } @@ -279,7 +279,8 @@ @Unpreemptible public final boolean attemptToMarkInflated(Object o, Offset lockOffset, Word oldLockWord, - int lockId) { + int lockId, + int cnt) { Word changed= TL_FAT_LOCK_MASK.or(Word.fromIntZeroExtend(lockId).lsh(TL_LOCK_ID_SHIFT)) .or(oldLockWord.and(TL_UNLOCK_MASK)); Modified: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/EagerDeflateLockPlan.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/EagerDeflateLockPlan.java 2009-03-12 04:34:06 UTC (rev 15579) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/EagerDeflateLockPlan.java 2009-03-12 16:10:06 UTC (rev 15580) @@ -114,7 +114,7 @@ if (PROFILE) RVMThread.enterLockingPath(); if (false) VM.sysWriteln("l = ",Magic.objectAsAddress(l)); l.lockState(); - do { + for (int cnt=0;;++cnt) { Word bits = Magic.getWordAtOffset(o, lockOffset); // check to see if another thread has already created a fat lock if (LockConfig.selectedThinPlan.isFat(bits)) { @@ -137,7 +137,7 @@ } if (VM.VerifyAssertions) VM._assert(l!=null); if (LockConfig.selectedThinPlan.attemptToMarkInflated( - o, lockOffset, bits, l.id)) { + o, lockOffset, bits, l.id, cnt)) { l.setLockedObject(o); l.setOwnerId(LockConfig.selectedThinPlan.getLockOwner(bits)); if (l.getOwnerId() != 0) { @@ -149,7 +149,7 @@ return l; } // contention detected, try again - } while (true); + } } /** Modified: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/ElementaryBiasedLockPlan.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/ElementaryBiasedLockPlan.java 2009-03-12 04:34:06 UTC (rev 15579) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/ElementaryBiasedLockPlan.java 2009-03-12 16:10:06 UTC (rev 15580) @@ -204,7 +204,8 @@ @Unpreemptible public final boolean attemptToMarkInflated(Object o, Offset lockOffset, Word oldLockWord, - int lockId) { + int lockId, + int cnt) { if (VM.VerifyAssertions) VM._assert(oldLockWord.and(TL_FAT_LOCK_MASK).isZero()); if (false) VM.sysWriteln("attemptToMarkInflated with oldLockWord = ",oldLockWord); // what this needs to do: Modified: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/HybridBiasedLockPlan.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/HybridBiasedLockPlan.java 2009-03-12 04:34:06 UTC (rev 15579) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/HybridBiasedLockPlan.java 2009-03-12 16:10:06 UTC (rev 15580) @@ -174,7 +174,7 @@ Magic.isync(); return; } - } else if (cnt>LockConfig.RETRY_LIMIT) { + } else if (cnt>VM.thinRetryLimit) { tryToInflate=true; } } else { @@ -198,7 +198,7 @@ if (LockConfig.selectedPlan.inflateAndLock(o, lockOffset)) { return; } - } else { + } else if (VM.thinYieldOnContention) { RVMThread.yield(); } } @@ -338,7 +338,8 @@ @Unpreemptible public final boolean attemptToMarkInflated(Object o, Offset lockOffset, Word oldLockWord, - int lockId) { + int lockId, + int cnt) { if (VM.VerifyAssertions) VM._assert(oldLockWord.and(BL_STAT_MASK).NE(BL_STAT_FAT)); if (false) VM.sysWriteln("attemptToMarkInflated with oldLockWord = ",oldLockWord); // what this needs to do: @@ -386,35 +387,82 @@ } else { if (STATS) numRevocations++; - boolean result=false; - - // NB. this may stop a thread other than the one that had the bias, - // if that thread died and some other thread took its slot. that's - // why we do a CAS below. it's only needed if some other thread - // had seen the owner be null (which may happen if we came here after - // a new thread took the slot while someone else came here when the - // slot was still null). if it was the case that everyone else had - // seen a non-null owner, then the pair handshake would serve as - // sufficient synchronization (the id would identify the set of threads - // that shared that id's communicationLock). oddly, that means that - // this whole thing could be "simplified" to acquire the - // communicationLock even if the owner was null. but that would be - // goofy. - if (false) VM.sysWriteln("entering pair handshake"); - owner.beginPairHandshake(); - if (false) VM.sysWriteln("done with that"); - - Word newLockWord=Magic.getWordAtOffset(o, lockOffset); - result=Synchronization.tryCompareAndSwap( - o, lockOffset, oldLockWord, changed); - owner.endPairHandshake(); - if (false) VM.sysWriteln("that worked."); - return result; + if (VM.biasSpinToRevoke && cnt==0) { + owner.objectToUnbias=o; + owner.takeYieldpoint=1; + + for (int limit=VM.biasRevokeRetryLimit;limit-->0;) { + if (Magic.getWordAtOffset(o,lockOffset)!=oldLockWord) { + break; + } + if (VM.thinYieldOnContention) RVMThread.yield(); + } + + owner.objectToUnbias=null; + return false; + } else { + + boolean result=false; + + // NB. this may stop a thread other than the one that had the bias, + // if that thread died and some other thread took its slot. that's + // why we do a CAS below. it's only needed if some other thread + // had seen the owner be null (which may happen if we came here after + // a new thread took the slot while someone else came here when the + // slot was still null). if it was the case that everyone else had + // seen a non-null owner, then the pair handshake would serve as + // sufficient synchronization (the id would identify the set of threads + // that shared that id's communicationLock). oddly, that means that + // this whole thing could be "simplified" to acquire the + // communicationLock even if the owner was null. but that would be + // goofy. + if (false) VM.sysWriteln("entering pair handshake"); + owner.beginPairHandshake(); + if (false) VM.sysWriteln("done with that"); + + Word newLockWord=Magic.getWordAtOffset(o, lockOffset); + result=Synchronization.tryCompareAndSwap( + o, lockOffset, oldLockWord, changed); + owner.endPairHandshake(); + if (false) VM.sysWriteln("that worked."); + + return result; + } } } } } + public final void poll(RVMThread t) { + Object o=t.objectToUnbias; + t.objectToUnbias=null; + + if (o!=null) { + Offset lockOffset=Magic.getObjectType(o).getThinLockOffset(); + + Word bits=Magic.getWordAtOffset(o, lockOffset); + + if (bits.and(BL_STAT_MASK).EQ(BL_STAT_BIASABLE)) { + int lockOwner=getLockOwner(bits); + + Word changed=bits.and(BL_UNLOCK_MASK).or(BL_STAT_THIN); + + if (lockOwner!=0) { + int recCount=getRecCount(bits); + changed=changed + .or(Word.fromIntZeroExtend(lockOwner)) + .or(Word.fromIntZeroExtend(recCount-1).lsh(BL_LOCK_COUNT_SHIFT)); + } + + if (false) VM.sysWriteln("unbiasing in poll: ",bits," -> ",changed); + + if (VM.VerifyAssertions) VM._assert(Magic.getWordAtOffset(o, lockOffset)==bits); + + Magic.setWordAtOffset(o,lockOffset,changed); + } + } + } + @Inline @Unpreemptible public final boolean attemptToMarkDeflated(Object o, Offset lockOffset, Modified: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/RVMThread.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/RVMThread.java 2009-03-12 04:34:06 UTC (rev 15579) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/RVMThread.java 2009-03-12 16:10:06 UTC (rev 15580) @@ -612,6 +612,8 @@ CommonLock cachedFreeLock=null; boolean noMoreLocking=false; + + Object objectToUnbias; /* * Wait/notify fields @@ -3381,6 +3383,9 @@ int takeYieldpointVal = t.takeYieldpoint; if (takeYieldpointVal != 0) { t.takeYieldpoint = 0; + + LockConfig.selectedThinPlan.poll(t); + // do two things: check if we should be blocking, and act upon // handshake requests. This also has the effect of reasserting that // we are in fact IN_JAVA (as opposed to IN_JAVA_TO_BLOCK). Modified: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/SloppyDeflateLockPlan.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/SloppyDeflateLockPlan.java 2009-03-12 04:34:06 UTC (rev 15579) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/SloppyDeflateLockPlan.java 2009-03-12 16:10:06 UTC (rev 15580) @@ -69,7 +69,7 @@ // no. you're only allowed to ask for the fat lock when the object is locked. in // that case, it cannot be deflated. - for (;;) { + for (int cnt=0;;cnt++) { Word bits = Magic.getWordAtOffset(o, lockOffset); if (LockConfig.selectedThinPlan.isFat(bits)) { @@ -114,7 +114,7 @@ // will also see that the lock is held. if (LockConfig.selectedThinPlan.attemptToMarkInflated( - o, lockOffset, bits, l.id)) { + o, lockOffset, bits, l.id, cnt)) { if (trace) VM.tsysWriteln("inflated a lock."); return l; } else { Modified: rvmroot/branches/RVM-791/working-15440/rvm/src-generated/options/BooleanOptions.vm.dat =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src-generated/options/BooleanOptions.vm.dat 2009-03-12 04:34:06 UTC (rev 15579) +++ rvmroot/branches/RVM-791/working-15440/rvm/src-generated/options/BooleanOptions.vm.dat 2009-03-12 16:10:06 UTC (rev 15580) @@ -41,3 +41,9 @@ reportRuntimeProfile false Report profiling information from the runtime. +thinYieldOnContention true +Yield on contention in the thin lock implementation. + +biasSpinToRevoke false +In the case of revocation, spin to allow the thread that owns the lock to revoke its bias quickly before using the heavier mechanism. + Modified: rvmroot/branches/RVM-791/working-15440/rvm/src-generated/options/ValueOptions.vm.dat =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src-generated/options/ValueOptions.vm.dat 2009-03-12 04:34:06 UTC (rev 15579) +++ rvmroot/branches/RVM-791/working-15440/rvm/src-generated/options/ValueOptions.vm.dat 2009-03-12 16:10:06 UTC (rev 15580) @@ -72,3 +72,11 @@ Force all threads to run on one CPU. The argument specifies which CPU (starting from 0). +V thinRetryLimit int 40 +The number of times to spin on a thin lock before inflating it into a fat lock. + + +V biasRevokeRetryLimit int 40 +The number of times to spin on a thin lock before inflating it into a fat lock. + + This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <pi...@us...> - 2009-03-17 03:42:23
|
Revision: 15590 http://jikesrvm.svn.sourceforge.net/jikesrvm/?rev=15590&view=rev Author: pizlo Date: 2009-03-17 03:41:53 +0000 (Tue, 17 Mar 2009) Log Message: ----------- added a thoughtful comment and a useless boolean Modified Paths: -------------- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/HybridBiasedLockPlan.java rvmroot/branches/RVM-791/working-15440/rvm/src-generated/vm-configuration/LockConfig.template Modified: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/HybridBiasedLockPlan.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/HybridBiasedLockPlan.java 2009-03-17 02:23:26 UTC (rev 15589) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/HybridBiasedLockPlan.java 2009-03-17 03:41:53 UTC (rev 15590) @@ -164,6 +164,8 @@ tryToInflate=true; } } else { + // FIXME: don't inflate. just unbias it by turning it into a thin + // lock. tryToInflate=true; } } else if (stat.EQ(BL_STAT_THIN)) { Modified: rvmroot/branches/RVM-791/working-15440/rvm/src-generated/vm-configuration/LockConfig.template =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src-generated/vm-configuration/LockConfig.template 2009-03-17 02:23:26 UTC (rev 15589) +++ rvmroot/branches/RVM-791/working-15440/rvm/src-generated/vm-configuration/LockConfig.template 2009-03-17 03:41:53 UTC (rev 15590) @@ -30,6 +30,11 @@ SELECTED==LockConfigs.SloppyDeflateHybrid) ? ThinLockConstants.BL_THREAD_ID_SHIFT : ThinLockConstants.TL_THREAD_ID_SHIFT; + + public static final boolean USING_SLOPPY = + SELECTED==LockConfigs.SloppyDeflate || + SELECTED==LockConfigs.SloppyDeflateInline || + SELECTED==LockConfigs.SloopyDeflateHybrid; public static final class Selected extends @_SELECTED_@Lock {} public static final class SelectedPlan extends @_SELECTED_@LockPlan {} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <pi...@us...> - 2009-03-17 20:44:24
|
Revision: 15598 http://jikesrvm.svn.sourceforge.net/jikesrvm/?rev=15598&view=rev Author: pizlo Date: 2009-03-17 20:44:09 +0000 (Tue, 17 Mar 2009) Log Message: ----------- small tweaks to make hybrid biased locking faster Modified Paths: -------------- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/HybridBiasedLockPlan.java rvmroot/branches/RVM-791/working-15440/rvm/src-generated/options/BooleanOptions.vm.dat Modified: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/HybridBiasedLockPlan.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/HybridBiasedLockPlan.java 2009-03-17 15:49:44 UTC (rev 15597) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/HybridBiasedLockPlan.java 2009-03-17 20:44:09 UTC (rev 15598) @@ -164,9 +164,9 @@ tryToInflate=true; } } else { - // FIXME: don't inflate. just unbias it by turning it into a thin - // lock. - tryToInflate=true; + if (casFromBiased(o, lockOffset, old, biasBitsToThinBits(old), cnt)) { + continue; // don't spin, since it's thin now + } } } else if (stat.EQ(BL_STAT_THIN)) { Word id = old.and(BL_THREAD_ID_MASK); @@ -348,6 +348,78 @@ } } + @NoInline + @Unpreemptible + public final boolean casFromBiased(Object o, Offset lockOffset, + Word oldLockWord, Word changed, + int cnt) { + RVMThread me=RVMThread.getCurrentThread(); + Word id=oldLockWord.and(BL_THREAD_ID_MASK); + if (id.isZero()) { + if (false) VM.sysWriteln("id is zero - easy case."); + return Synchronization.tryCompareAndSwap(o, lockOffset, oldLockWord, changed); + } else { + if (false) VM.sysWriteln("id = ",id); + int slot=id.toInt()>>BL_THREAD_ID_SHIFT; + if (false) VM.sysWriteln("slot = ",slot); + RVMThread owner=RVMThread.threadBySlot[slot]; + if (owner==me /* I own it, so I can unbias it trivially. This occurs + when we are inflating due to, for example, wait() */ || + owner==null /* the thread that owned it is dead, so it's safe to + unbias. */) { + // note that we use a CAS here, but it's only needed in the case + // that owner==null, since in that case some other thread may also + // be unbiasing. + return Synchronization.tryCompareAndSwap( + o, lockOffset, oldLockWord, changed); + } else { + if (VM.biasSpinToRevoke && cnt==0) { + owner.objectToUnbias=o; + owner.takeYieldpoint=1; + + int limit=VM.biasRevokeRetryLimit; + for (int cnt2=0;cnt2<limit;++cnt2) { + if (Magic.getWordAtOffset(o,lockOffset)!=oldLockWord) { + break; + } + Spinning.uninterruptibly(cnt2,0); + } + + owner.objectToUnbias=null; + return false; + } else { + numSlowRevocations++; + + boolean result=false; + + // NB. this may stop a thread other than the one that had the bias, + // if that thread died and some other thread took its slot. that's + // why we do a CAS below. it's only needed if some other thread + // had seen the owner be null (which may happen if we came here after + // a new thread took the slot while someone else came here when the + // slot was still null). if it was the case that everyone else had + // seen a non-null owner, then the pair handshake would serve as + // sufficient synchronization (the id would identify the set of threads + // that shared that id's communicationLock). oddly, that means that + // this whole thing could be "simplified" to acquire the + // communicationLock even if the owner was null. but that would be + // goofy. + if (false) VM.sysWriteln("entering pair handshake"); + owner.beginPairHandshake(); + if (false) VM.sysWriteln("done with that"); + + Word newLockWord=Magic.getWordAtOffset(o, lockOffset); + result=Synchronization.tryCompareAndSwap( + o, lockOffset, oldLockWord, changed); + owner.endPairHandshake(); + if (false) VM.sysWriteln("that worked."); + + return result; + } + } + } + } + @Inline @Unpreemptible public final boolean attemptToMarkInflated(Object o, Offset lockOffset, @@ -362,7 +434,6 @@ // 3) if the lock is biased in our favor, store the lock without CAS // 4) if the lock is biased but to someone else, enter the pair handshake // to unbias it and install the inflated lock - RVMThread me=RVMThread.getCurrentThread(); Word changed= BL_STAT_FAT.or(Word.fromIntZeroExtend(lockId).lsh(BL_LOCK_ID_SHIFT)) .or(oldLockWord.and(BL_UNLOCK_MASK)); @@ -380,73 +451,25 @@ return Synchronization.tryCompareAndSwap( o, lockOffset, oldLockWord, changed); } else { - Word id=oldLockWord.and(BL_THREAD_ID_MASK); - if (id.isZero()) { - if (false) VM.sysWriteln("id is zero - easy case."); - return Synchronization.tryCompareAndSwap(o, lockOffset, oldLockWord, changed); - } else { - if (false) VM.sysWriteln("id = ",id); - int slot=id.toInt()>>BL_THREAD_ID_SHIFT; - if (false) VM.sysWriteln("slot = ",slot); - RVMThread owner=RVMThread.threadBySlot[slot]; - if (owner==me /* I own it, so I can unbias it trivially. This occurs - when we are inflating due to, for example, wait() */ || - owner==null /* the thread that owned it is dead, so it's safe to - unbias. */) { - // note that we use a CAS here, but it's only needed in the case - // that owner==null, since in that case some other thread may also - // be unbiasing. - return Synchronization.tryCompareAndSwap( - o, lockOffset, oldLockWord, changed); - } else { - if (VM.biasSpinToRevoke && cnt==0) { - owner.objectToUnbias=o; - owner.takeYieldpoint=1; - - int limit=VM.biasRevokeRetryLimit; - for (int cnt2=0;cnt2<limit;++cnt2) { - if (Magic.getWordAtOffset(o,lockOffset)!=oldLockWord) { - break; - } - Spinning.uninterruptibly(cnt2,0); - } - - owner.objectToUnbias=null; - return false; - } else { - numSlowRevocations++; - - boolean result=false; - - // NB. this may stop a thread other than the one that had the bias, - // if that thread died and some other thread took its slot. that's - // why we do a CAS below. it's only needed if some other thread - // had seen the owner be null (which may happen if we came here after - // a new thread took the slot while someone else came here when the - // slot was still null). if it was the case that everyone else had - // seen a non-null owner, then the pair handshake would serve as - // sufficient synchronization (the id would identify the set of threads - // that shared that id's communicationLock). oddly, that means that - // this whole thing could be "simplified" to acquire the - // communicationLock even if the owner was null. but that would be - // goofy. - if (false) VM.sysWriteln("entering pair handshake"); - owner.beginPairHandshake(); - if (false) VM.sysWriteln("done with that"); - - Word newLockWord=Magic.getWordAtOffset(o, lockOffset); - result=Synchronization.tryCompareAndSwap( - o, lockOffset, oldLockWord, changed); - owner.endPairHandshake(); - if (false) VM.sysWriteln("that worked."); - - return result; - } - } - } + return casFromBiased(o, lockOffset, oldLockWord, changed, cnt); } } + private Word biasBitsToThinBits(Word bits) { + int lockOwner=getLockOwner(bits); + + Word changed=bits.and(BL_UNLOCK_MASK).or(BL_STAT_THIN); + + if (lockOwner!=0) { + int recCount=getRecCount(bits); + changed=changed + .or(Word.fromIntZeroExtend(lockOwner)) + .or(Word.fromIntZeroExtend(recCount-1).lsh(BL_LOCK_COUNT_SHIFT)); + } + + return changed; + } + @Unpreemptible public final void poll(RVMThread t) { Object o=t.objectToUnbias; @@ -458,17 +481,8 @@ Word bits=Magic.getWordAtOffset(o, lockOffset); if (bits.and(BL_STAT_MASK).EQ(BL_STAT_BIASABLE)) { - int lockOwner=getLockOwner(bits); + Word changed=biasBitsToThinBits(bits); - Word changed=bits.and(BL_UNLOCK_MASK).or(BL_STAT_THIN); - - if (lockOwner!=0) { - int recCount=getRecCount(bits); - changed=changed - .or(Word.fromIntZeroExtend(lockOwner)) - .or(Word.fromIntZeroExtend(recCount-1).lsh(BL_LOCK_COUNT_SHIFT)); - } - if (false) VM.sysWriteln("unbiasing in poll: ",bits," -> ",changed); if (VM.VerifyAssertions) VM._assert(Magic.getWordAtOffset(o, lockOffset)==bits); Modified: rvmroot/branches/RVM-791/working-15440/rvm/src-generated/options/BooleanOptions.vm.dat =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src-generated/options/BooleanOptions.vm.dat 2009-03-17 15:49:44 UTC (rev 15597) +++ rvmroot/branches/RVM-791/working-15440/rvm/src-generated/options/BooleanOptions.vm.dat 2009-03-17 20:44:09 UTC (rev 15598) @@ -41,7 +41,7 @@ reportRuntimeProfile false Report profiling information from the runtime. -biasSpinToRevoke false +biasSpinToRevoke true In the case of revocation, spin to allow the thread that owns the lock to revoke its bias quickly before using the heavier mechanism. traceSloppyDeflations false This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <pi...@us...> - 2009-03-31 18:33:04
|
Revision: 15636 http://jikesrvm.svn.sourceforge.net/jikesrvm/?rev=15636&view=rev Author: pizlo Date: 2009-03-31 18:32:51 +0000 (Tue, 31 Mar 2009) Log Message: ----------- latest changes ... will get back to this later today, hopefully Modified Paths: -------------- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/BargingCascadeFutexLock.java rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/FutexThinLockPlan.java rvmroot/branches/RVM-791/working-15440/rvm/src-generated/vm-configuration/LockConfig.template Modified: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/BargingCascadeFutexLock.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/BargingCascadeFutexLock.java 2009-03-31 06:22:08 UTC (rev 15635) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/BargingCascadeFutexLock.java 2009-03-31 18:32:51 UTC (rev 15636) @@ -71,7 +71,10 @@ } else { futex.wake(1); } - if (res==0) continue; + if (res==0) { + if (LockConfig.FUTEX_REHEAT) cnt=0; + continue; + } } Spinning.interruptibly(cnt,0); } Modified: rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/FutexThinLockPlan.java =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/FutexThinLockPlan.java 2009-03-31 06:22:08 UTC (rev 15635) +++ rvmroot/branches/RVM-791/working-15440/rvm/src/org/jikesrvm/scheduler/FutexThinLockPlan.java 2009-03-31 18:32:51 UTC (rev 15636) @@ -173,7 +173,10 @@ // should this guy wake on the old address? FutexUtils.wake(o, lockOffset, 1); } - if (res==0) continue; // don't spin if we were awakened. + if (res==0) { + if (LockConfig.FUTEX_REHEAT) cnt=0; + continue; // don't spin if we were awakened. + } } } Modified: rvmroot/branches/RVM-791/working-15440/rvm/src-generated/vm-configuration/LockConfig.template =================================================================== --- rvmroot/branches/RVM-791/working-15440/rvm/src-generated/vm-configuration/LockConfig.template 2009-03-31 06:22:08 UTC (rev 15635) +++ rvmroot/branches/RVM-791/working-15440/rvm/src-generated/vm-configuration/LockConfig.template 2009-03-31 18:32:51 UTC (rev 15636) @@ -42,6 +42,7 @@ public static final boolean SPIN_UNLOCK = false; public static final boolean LATE_WAKE_FUTEX = true; + public static final boolean FUTEX_REHEAT = true; public static final class Selected extends @_SELECTED_@Lock {} public static final class SelectedPlan extends @_SELECTED_@LockPlan {} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |