diff options
| -rw-r--r-- | src/monitor.cc | 57 | ||||
| -rw-r--r-- | src/monitor.h | 14 | ||||
| -rw-r--r-- | src/monitor_android.cc | 2 | ||||
| -rw-r--r-- | src/thread.cc | 38 | ||||
| -rw-r--r-- | src/thread.h | 5 |
5 files changed, 62 insertions, 54 deletions
diff --git a/src/monitor.cc b/src/monitor.cc index 16298aed86..b9a94590f3 100644 --- a/src/monitor.cc +++ b/src/monitor.cc @@ -24,6 +24,7 @@ #include <time.h> #include <unistd.h> +#include "class_linker.h" #include "mutex.h" #include "object.h" #include "stl_util.h" @@ -120,8 +121,8 @@ Monitor::Monitor(Object* obj) obj_(obj), wait_set_(NULL), lock_("a monitor lock"), - owner_filename_(NULL), - owner_line_number_(0) { + locking_method_(NULL), + locking_pc_(0) { } Monitor::~Monitor() { @@ -197,15 +198,15 @@ void Monitor::Lock(Thread* self) { uint64_t waitStart, waitEnd; if (!lock_.TryLock()) { uint32_t wait_threshold = lock_profiling_threshold_; - const char* current_owner_filename = NULL; - uint32_t current_owner_line_number = -1; + const Method* current_locking_method = NULL; + uint32_t current_locking_pc = 0; { ScopedThreadStateChange tsc(self, Thread::kBlocked); if (wait_threshold != 0) { waitStart = NanoTime() / 1000; } - current_owner_filename = owner_filename_; - current_owner_line_number = owner_line_number_; + current_locking_method = locking_method_; + current_locking_pc = locking_pc_; lock_.Lock(); if (wait_threshold != 0) { @@ -222,7 +223,11 @@ void Monitor::Lock(Thread* self) { sample_percent = 100 * wait_ms / wait_threshold; } if (sample_percent != 0 && (static_cast<uint32_t>(rand() % 100) < sample_percent)) { - LogContentionEvent(self, wait_ms, sample_percent, current_owner_filename, current_owner_line_number); + const char* current_locking_filename; + uint32_t current_locking_line_number; + TranslateLocation(current_locking_method, current_locking_pc, + current_locking_filename, current_locking_line_number); + LogContentionEvent(self, wait_ms, sample_percent, current_locking_filename, current_locking_line_number); } } } @@ -232,7 +237,8 @@ void Monitor::Lock(Thread* self) { // When debugging, save the current monitor holder for future // acquisition failures to use in sampled logging. if (lock_profiling_threshold_ != 0) { - self->GetCurrentLocation(owner_filename_, owner_line_number_); + locking_method_ = self->GetCurrentMethod(); + locking_pc_ = self->GetCurrentReturnPc(); } } @@ -246,8 +252,8 @@ bool Monitor::Unlock(Thread* self) { // We own the monitor, so nobody else can be in here. if (lock_count_ == 0) { owner_ = NULL; - owner_filename_ = "unlocked"; - owner_line_number_ = 0; + locking_method_ = NULL; + locking_pc_ = 0; lock_.Unlock(); } else { --lock_count_; @@ -366,10 +372,10 @@ void Monitor::Wait(Thread* self, int64_t ms, int32_t ns, bool interruptShouldThr int prevLockCount = lock_count_; lock_count_ = 0; owner_ = NULL; - const char* savedFileName = owner_filename_; - owner_filename_ = NULL; - uint32_t savedLineNumber = owner_line_number_; - owner_line_number_ = 0; + const Method* savedMethod = locking_method_; + locking_method_ = NULL; + uint32_t savedPc = locking_pc_; + locking_pc_ = 0; /* * Update thread status. If the GC wakes up, it'll ignore us, knowing @@ -435,8 +441,8 @@ done: */ owner_ = self; lock_count_ = prevLockCount; - owner_filename_ = savedFileName; - owner_line_number_ = savedLineNumber; + locking_method_ = savedMethod; + locking_pc_ = savedPc; RemoveFromWaitSet(self); /* set self->status back to Thread::kRunnable, and self-suspend if needed */ @@ -810,6 +816,25 @@ void Monitor::DescribeWait(std::ostream& os, const Thread* thread) { os << "\n"; } +void Monitor::TranslateLocation(const Method* method, uint32_t pc, + const char*& source_file, uint32_t& line_number) const { + // If method is null, location is unknown + if (method == NULL) { + source_file = "unknown"; + line_number = 0; + return; + } + + ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); + Class* c = method->GetDeclaringClass(); + DexCache* dex_cache = c->GetDexCache(); + const DexFile& dex_file = class_linker->FindDexFile(dex_cache); + const DexFile::ClassDef* class_def = dex_file.FindClassDef(c->GetDescriptor()->ToModifiedUtf8()); + + source_file = dex_file.dexGetSourceFile(*class_def); + line_number = dex_file.GetLineNumFromPC(method, method->ToDexPC(pc)); +} + MonitorList::MonitorList() : lock_("MonitorList lock") { } diff --git a/src/monitor.h b/src/monitor.h index be704bab54..9b79f8ec27 100644 --- a/src/monitor.h +++ b/src/monitor.h @@ -55,6 +55,7 @@ namespace art { #define LW_LOCK_OWNER_SHIFT 3 #define LW_LOCK_OWNER(x) (((x) >> LW_LOCK_OWNER_SHIFT) & LW_LOCK_OWNER_MASK) +class Method; class Object; class Thread; @@ -97,6 +98,10 @@ class Monitor { void Wait(Thread* self, int64_t msec, int32_t nsec, bool interruptShouldThrow); + // Translates the provided method and pc into its declaring class' source file and line number. + void TranslateLocation(const Method* method, uint32_t pc, + const char*& source_file, uint32_t& line_number) const; + static bool (*is_sensitive_thread_hook_)(); static bool is_verbose_; static uint32_t lock_profiling_threshold_; @@ -115,10 +120,11 @@ class Monitor { Mutex lock_; - // Who last acquired this monitor, when lock sampling is enabled. - // Even when enabled, owner_filename_ may be NULL. - const char* owner_filename_; - uint32_t owner_line_number_; + // Method and pc where the lock owner acquired the lock, used when lock + // sampling is enabled. locking_method_ may be null if the lock is currently + // unlocked, or if the lock is acquired by the system when the stack is empty. + const Method* locking_method_; + uint32_t locking_pc_; friend class MonitorList; friend class Object; diff --git a/src/monitor_android.cc b/src/monitor_android.cc index 95dd397042..39dc5244d1 100644 --- a/src/monitor_android.cc +++ b/src/monitor_android.cc @@ -78,7 +78,7 @@ void Monitor::LogContentionEvent(Thread* self, uint32_t wait_ms, uint32_t sample // Emit the source code file name, <= 37 bytes. const char* filename; uint32_t line_number; - self->GetCurrentLocation(filename, line_number); + TranslateLocation(self->GetCurrentMethod(), self->GetCurrentReturnPc(), filename, line_number); cp = EventLogWriteString(cp, filename, strlen(filename)); // Emit the source code line number, 5 bytes. diff --git a/src/thread.cc b/src/thread.cc index 2bdfb3c73d..5dd0f2dca2 100644 --- a/src/thread.cc +++ b/src/thread.cc @@ -1191,35 +1191,6 @@ jobjectArray Thread::InternalStackTraceToStackTraceElementArray(JNIEnv* env, job return result; } -void Thread::GetCurrentLocation(const char*& source_file, uint32_t& line_number) const { - Frame f = top_of_managed_stack_; - Method* m = f.GetMethod(); - - // Check if the stack is empty - if (m == NULL) { - source_file = "UNKNOWN"; - line_number = 0; - return; - } - - // TODO: can this ever happen? - if (m->IsCalleeSaveMethod()) { - f.Next(); - m = f.GetMethod(); - } - - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - Class* c = m->GetDeclaringClass(); - DexCache* dex_cache = c->GetDexCache(); - const DexFile& dex_file = class_linker->FindDexFile(dex_cache); - const DexFile::ClassDef* class_def = dex_file.FindClassDef(c->GetDescriptor()->ToModifiedUtf8()); - - source_file = dex_file.dexGetSourceFile(*class_def); - - uint32_t pc = ManglePc(f.GetReturnPC()); - line_number = dex_file.GetLineNumFromPC(m, m->ToDexPC(pc)); -} - void Thread::ThrowNewExceptionF(const char* exception_class_descriptor, const char* fmt, ...) { va_list args; va_start(args, fmt); @@ -1399,7 +1370,7 @@ const Method* Thread::GetCurrentMethod() const { // here via a "FromCode" function, in which case there's a synthetic // callee-save method at the top of the stack. These shouldn't be user-visible, // so if we find one, skip it and return the compiled method underneath. - if (m->IsCalleeSaveMethod()) { + if (m != NULL && m->IsCalleeSaveMethod()) { Frame f = top_of_managed_stack_; f.Next(); m = f.GetMethod(); @@ -1407,6 +1378,13 @@ const Method* Thread::GetCurrentMethod() const { return m; } +uint32_t Thread::GetCurrentReturnPc() const { + if (top_of_managed_stack_.GetMethod() == NULL) { + return 0; + } + return ManglePc(top_of_managed_stack_.GetReturnPC()); +} + bool Thread::HoldsLock(Object* object) { if (object == NULL) { return false; diff --git a/src/thread.h b/src/thread.h index 15ded2490c..7b8c8b9524 100644 --- a/src/thread.h +++ b/src/thread.h @@ -229,9 +229,6 @@ class PACKED Thread { // Returns the java.lang.Thread's name, or NULL. String* GetName() const; - // Returns the current method's declaring class' source file and the current line number. - void GetCurrentLocation(const char*& source_file, uint32_t& line_number) const; - Object* GetPeer() const { return peer_; } @@ -244,6 +241,8 @@ class PACKED Thread { // This is used by the JNI implementation for logging and diagnostic purposes. const Method* GetCurrentMethod() const; + uint32_t GetCurrentReturnPc() const; + bool IsExceptionPending() const { return exception_ != NULL; } |