diff options
Diffstat (limited to 'runtime/monitor.cc')
| -rw-r--r-- | runtime/monitor.cc | 307 |
1 files changed, 159 insertions, 148 deletions
diff --git a/runtime/monitor.cc b/runtime/monitor.cc index 0cf077a400..4be25d6946 100644 --- a/runtime/monitor.cc +++ b/runtime/monitor.cc @@ -16,15 +16,19 @@ #include "monitor.h" +#define ATRACE_TAG ATRACE_TAG_DALVIK + +#include <cutils/trace.h> #include <vector> +#include "art_method-inl.h" #include "base/mutex.h" #include "base/stl_util.h" +#include "base/time_utils.h" #include "class_linker.h" #include "dex_file-inl.h" #include "dex_instruction.h" #include "lock_word-inl.h" -#include "mirror/art_method-inl.h" #include "mirror/class-inl.h" #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" @@ -65,11 +69,11 @@ static constexpr uint64_t kLongWaitMs = 100; * at any given time. */ -bool (*Monitor::is_sensitive_thread_hook_)() = NULL; +bool (*Monitor::is_sensitive_thread_hook_)() = nullptr; uint32_t Monitor::lock_profiling_threshold_ = 0; bool Monitor::IsSensitiveThread() { - if (is_sensitive_thread_hook_ != NULL) { + if (is_sensitive_thread_hook_ != nullptr) { return (*is_sensitive_thread_hook_)(); } return false; @@ -87,9 +91,9 @@ Monitor::Monitor(Thread* self, Thread* owner, mirror::Object* obj, int32_t hash_ owner_(owner), lock_count_(0), obj_(GcRoot<mirror::Object>(obj)), - wait_set_(NULL), + wait_set_(nullptr), hash_code_(hash_code), - locking_method_(NULL), + locking_method_(nullptr), locking_dex_pc_(0), monitor_id_(MonitorPool::ComputeMonitorId(this, self)) { #ifdef __LP64__ @@ -110,9 +114,9 @@ Monitor::Monitor(Thread* self, Thread* owner, mirror::Object* obj, int32_t hash_ owner_(owner), lock_count_(0), obj_(GcRoot<mirror::Object>(obj)), - wait_set_(NULL), + wait_set_(nullptr), hash_code_(hash_code), - locking_method_(NULL), + locking_method_(nullptr), locking_dex_pc_(0), monitor_id_(id) { #ifdef __LP64__ @@ -162,7 +166,7 @@ bool Monitor::Install(Thread* self) { return false; } } - LockWord fat(this); + LockWord fat(this, lw.ReadBarrierState()); // Publish the updated lock word, which may race with other threads. bool success = GetObject()->CasLockWordWeakSequentiallyConsistent(lw, fat); // Lock profiling. @@ -178,15 +182,11 @@ Monitor::~Monitor() { // Deflated monitors have a null object. } -/* - * Links a thread into a monitor's wait set. The monitor lock must be - * held by the caller of this routine. - */ void Monitor::AppendToWaitSet(Thread* thread) { DCHECK(owner_ == Thread::Current()); - DCHECK(thread != NULL); + DCHECK(thread != nullptr); DCHECK(thread->GetWaitNext() == nullptr) << thread->GetWaitNext(); - if (wait_set_ == NULL) { + if (wait_set_ == nullptr) { wait_set_ = thread; return; } @@ -199,14 +199,10 @@ void Monitor::AppendToWaitSet(Thread* thread) { t->SetWaitNext(thread); } -/* - * Unlinks a thread from a monitor's wait set. The monitor lock must - * be held by the caller of this routine. - */ void Monitor::RemoveFromWaitSet(Thread *thread) { DCHECK(owner_ == Thread::Current()); - DCHECK(thread != NULL); - if (wait_set_ == NULL) { + DCHECK(thread != nullptr); + if (wait_set_ == nullptr) { return; } if (wait_set_ == thread) { @@ -216,7 +212,7 @@ void Monitor::RemoveFromWaitSet(Thread *thread) { } Thread* t = wait_set_; - while (t->GetWaitNext() != NULL) { + while (t->GetWaitNext() != nullptr) { if (t->GetWaitNext() == thread) { t->SetWaitNext(thread->GetWaitNext()); thread->SetWaitNext(nullptr); @@ -249,7 +245,7 @@ void Monitor::Lock(Thread* self) { // Contended. const bool log_contention = (lock_profiling_threshold_ != 0); uint64_t wait_start_ms = log_contention ? MilliTime() : 0; - mirror::ArtMethod* owners_method = locking_method_; + ArtMethod* owners_method = locking_method_; uint32_t owners_dex_pc = locking_dex_pc_; // Do this before releasing the lock so that we don't get deflated. size_t num_waiters = num_waiters_; @@ -258,8 +254,14 @@ void Monitor::Lock(Thread* self) { self->SetMonitorEnterObject(GetObject()); { ScopedThreadStateChange tsc(self, kBlocked); // Change to blocked and give up mutator_lock_. - MutexLock mu2(self, monitor_lock_); // Reacquire monitor_lock_ without mutator_lock_ for Wait. - if (owner_ != NULL) { // Did the owner_ give the lock up? + // Reacquire monitor_lock_ without mutator_lock_ for Wait. + MutexLock mu2(self, monitor_lock_); + if (owner_ != nullptr) { // Did the owner_ give the lock up? + if (ATRACE_ENABLED()) { + std::string name; + owner_->GetThreadName(name); + ATRACE_BEGIN(("Contended on monitor with owner " + name).c_str()); + } monitor_contenders_.Wait(self); // Still contended so wait. // Woken from contention. if (log_contention) { @@ -283,6 +285,7 @@ void Monitor::Lock(Thread* self) { LogContentionEvent(self, wait_ms, sample_percent, owners_filename, owners_line_number); } } + ATRACE_END(); } } self->SetMonitorEnterObject(nullptr); @@ -299,20 +302,19 @@ static void ThrowIllegalMonitorStateExceptionF(const char* fmt, ...) va_list args; va_start(args, fmt); Thread* self = Thread::Current(); - ThrowLocation throw_location = self->GetCurrentLocationForThrow(); - self->ThrowNewExceptionV(throw_location, "Ljava/lang/IllegalMonitorStateException;", fmt, args); + self->ThrowNewExceptionV("Ljava/lang/IllegalMonitorStateException;", fmt, args); if (!Runtime::Current()->IsStarted() || VLOG_IS_ON(monitor)) { std::ostringstream ss; self->Dump(ss); LOG(Runtime::Current()->IsStarted() ? INFO : ERROR) - << self->GetException(NULL)->Dump() << "\n" << ss.str(); + << self->GetException()->Dump() << "\n" << ss.str(); } va_end(args); } static std::string ThreadToString(Thread* thread) { - if (thread == NULL) { - return "NULL"; + if (thread == nullptr) { + return "nullptr"; } std::ostringstream oss; // TODO: alternatively, we could just return the thread's name. @@ -322,7 +324,7 @@ static std::string ThreadToString(Thread* thread) { void Monitor::FailedUnlock(mirror::Object* o, Thread* expected_owner, Thread* found_owner, Monitor* monitor) { - Thread* current_owner = NULL; + Thread* current_owner = nullptr; std::string current_owner_string; std::string expected_owner_string; std::string found_owner_string; @@ -331,14 +333,14 @@ void Monitor::FailedUnlock(mirror::Object* o, Thread* expected_owner, Thread* fo // Acquire thread list lock so threads won't disappear from under us. MutexLock mu(Thread::Current(), *Locks::thread_list_lock_); // Re-read owner now that we hold lock. - current_owner = (monitor != NULL) ? monitor->GetOwner() : NULL; + current_owner = (monitor != nullptr) ? monitor->GetOwner() : nullptr; // Get short descriptions of the threads involved. current_owner_string = ThreadToString(current_owner); expected_owner_string = ThreadToString(expected_owner); found_owner_string = ThreadToString(found_owner); } - if (current_owner == NULL) { - if (found_owner == NULL) { + if (current_owner == nullptr) { + if (found_owner == nullptr) { ThrowIllegalMonitorStateExceptionF("unlock of unowned monitor on object of type '%s'" " on thread '%s'", PrettyTypeOf(o).c_str(), @@ -352,7 +354,7 @@ void Monitor::FailedUnlock(mirror::Object* o, Thread* expected_owner, Thread* fo expected_owner_string.c_str()); } } else { - if (found_owner == NULL) { + if (found_owner == nullptr) { // Race: originally there was no owner, there is now ThrowIllegalMonitorStateExceptionF("unlock of monitor owned by '%s' on object of type '%s'" " (originally believed to be unowned) on thread '%s'", @@ -380,14 +382,14 @@ void Monitor::FailedUnlock(mirror::Object* o, Thread* expected_owner, Thread* fo } bool Monitor::Unlock(Thread* self) { - DCHECK(self != NULL); + DCHECK(self != nullptr); MutexLock mu(self, monitor_lock_); Thread* owner = owner_; if (owner == self) { // We own the monitor, so nobody else can be in here. if (lock_count_ == 0) { - owner_ = NULL; - locking_method_ = NULL; + owner_ = nullptr; + locking_method_ = nullptr; locking_dex_pc_ = 0; // Wake a contender. monitor_contenders_.Signal(self); @@ -404,32 +406,9 @@ bool Monitor::Unlock(Thread* self) { return true; } -/* - * Wait on a monitor until timeout, interrupt, or notification. Used for - * Object.wait() and (somewhat indirectly) Thread.sleep() and Thread.join(). - * - * If another thread calls Thread.interrupt(), we throw InterruptedException - * and return immediately if one of the following are true: - * - blocked in wait(), wait(long), or wait(long, int) methods of Object - * - blocked in join(), join(long), or join(long, int) methods of Thread - * - blocked in sleep(long), or sleep(long, int) methods of Thread - * Otherwise, we set the "interrupted" flag. - * - * Checks to make sure that "ns" is in the range 0-999999 - * (i.e. fractions of a millisecond) and throws the appropriate - * exception if it isn't. - * - * The spec allows "spurious wakeups", and recommends that all code using - * Object.wait() do so in a loop. This appears to derive from concerns - * about pthread_cond_wait() on multiprocessor systems. Some commentary - * on the web casts doubt on whether these can/should occur. - * - * Since we're allowed to wake up "early", we clamp extremely long durations - * to return at the end of the 32-bit time epoch. - */ void Monitor::Wait(Thread* self, int64_t ms, int32_t ns, bool interruptShouldThrow, ThreadState why) { - DCHECK(self != NULL); + DCHECK(self != nullptr); DCHECK(why == kTimedWaiting || why == kWaiting || why == kSleeping); monitor_lock_.Lock(self); @@ -450,8 +429,7 @@ void Monitor::Wait(Thread* self, int64_t ms, int32_t ns, // Enforce the timeout range. if (ms < 0 || ns < 0 || ns > 999999) { monitor_lock_.Unlock(self); - ThrowLocation throw_location = self->GetCurrentLocationForThrow(); - self->ThrowNewExceptionF(throw_location, "Ljava/lang/IllegalArgumentException;", + self->ThrowNewExceptionF("Ljava/lang/IllegalArgumentException;", "timeout arguments out of range: ms=%" PRId64 " ns=%d", ms, ns); return; } @@ -470,9 +448,9 @@ void Monitor::Wait(Thread* self, int64_t ms, int32_t ns, ++num_waiters_; int prev_lock_count = lock_count_; lock_count_ = 0; - owner_ = NULL; - mirror::ArtMethod* saved_method = locking_method_; - locking_method_ = NULL; + owner_ = nullptr; + ArtMethod* saved_method = locking_method_; + locking_method_ = nullptr; uintptr_t saved_dex_pc = locking_dex_pc_; locking_dex_pc_ = 0; @@ -489,7 +467,7 @@ void Monitor::Wait(Thread* self, int64_t ms, int32_t ns, MutexLock mu(self, *self->GetWaitMutex()); // Set wait_monitor_ to the monitor object we will be waiting on. When wait_monitor_ is - // non-NULL a notifying or interrupting thread must signal the thread's wait_cond_ to wake it + // non-null a notifying or interrupting thread must signal the thread's wait_cond_ to wake it // up. DCHECK(self->GetWaitMonitor() == nullptr); self->SetWaitMonitor(this); @@ -562,14 +540,13 @@ void Monitor::Wait(Thread* self, int64_t ms, int32_t ns, self->SetInterruptedLocked(false); } if (interruptShouldThrow) { - ThrowLocation throw_location = self->GetCurrentLocationForThrow(); - self->ThrowNewException(throw_location, "Ljava/lang/InterruptedException;", NULL); + self->ThrowNewException("Ljava/lang/InterruptedException;", nullptr); } } } void Monitor::Notify(Thread* self) { - DCHECK(self != NULL); + DCHECK(self != nullptr); MutexLock mu(self, monitor_lock_); // Make sure that we hold the lock. if (owner_ != self) { @@ -577,13 +554,13 @@ void Monitor::Notify(Thread* self) { return; } // Signal the first waiting thread in the wait set. - while (wait_set_ != NULL) { + while (wait_set_ != nullptr) { Thread* thread = wait_set_; wait_set_ = thread->GetWaitNext(); thread->SetWaitNext(nullptr); // Check to see if the thread is still waiting. - MutexLock mu(self, *thread->GetWaitMutex()); + MutexLock wait_mu(self, *thread->GetWaitMutex()); if (thread->GetWaitMonitor() != nullptr) { thread->GetWaitConditionVariable()->Signal(self); return; @@ -592,7 +569,7 @@ void Monitor::Notify(Thread* self) { } void Monitor::NotifyAll(Thread* self) { - DCHECK(self != NULL); + DCHECK(self != nullptr); MutexLock mu(self, monitor_lock_); // Make sure that we hold the lock. if (owner_ != self) { @@ -600,7 +577,7 @@ void Monitor::NotifyAll(Thread* self) { return; } // Signal all threads in the wait set. - while (wait_set_ != NULL) { + while (wait_set_ != nullptr) { Thread* thread = wait_set_; wait_set_ = thread->GetWaitNext(); thread->SetWaitNext(nullptr); @@ -632,18 +609,25 @@ bool Monitor::Deflate(Thread* self, mirror::Object* obj) { return false; } // Deflate to a thin lock. - obj->SetLockWord(LockWord::FromThinLockId(owner->GetThreadId(), monitor->lock_count_), false); + LockWord new_lw = LockWord::FromThinLockId(owner->GetThreadId(), monitor->lock_count_, + lw.ReadBarrierState()); + // Assume no concurrent read barrier state changes as mutators are suspended. + obj->SetLockWord(new_lw, false); VLOG(monitor) << "Deflated " << obj << " to thin lock " << owner->GetTid() << " / " << monitor->lock_count_; } else if (monitor->HasHashCode()) { - obj->SetLockWord(LockWord::FromHashCode(monitor->GetHashCode()), false); + LockWord new_lw = LockWord::FromHashCode(monitor->GetHashCode(), lw.ReadBarrierState()); + // Assume no concurrent read barrier state changes as mutators are suspended. + obj->SetLockWord(new_lw, false); VLOG(monitor) << "Deflated " << obj << " to hash monitor " << monitor->GetHashCode(); } else { // No lock and no hash, just put an empty lock word inside the object. - obj->SetLockWord(LockWord(), false); + LockWord new_lw = LockWord::FromDefault(lw.ReadBarrierState()); + // Assume no concurrent read barrier state changes as mutators are suspended. + obj->SetLockWord(new_lw, false); VLOG(monitor) << "Deflated" << obj << " to empty lock word"; } - // The monitor is deflated, mark the object as nullptr so that we know to delete it during the + // The monitor is deflated, mark the object as null so that we know to delete it during the // next GC. monitor->obj_ = GcRoot<mirror::Object>(nullptr); } @@ -686,8 +670,6 @@ void Monitor::InflateThinLocked(Thread* self, Handle<mirror::Object> obj, LockWo Thread* owner; { ScopedThreadStateChange tsc(self, kBlocked); - // Take suspend thread lock to avoid races with threads trying to suspend this one. - MutexLock mu(self, *Locks::thread_list_suspend_thread_lock_); owner = thread_list->SuspendThreadByThreadId(owner_thread_id, false, &timed_out); } if (owner != nullptr) { @@ -717,8 +699,8 @@ static mirror::Object* FakeUnlock(mirror::Object* obj) } mirror::Object* Monitor::MonitorEnter(Thread* self, mirror::Object* obj) { - DCHECK(self != NULL); - DCHECK(obj != NULL); + DCHECK(self != nullptr); + DCHECK(obj != nullptr); obj = FakeLock(obj); uint32_t thread_id = self->GetThreadId(); size_t contention_count = 0; @@ -728,7 +710,7 @@ mirror::Object* Monitor::MonitorEnter(Thread* self, mirror::Object* obj) { LockWord lock_word = h_obj->GetLockWord(true); switch (lock_word.GetState()) { case LockWord::kUnlocked: { - LockWord thin_locked(LockWord::FromThinLockId(thread_id, 0)); + LockWord thin_locked(LockWord::FromThinLockId(thread_id, 0, lock_word.ReadBarrierState())); if (h_obj->CasLockWordWeakSequentiallyConsistent(lock_word, thin_locked)) { // CasLockWord enforces more than the acquire ordering we need here. return h_obj.Get(); // Success! @@ -741,9 +723,18 @@ mirror::Object* Monitor::MonitorEnter(Thread* self, mirror::Object* obj) { // We own the lock, increase the recursion count. uint32_t new_count = lock_word.ThinLockCount() + 1; if (LIKELY(new_count <= LockWord::kThinLockMaxCount)) { - LockWord thin_locked(LockWord::FromThinLockId(thread_id, new_count)); - h_obj->SetLockWord(thin_locked, true); - return h_obj.Get(); // Success! + LockWord thin_locked(LockWord::FromThinLockId(thread_id, new_count, + lock_word.ReadBarrierState())); + if (!kUseReadBarrier) { + h_obj->SetLockWord(thin_locked, true); + return h_obj.Get(); // Success! + } else { + // Use CAS to preserve the read barrier state. + if (h_obj->CasLockWordWeakSequentiallyConsistent(lock_word, thin_locked)) { + return h_obj.Get(); // Success! + } + } + continue; // Go again. } else { // We'd overflow the recursion count, so inflate the monitor. InflateThinLocked(self, h_obj, lock_word, 0); @@ -783,53 +774,64 @@ mirror::Object* Monitor::MonitorEnter(Thread* self, mirror::Object* obj) { } bool Monitor::MonitorExit(Thread* self, mirror::Object* obj) { - DCHECK(self != NULL); - DCHECK(obj != NULL); + DCHECK(self != nullptr); + DCHECK(obj != nullptr); obj = FakeUnlock(obj); - LockWord lock_word = obj->GetLockWord(true); StackHandleScope<1> hs(self); Handle<mirror::Object> h_obj(hs.NewHandle(obj)); - switch (lock_word.GetState()) { - case LockWord::kHashCode: - // Fall-through. - case LockWord::kUnlocked: - FailedUnlock(h_obj.Get(), self, nullptr, nullptr); - return false; // Failure. - case LockWord::kThinLocked: { - uint32_t thread_id = self->GetThreadId(); - uint32_t owner_thread_id = lock_word.ThinLockOwner(); - if (owner_thread_id != thread_id) { - // TODO: there's a race here with the owner dying while we unlock. - Thread* owner = - Runtime::Current()->GetThreadList()->FindThreadByThreadId(lock_word.ThinLockOwner()); - FailedUnlock(h_obj.Get(), self, owner, nullptr); + while (true) { + LockWord lock_word = obj->GetLockWord(true); + switch (lock_word.GetState()) { + case LockWord::kHashCode: + // Fall-through. + case LockWord::kUnlocked: + FailedUnlock(h_obj.Get(), self, nullptr, nullptr); return false; // Failure. - } else { - // We own the lock, decrease the recursion count. - if (lock_word.ThinLockCount() != 0) { - uint32_t new_count = lock_word.ThinLockCount() - 1; - LockWord thin_locked(LockWord::FromThinLockId(thread_id, new_count)); - h_obj->SetLockWord(thin_locked, true); + case LockWord::kThinLocked: { + uint32_t thread_id = self->GetThreadId(); + uint32_t owner_thread_id = lock_word.ThinLockOwner(); + if (owner_thread_id != thread_id) { + // TODO: there's a race here with the owner dying while we unlock. + Thread* owner = + Runtime::Current()->GetThreadList()->FindThreadByThreadId(lock_word.ThinLockOwner()); + FailedUnlock(h_obj.Get(), self, owner, nullptr); + return false; // Failure. } else { - h_obj->SetLockWord(LockWord(), true); + // We own the lock, decrease the recursion count. + LockWord new_lw = LockWord::Default(); + if (lock_word.ThinLockCount() != 0) { + uint32_t new_count = lock_word.ThinLockCount() - 1; + new_lw = LockWord::FromThinLockId(thread_id, new_count, lock_word.ReadBarrierState()); + } else { + new_lw = LockWord::FromDefault(lock_word.ReadBarrierState()); + } + if (!kUseReadBarrier) { + DCHECK_EQ(new_lw.ReadBarrierState(), 0U); + h_obj->SetLockWord(new_lw, true); + // Success! + return true; + } else { + // Use CAS to preserve the read barrier state. + if (h_obj->CasLockWordWeakSequentiallyConsistent(lock_word, new_lw)) { + // Success! + return true; + } + } + continue; // Go again. } - return true; // Success! } - } - case LockWord::kFatLocked: { - Monitor* mon = lock_word.FatLockMonitor(); - return mon->Unlock(self); - } - default: { - LOG(FATAL) << "Invalid monitor state " << lock_word.GetState(); - return false; + case LockWord::kFatLocked: { + Monitor* mon = lock_word.FatLockMonitor(); + return mon->Unlock(self); + } + default: { + LOG(FATAL) << "Invalid monitor state " << lock_word.GetState(); + return false; + } } } } -/* - * Object.wait(). Also called for class init. - */ void Monitor::Wait(Thread* self, mirror::Object *obj, int64_t ms, int32_t ns, bool interruptShouldThrow, ThreadState why) { DCHECK(self != nullptr); @@ -920,7 +922,7 @@ uint32_t Monitor::GetLockOwnerThreadId(mirror::Object* obj) { } default: { LOG(FATAL) << "Unreachable"; - return ThreadList::kInvalidThreadId; + UNREACHABLE(); } } } @@ -960,8 +962,11 @@ void Monitor::DescribeWait(std::ostream& os, const Thread* thread) { PrettyTypeOf(pretty_object).c_str()); } else { // - waiting on <0x6008c468> (a java.lang.Class<java.lang.ref.ReferenceQueue>) + // Call PrettyTypeOf before IdentityHashCode since IdentityHashCode can cause thread + // suspension and move pretty_object. + const std::string pretty_type(PrettyTypeOf(pretty_object)); os << wait_message << StringPrintf("<0x%08x> (a %s)", pretty_object->IdentityHashCode(), - PrettyTypeOf(pretty_object).c_str()); + pretty_type.c_str()); } } // - waiting to lock <0x613f83d8> (a java.lang.Object) held by thread 5 @@ -976,11 +981,11 @@ mirror::Object* Monitor::GetContendedMonitor(Thread* thread) { // This is used to implement JDWP's ThreadReference.CurrentContendedMonitor, and has a bizarre // definition of contended that includes a monitor a thread is trying to enter... mirror::Object* result = thread->GetMonitorEnterObject(); - if (result == NULL) { + if (result == nullptr) { // ...but also a monitor that the thread is waiting on. MutexLock mu(Thread::Current(), *thread->GetWaitMutex()); Monitor* monitor = thread->GetWaitMonitor(); - if (monitor != NULL) { + if (monitor != nullptr) { result = monitor->GetObject(); } } @@ -989,14 +994,15 @@ mirror::Object* Monitor::GetContendedMonitor(Thread* thread) { void Monitor::VisitLocks(StackVisitor* stack_visitor, void (*callback)(mirror::Object*, void*), void* callback_context, bool abort_on_failure) { - mirror::ArtMethod* m = stack_visitor->GetMethod(); - CHECK(m != NULL); + ArtMethod* m = stack_visitor->GetMethod(); + CHECK(m != nullptr); // Native methods are an easy special case. // TODO: use the JNI implementation's table of explicit MonitorEnter calls and dump those too. if (m->IsNative()) { if (m->IsSynchronized()) { - mirror::Object* jni_this = stack_visitor->GetCurrentHandleScope()->GetReference(0); + mirror::Object* jni_this = + stack_visitor->GetCurrentHandleScope(sizeof(void*))->GetReference(0); callback(jni_this, callback_context); } return; @@ -1010,7 +1016,7 @@ void Monitor::VisitLocks(StackVisitor* stack_visitor, void (*callback)(mirror::O // Is there any reason to believe there's any synchronization in this method? const DexFile::CodeItem* code_item = m->GetCodeItem(); - CHECK(code_item != NULL) << PrettyMethod(m); + CHECK(code_item != nullptr) << PrettyMethod(m); if (code_item->tries_size_ == 0) { return; // No "tries" implies no synchronization, so no held locks to report. } @@ -1028,25 +1034,23 @@ void Monitor::VisitLocks(StackVisitor* stack_visitor, void (*callback)(mirror::O // the locks held in this stack frame. std::vector<uint32_t> monitor_enter_dex_pcs; verifier::MethodVerifier::FindLocksAtDexPc(m, dex_pc, &monitor_enter_dex_pcs); - if (monitor_enter_dex_pcs.empty()) { - return; - } - - for (size_t i = 0; i < monitor_enter_dex_pcs.size(); ++i) { + for (uint32_t monitor_dex_pc : monitor_enter_dex_pcs) { // The verifier works in terms of the dex pcs of the monitor-enter instructions. // We want the registers used by those instructions (so we can read the values out of them). - uint32_t dex_pc = monitor_enter_dex_pcs[i]; - uint16_t monitor_enter_instruction = code_item->insns_[dex_pc]; + uint16_t monitor_enter_instruction = code_item->insns_[monitor_dex_pc]; // Quick sanity check. if ((monitor_enter_instruction & 0xff) != Instruction::MONITOR_ENTER) { - LOG(FATAL) << "expected monitor-enter @" << dex_pc << "; was " + LOG(FATAL) << "expected monitor-enter @" << monitor_dex_pc << "; was " << reinterpret_cast<void*>(monitor_enter_instruction); } uint16_t monitor_register = ((monitor_enter_instruction >> 8) & 0xff); - mirror::Object* o = reinterpret_cast<mirror::Object*>(stack_visitor->GetVReg(m, monitor_register, - kReferenceVReg)); + uint32_t value; + bool success = stack_visitor->GetVReg(m, monitor_register, kReferenceVReg, &value); + CHECK(success) << "Failed to read v" << monitor_register << " of kind " + << kReferenceVReg << " in method " << PrettyMethod(m); + mirror::Object* o = reinterpret_cast<mirror::Object*>(value); callback(o, callback_context); } } @@ -1075,7 +1079,7 @@ bool Monitor::IsValidLockWord(LockWord lock_word) { return true; default: LOG(FATAL) << "Unreachable"; - return false; + UNREACHABLE(); } } @@ -1084,16 +1088,16 @@ bool Monitor::IsLocked() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return owner_ != nullptr; } -void Monitor::TranslateLocation(mirror::ArtMethod* method, uint32_t dex_pc, +void Monitor::TranslateLocation(ArtMethod* method, uint32_t dex_pc, const char** source_file, uint32_t* line_number) const { // If method is null, location is unknown - if (method == NULL) { + if (method == nullptr) { *source_file = ""; *line_number = 0; return; } *source_file = method->GetDeclaringClassSourceFile(); - if (*source_file == NULL) { + if (*source_file == nullptr) { *source_file = ""; } *line_number = method->GetLineNumFromDexPC(dex_pc); @@ -1102,7 +1106,7 @@ void Monitor::TranslateLocation(mirror::ArtMethod* method, uint32_t dex_pc, uint32_t Monitor::GetOwnerThreadId() { MutexLock mu(Thread::Current(), monitor_lock_); Thread* owner = owner_; - if (owner != NULL) { + if (owner != nullptr) { return owner->GetThreadId(); } else { return ThreadList::kInvalidThreadId; @@ -1135,6 +1139,13 @@ void MonitorList::AllowNewMonitors() { monitor_add_condition_.Broadcast(self); } +void MonitorList::EnsureNewMonitorsDisallowed() { + // Lock and unlock once to ensure that no threads are still in the + // middle of adding new monitors. + MutexLock mu(Thread::Current(), monitor_list_lock_); + CHECK(!allow_new_monitors_); +} + void MonitorList::Add(Monitor* m) { Thread* self = Thread::Current(); MutexLock mu(self, monitor_list_lock_); @@ -1177,7 +1188,7 @@ static mirror::Object* MonitorDeflateCallback(mirror::Object* object, void* arg) if (Monitor::Deflate(args->self, object)) { DCHECK_NE(object->GetLockWord(true).GetState(), LockWord::kFatLocked); ++args->deflate_count; - // If we deflated, return nullptr so that the monitor gets removed from the array. + // If we deflated, return null so that the monitor gets removed from the array. return nullptr; } return object; // Monitor was not deflated. @@ -1190,7 +1201,7 @@ size_t MonitorList::DeflateMonitors() { return args.deflate_count; } -MonitorInfo::MonitorInfo(mirror::Object* obj) : owner_(NULL), entry_count_(0) { +MonitorInfo::MonitorInfo(mirror::Object* obj) : owner_(nullptr), entry_count_(0) { DCHECK(obj != nullptr); LockWord lock_word = obj->GetLockWord(true); switch (lock_word.GetState()) { @@ -1209,7 +1220,7 @@ MonitorInfo::MonitorInfo(mirror::Object* obj) : owner_(NULL), entry_count_(0) { Monitor* mon = lock_word.FatLockMonitor(); owner_ = mon->owner_; entry_count_ = 1 + mon->lock_count_; - for (Thread* waiter = mon->wait_set_; waiter != NULL; waiter = waiter->GetWaitNext()) { + for (Thread* waiter = mon->wait_set_; waiter != nullptr; waiter = waiter->GetWaitNext()) { waiters_.push_back(waiter); } break; |