@Uninterruptible @NoNullCheck public static boolean holdsLock(Object o, Offset lockOffset, RVMThread thread) { for (int cnt = 0; ; ++cnt) { int tid = thread.getLockingId(); Word bits = Magic.getWordAtOffset(o, lockOffset); if (bits.and(TL_STAT_MASK).EQ(TL_STAT_BIASABLE)) { // if locked, then it is locked with a thin lock return bits.and(TL_THREAD_ID_MASK).toInt() == tid && !bits.and(TL_LOCK_COUNT_MASK).isZero(); } else if (bits.and(TL_STAT_MASK).EQ(TL_STAT_THIN)) { return bits.and(TL_THREAD_ID_MASK).toInt() == tid; } else { if (VM.VerifyAssertions) VM._assert(bits.and(TL_STAT_MASK).EQ(TL_STAT_FAT)); // if locked, then it is locked with a fat lock Lock l = Lock.getLock(getLockIndex(bits)); if (l != null) { l.mutex.lock(); boolean result = (l.getOwnerId() == tid && l.getLockedObject() == o); l.mutex.unlock(); return result; } } RVMThread.yieldNoHandshake(); } }
@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))) { Magic.isync(); return; } } else { // lock is unbiased but biasing is NOT allowed, so turn it into // a thin lock if (Synchronization.tryCompareAndSwap( o, lockOffset, old, old.or(threadId).or(TL_STAT_THIN))) { Magic.isync(); 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); return; } else { tryToInflate = true; } } else { if (casFromBiased(o, lockOffset, old, biasBitsToThinBits(old), cnt)) { continue; // don't spin, since it's thin now } } } 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))) { Magic.isync(); 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)) { Magic.isync(); 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++; // 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. // NB: this calls into our attemptToMarkInflated() method, which will do the // Right Thing if the lock is biased to someone else. if (inflateAndLock(o, lockOffset)) { return; } } else { RVMThread.yieldNoHandshake(); } } }