summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/monitor.cc57
-rw-r--r--src/monitor.h14
-rw-r--r--src/monitor_android.cc2
-rw-r--r--src/thread.cc38
-rw-r--r--src/thread.h5
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;
}