use of org.vmmagic.unboxed.Word in project JikesRVM by JikesRVM.
the class ThinLock method lock.
@NoInline
@NoNullCheck
@Unpreemptible
public static void lock(Object o, Offset lockOffset) {
if (STATS)
fastLocks++;
Word threadId = Word.fromIntZeroExtend(RVMThread.getCurrentThread().getLockingId());
for (int cnt = 0; ; cnt++) {
Word old = Magic.getWordAtOffset(o, lockOffset);
Word stat = old.and(TL_STAT_MASK);
boolean tryToInflate = false;
if (stat.EQ(TL_STAT_BIASABLE)) {
Word id = old.and(TL_THREAD_ID_MASK);
if (id.isZero()) {
if (ENABLE_BIASED_LOCKING) {
// lock is unbiased, bias it in our favor and grab it
if (Synchronization.tryCompareAndSwap(o, lockOffset, old, old.or(threadId).plus(TL_LOCK_COUNT_UNIT))) {
if (!VM.MagicAttemptImpliesStoreLoadBarrier)
Magic.fence();
return;
}
} else {
// a thin lock
if (Synchronization.tryCompareAndSwap(o, lockOffset, old, old.or(threadId).or(TL_STAT_THIN))) {
if (!VM.MagicAttemptImpliesStoreLoadBarrier)
Magic.fence();
return;
}
}
} else if (id.EQ(threadId)) {
// lock is biased in our favor
Word changed = old.plus(TL_LOCK_COUNT_UNIT);
if (!changed.and(TL_LOCK_COUNT_MASK).isZero()) {
setDedicatedU16(o, lockOffset, changed);
Magic.combinedLoadBarrier();
return;
} else {
tryToInflate = true;
}
} else {
if (casFromBiased(o, lockOffset, old, biasBitsToThinBits(old), cnt)) {
// don't spin, since it's thin now
continue;
}
}
} else if (stat.EQ(TL_STAT_THIN)) {
Word id = old.and(TL_THREAD_ID_MASK);
if (id.isZero()) {
if (Synchronization.tryCompareAndSwap(o, lockOffset, old, old.or(threadId))) {
if (!VM.MagicAttemptImpliesStoreLoadBarrier)
Magic.fence();
return;
}
} else if (id.EQ(threadId)) {
Word changed = old.plus(TL_LOCK_COUNT_UNIT);
if (changed.and(TL_LOCK_COUNT_MASK).isZero()) {
tryToInflate = true;
} else if (Synchronization.tryCompareAndSwap(o, lockOffset, old, changed)) {
if (!VM.MagicAttemptImpliesStoreLoadBarrier)
Magic.fence();
return;
}
} else if (cnt > retryLimit) {
tryToInflate = true;
}
} else {
if (VM.VerifyAssertions)
VM._assert(stat.EQ(TL_STAT_FAT));
// lock is fat. contend on it.
if (Lock.getLock(getLockIndex(old)).lockHeavy(o)) {
return;
}
}
if (tryToInflate) {
if (STATS)
slowLocks++;
// Right Thing if the lock is biased to someone else.
if (inflateAndLock(o, lockOffset)) {
return;
}
} else {
Magic.combinedLoadBarrier();
RVMThread.yieldNoHandshake();
}
}
}
use of org.vmmagic.unboxed.Word in project JikesRVM by JikesRVM.
the class ThinLock method unlock.
@NoInline
@NoNullCheck
@Unpreemptible
public static void unlock(Object o, Offset lockOffset) {
Word threadId = Word.fromIntZeroExtend(RVMThread.getCurrentThread().getLockingId());
for (int cnt = 0; ; cnt++) {
Word old = Magic.getWordAtOffset(o, lockOffset);
Word stat = old.and(TL_STAT_MASK);
if (stat.EQ(TL_STAT_BIASABLE)) {
Word id = old.and(TL_THREAD_ID_MASK);
if (id.EQ(threadId)) {
if (old.and(TL_LOCK_COUNT_MASK).isZero()) {
RVMThread.raiseIllegalMonitorStateException("biased unlocking: we own this object but the count is already zero", o);
}
setDedicatedU16(o, lockOffset, old.minus(TL_LOCK_COUNT_UNIT));
Magic.fence();
return;
} else {
RVMThread.raiseIllegalMonitorStateException("biased unlocking: we don't own this object", o);
}
} else if (stat.EQ(TL_STAT_THIN)) {
Word id = old.and(TL_THREAD_ID_MASK);
if (id.EQ(threadId)) {
Word changed;
if (old.and(TL_LOCK_COUNT_MASK).isZero()) {
changed = old.and(TL_UNLOCK_MASK).or(TL_STAT_THIN);
} else {
changed = old.minus(TL_LOCK_COUNT_UNIT);
}
Magic.combinedLoadBarrier();
if (Synchronization.tryCompareAndSwap(o, lockOffset, old, changed)) {
if (!VM.MagicAttemptImpliesStoreLoadBarrier)
Magic.fence();
return;
}
} else {
if (false) {
VM.sysWriteln("threadId = ", threadId);
VM.sysWriteln("id = ", id);
}
RVMThread.raiseIllegalMonitorStateException("thin unlocking: we don't own this object", o);
}
} else {
if (VM.VerifyAssertions)
VM._assert(stat.EQ(TL_STAT_FAT));
// fat unlock
Lock.getLock(getLockIndex(old)).unlockHeavy(o);
return;
}
}
}
use of org.vmmagic.unboxed.Word in project JikesRVM by JikesRVM.
the class ThinLock method inlineUnlock.
@Inline
@NoNullCheck
@Unpreemptible
@Entrypoint
public static void inlineUnlock(Object o, Offset lockOffset) {
// FIXME: bad for PPC?
Word old = Magic.prepareWord(o, lockOffset);
Word id = old.and(TL_THREAD_ID_MASK.or(TL_STAT_MASK));
Word tid = Word.fromIntSignExtend(RVMThread.getCurrentThread().getLockingId());
if (id.EQ(tid)) {
if (!old.and(TL_LOCK_COUNT_MASK).isZero()) {
setDedicatedU16(o, lockOffset, old.minus(TL_LOCK_COUNT_UNIT));
Magic.fence();
return;
}
} else if (old.xor(tid).rshl(TL_LOCK_COUNT_SHIFT).EQ(TL_STAT_THIN.rshl(TL_LOCK_COUNT_SHIFT))) {
Magic.combinedLoadBarrier();
if (Magic.attemptWord(o, lockOffset, old, old.and(TL_UNLOCK_MASK).or(TL_STAT_THIN))) {
if (!VM.MagicAttemptImpliesStoreLoadBarrier)
Magic.fence();
return;
}
}
unlock(o, lockOffset);
}
use of org.vmmagic.unboxed.Word in project JikesRVM by JikesRVM.
the class ThinLock method casFromBiased.
@NoInline
@Unpreemptible
public static boolean casFromBiased(Object o, Offset lockOffset, Word oldLockWord, Word changed, int cnt) {
RVMThread me = RVMThread.getCurrentThread();
Word id = oldLockWord.and(TL_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() >> TL_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. */
{
// be unbiasing.
return Synchronization.tryCompareAndSwap(o, lockOffset, oldLockWord, changed);
} else {
boolean result = false;
// 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;
}
}
}
use of org.vmmagic.unboxed.Word in project JikesRVM by JikesRVM.
the class ThinLock method attemptToInflate.
/**
* Promotes a light-weight lock to a heavy-weight lock. If this returns the lock
* that you gave it, its mutex will be locked; otherwise, its mutex will be unlocked.
* Hence, calls to this method should always be followed by a condition lock() or
* unlock() call.
*
* @param o the object to get a heavy-weight lock
* @param lockOffset the offset of the thin lock word in the object.
* @param l the lock to attempt to inflate
* @return the inflated lock; either the one you gave, or another one, if the lock
* was inflated by some other thread.
*/
@NoNullCheck
@Unpreemptible
protected static Lock attemptToInflate(Object o, Offset lockOffset, Lock l) {
if (false)
VM.sysWriteln("l = ", Magic.objectAsAddress(l));
l.mutex.lock();
for (int cnt = 0; ; ++cnt) {
Word bits = Magic.getWordAtOffset(o, lockOffset);
// check to see if another thread has already created a fat lock
if (isFat(bits)) {
if (trace) {
VM.sysWriteln("Thread #", RVMThread.getCurrentThreadSlot(), ": freeing lock ", Magic.objectAsAddress(l), " because we had a double-inflate");
}
Lock result = Lock.getLock(getLockIndex(bits));
if (result == null || result.lockedObject != o) {
continue;
/* this is nasty. this will happen when a lock
is deflated. */
}
Lock.free(l);
l.mutex.unlock();
return result;
}
if (VM.VerifyAssertions)
VM._assert(l != null);
if (attemptToMarkInflated(o, lockOffset, bits, l.index, cnt)) {
l.setLockedObject(o);
l.setOwnerId(getLockOwner(bits));
if (l.getOwnerId() != 0) {
l.setRecursionCount(getRecCount(bits));
} else {
if (VM.VerifyAssertions)
VM._assert(l.getRecursionCount() == 0);
}
return l;
}
// contention detected, try again
}
}
Aggregations