summaryrefslogtreecommitdiff
path: root/runtime/monitor.cc
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/monitor.cc')
-rw-r--r--runtime/monitor.cc307
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;