summaryrefslogtreecommitdiffstats
path: root/runtime/debugger.cc
diff options
context:
space:
mode:
authorSebastien Hertz <shertz@google.com>2014-09-09 12:10:13 +0200
committerSebastien Hertz <shertz@google.com>2014-09-18 14:31:54 +0200
commit6995c60cd6657c10811055c42661a55b10b47cef (patch)
tree6fc528bca6f0c6fb989f88cb6af6c4829e1da172 /runtime/debugger.cc
parentd41491adb23764f28a80cbb7f2bd7af6491cd892 (diff)
downloadart-6995c60cd6657c10811055c42661a55b10b47cef.tar.gz
art-6995c60cd6657c10811055c42661a55b10b47cef.tar.bz2
art-6995c60cd6657c10811055c42661a55b10b47cef.zip
Update JDWP event filtering to avoid useless ids
To reduce the number of JDWP ids in the debugger, we update the event filtering support to work with runtime objects (Thread, Class, Object, ...) instead of JDWP ids (ThreadId, RefTypeId, ObjectId, ...). We used to create useless JDWP ids for events even if they were not reported because of event filtering (thread only, class only, instance only, ...). Now we only create JDWP ids when we know we're going to report an event. Bug: 17343664 (cherry picked from commit d539167b7f11136fe570a77aff2ee4935842007a) Change-Id: I8619e219733fc2fa3569f473b7bd8d9af4181f2b
Diffstat (limited to 'runtime/debugger.cc')
-rw-r--r--runtime/debugger.cc174
1 files changed, 93 insertions, 81 deletions
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 6c374029d8..aced95465b 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -311,7 +311,7 @@ static Dbg::HpsgWhat gDdmHpsgWhat;
static Dbg::HpsgWhen gDdmNhsgWhen = Dbg::HPSG_WHEN_NEVER;
static Dbg::HpsgWhat gDdmNhsgWhat;
-static ObjectRegistry* gRegistry = nullptr;
+ObjectRegistry* Dbg::gRegistry = nullptr;
// Recent allocation tracking.
AllocRecord* Dbg::recent_allocation_records_ = nullptr; // TODO: CircularBuffer<AllocRecord>
@@ -401,7 +401,7 @@ static bool IsSuspendedForDebugger(ScopedObjectAccessUnchecked& soa, Thread* thr
static mirror::Array* DecodeNonNullArray(JDWP::RefTypeId id, JDWP::JdwpError* error)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- mirror::Object* o = gRegistry->Get<mirror::Object*>(id, error);
+ mirror::Object* o = Dbg::GetObjectRegistry()->Get<mirror::Object*>(id, error);
if (o == nullptr) {
*error = JDWP::ERR_INVALID_OBJECT;
return nullptr;
@@ -416,7 +416,7 @@ static mirror::Array* DecodeNonNullArray(JDWP::RefTypeId id, JDWP::JdwpError* er
static mirror::Class* DecodeClass(JDWP::RefTypeId id, JDWP::JdwpError* error)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- mirror::Object* o = gRegistry->Get<mirror::Object*>(id, error);
+ mirror::Object* o = Dbg::GetObjectRegistry()->Get<mirror::Object*>(id, error);
if (o == nullptr) {
*error = JDWP::ERR_INVALID_OBJECT;
return nullptr;
@@ -434,7 +434,7 @@ static Thread* DecodeThread(ScopedObjectAccessUnchecked& soa, JDWP::ObjectId thr
EXCLUSIVE_LOCKS_REQUIRED(Locks::thread_list_lock_)
LOCKS_EXCLUDED(Locks::thread_suspend_count_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- mirror::Object* thread_peer = gRegistry->Get<mirror::Object*>(thread_id, error);
+ mirror::Object* thread_peer = Dbg::GetObjectRegistry()->Get<mirror::Object*>(thread_id, error);
if (thread_peer == nullptr) {
// This isn't even an object.
*error = JDWP::ERR_INVALID_OBJECT;
@@ -511,8 +511,7 @@ static JDWP::JdwpTag TagFromClass(const ScopedObjectAccessUnchecked& soa, mirror
*
* Null objects are tagged JT_OBJECT.
*/
-static JDWP::JdwpTag TagFromObject(const ScopedObjectAccessUnchecked& soa, mirror::Object* o)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+JDWP::JdwpTag Dbg::TagFromObject(const ScopedObjectAccessUnchecked& soa, mirror::Object* o) {
return (o == nullptr) ? JDWP::JT_OBJECT : TagFromClass(soa, o->GetClass());
}
@@ -842,8 +841,13 @@ std::string Dbg::GetClassName(JDWP::RefTypeId class_id) {
if (!o->IsClass()) {
return StringPrintf("non-class %p", o); // This is only used for debugging output anyway.
}
+ return GetClassName(o->AsClass());
+}
+
+std::string Dbg::GetClassName(mirror::Class* klass) {
+ DCHECK(klass != nullptr);
std::string temp;
- return DescriptorToName(o->AsClass()->GetDescriptor(&temp));
+ return DescriptorToName(klass->GetDescriptor(&temp));
}
JDWP::JdwpError Dbg::GetClassObject(JDWP::RefTypeId id, JDWP::ObjectId* class_object_id) {
@@ -1108,8 +1112,7 @@ void Dbg::DisposeObject(JDWP::ObjectId object_id, uint32_t reference_count) {
gRegistry->DisposeObject(object_id, reference_count);
}
-static JDWP::JdwpTypeTag GetTypeTag(mirror::Class* klass)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+JDWP::JdwpTypeTag Dbg::GetTypeTag(mirror::Class* klass) {
DCHECK(klass != nullptr);
if (klass->IsArrayClass()) {
return JDWP::TT_ARRAY;
@@ -1422,17 +1425,7 @@ JDWP::JdwpError Dbg::CreateArrayObject(JDWP::RefTypeId array_class_id, uint32_t
return JDWP::ERR_NONE;
}
-bool Dbg::MatchType(JDWP::RefTypeId instance_class_id, JDWP::RefTypeId class_id) {
- JDWP::JdwpError error;
- mirror::Class* c1 = DecodeClass(instance_class_id, &error);
- CHECK(c1 != nullptr);
- mirror::Class* c2 = DecodeClass(class_id, &error);
- CHECK(c2 != nullptr);
- return c2->IsAssignableFrom(c1);
-}
-
-static JDWP::FieldId ToFieldId(const mirror::ArtField* f)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+JDWP::FieldId Dbg::ToFieldId(const mirror::ArtField* f) {
CHECK(!kMovingFields);
return static_cast<JDWP::FieldId>(reinterpret_cast<uintptr_t>(f));
}
@@ -1455,10 +1448,49 @@ static mirror::ArtMethod* FromMethodId(JDWP::MethodId mid)
return reinterpret_cast<mirror::ArtMethod*>(static_cast<uintptr_t>(mid));
}
-static void SetLocation(JDWP::JdwpLocation* location, mirror::ArtMethod* m, uint32_t dex_pc)
+bool Dbg::MatchThread(JDWP::ObjectId expected_thread_id, Thread* event_thread) {
+ CHECK(event_thread != nullptr);
+ JDWP::JdwpError error;
+ mirror::Object* expected_thread_peer = gRegistry->Get<mirror::Object*>(expected_thread_id,
+ &error);
+ return expected_thread_peer == event_thread->GetPeer();
+}
+
+bool Dbg::MatchLocation(const JDWP::JdwpLocation& expected_location,
+ const JDWP::EventLocation& event_location) {
+ if (expected_location.dex_pc != event_location.dex_pc) {
+ return false;
+ }
+ mirror::ArtMethod* m = FromMethodId(expected_location.method_id);
+ return m == event_location.method;
+}
+
+bool Dbg::MatchType(mirror::Class* event_class, JDWP::RefTypeId class_id) {
+ JDWP::JdwpError error;
+ mirror::Class* expected_class = DecodeClass(class_id, &error);
+ CHECK(expected_class != nullptr);
+ return expected_class->IsAssignableFrom(event_class);
+}
+
+bool Dbg::MatchField(JDWP::RefTypeId expected_type_id, JDWP::FieldId expected_field_id,
+ mirror::ArtField* event_field) {
+ mirror::ArtField* expected_field = FromFieldId(expected_field_id);
+ if (expected_field != event_field) {
+ return false;
+ }
+ return Dbg::MatchType(event_field->GetDeclaringClass(), expected_type_id);
+}
+
+bool Dbg::MatchInstance(JDWP::ObjectId expected_instance_id, mirror::Object* event_instance) {
+ JDWP::JdwpError error;
+ mirror::Object* modifier_instance = gRegistry->Get<mirror::Object*>(expected_instance_id, &error);
+ return modifier_instance == event_instance;
+}
+
+void Dbg::SetJdwpLocation(JDWP::JdwpLocation* location, mirror::ArtMethod* m, uint32_t dex_pc)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
if (m == nullptr) {
- memset(&location, 0, sizeof(location));
+ memset(&location, 0, sizeof(*location));
} else {
mirror::Class* c = m->GetDeclaringClass();
location->type_tag = GetTypeTag(c);
@@ -1757,7 +1789,7 @@ static JDWP::JdwpError GetFieldValueImpl(JDWP::RefTypeId ref_type_id, JDWP::Obje
return error;
}
- mirror::Object* o = gRegistry->Get<mirror::Object*>(object_id, &error);
+ mirror::Object* o = Dbg::GetObjectRegistry()->Get<mirror::Object*>(object_id, &error);
if ((!is_static && o == nullptr) || error != JDWP::ERR_NONE) {
return JDWP::ERR_INVALID_OBJECT;
}
@@ -1819,7 +1851,7 @@ static JDWP::JdwpError SetFieldValueImpl(JDWP::ObjectId object_id, JDWP::FieldId
uint64_t value, int width, bool is_static)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
JDWP::JdwpError error;
- mirror::Object* o = gRegistry->Get<mirror::Object*>(object_id, &error);
+ mirror::Object* o = Dbg::GetObjectRegistry()->Get<mirror::Object*>(object_id, &error);
if ((!is_static && o == nullptr) || error != JDWP::ERR_NONE) {
return JDWP::ERR_INVALID_OBJECT;
}
@@ -1853,7 +1885,7 @@ static JDWP::JdwpError SetFieldValueImpl(JDWP::ObjectId object_id, JDWP::FieldId
f->Set32<false>(o, value);
}
} else {
- mirror::Object* v = gRegistry->Get<mirror::Object*>(value, &error);
+ mirror::Object* v = Dbg::GetObjectRegistry()->Get<mirror::Object*>(value, &error);
if (error != JDWP::ERR_NONE) {
return JDWP::ERR_INVALID_OBJECT;
}
@@ -1987,7 +2019,8 @@ JDWP::JdwpError Dbg::GetThreadGroup(JDWP::ObjectId thread_id, JDWP::ExpandBuf* p
static mirror::Object* DecodeThreadGroup(ScopedObjectAccessUnchecked& soa,
JDWP::ObjectId thread_group_id, JDWP::JdwpError* error)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- mirror::Object* thread_group = gRegistry->Get<mirror::Object*>(thread_group_id, error);
+ mirror::Object* thread_group = Dbg::GetObjectRegistry()->Get<mirror::Object*>(thread_group_id,
+ error);
if (*error != JDWP::ERR_NONE) {
return nullptr;
}
@@ -2062,8 +2095,9 @@ static void GetChildThreadGroups(ScopedObjectAccessUnchecked& soa, mirror::Objec
const int32_t size = size_field->GetInt(groups_array_list);
// Copy the first 'size' elements out of the array into the result.
+ ObjectRegistry* registry = Dbg::GetObjectRegistry();
for (int32_t i = 0; i < size; ++i) {
- child_thread_group_ids->push_back(gRegistry->Add(groups_array->Get(i)));
+ child_thread_group_ids->push_back(registry->Add(groups_array->Get(i)));
}
}
@@ -2296,7 +2330,7 @@ JDWP::JdwpError Dbg::GetThreadFrames(JDWP::ObjectId thread_id, size_t start_fram
if (depth_ >= start_frame_) {
JDWP::FrameId frame_id(GetFrameId());
JDWP::JdwpLocation location;
- SetLocation(&location, GetMethod(), GetDexPc());
+ SetJdwpLocation(&location, GetMethod(), GetDexPc());
VLOG(jdwp) << StringPrintf(" Frame %3zd: id=%3" PRIu64 " ", depth_, frame_id) << location;
expandBufAdd8BE(buf_, frame_id);
expandBufAddLocation(buf_, location);
@@ -2328,8 +2362,12 @@ JDWP::JdwpError Dbg::GetThreadFrames(JDWP::ObjectId thread_id, size_t start_fram
}
JDWP::ObjectId Dbg::GetThreadSelfId() {
+ return GetThreadId(Thread::Current());
+}
+
+JDWP::ObjectId Dbg::GetThreadId(Thread* thread) {
ScopedObjectAccessUnchecked soa(Thread::Current());
- return gRegistry->Add(soa.Self()->GetPeer());
+ return gRegistry->Add(thread->GetPeer());
}
void Dbg::SuspendVM() {
@@ -2733,16 +2771,15 @@ JDWP::JdwpError Dbg::SetLocalValue(JDWP::ObjectId thread_id, JDWP::FrameId frame
return visitor.error_;
}
-JDWP::ObjectId Dbg::GetThisObjectIdForEvent(mirror::Object* this_object) {
- // If 'this_object' isn't already in the registry, we know that we're not looking for it, so
- // there's no point adding it to the registry and burning through ids.
- // When registering an event request with an instance filter, we've been given an existing object
- // id so it must already be present in the registry when the event fires.
- JDWP::ObjectId this_id = 0;
- if (this_object != nullptr && gRegistry->Contains(this_object)) {
- this_id = gRegistry->Add(this_object);
+static void SetEventLocation(JDWP::EventLocation* location, mirror::ArtMethod* m, uint32_t dex_pc)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ DCHECK(location != nullptr);
+ if (m == nullptr) {
+ memset(location, 0, sizeof(*location));
+ } else {
+ location->method = m;
+ location->dex_pc = (m->IsNative() || m->IsProxyMethod()) ? static_cast<uint32_t>(-1) : dex_pc;
}
- return this_id;
}
void Dbg::PostLocationEvent(mirror::ArtMethod* m, int dex_pc, mirror::Object* this_object,
@@ -2752,12 +2789,10 @@ void Dbg::PostLocationEvent(mirror::ArtMethod* m, int dex_pc, mirror::Object* th
}
DCHECK(m != nullptr);
DCHECK_EQ(m->IsStatic(), this_object == nullptr);
- JDWP::JdwpLocation location;
- SetLocation(&location, m, dex_pc);
+ JDWP::EventLocation location;
+ SetEventLocation(&location, m, dex_pc);
- // We need 'this' for InstanceOnly filters only.
- JDWP::ObjectId this_id = GetThisObjectIdForEvent(this_object);
- gJdwpState->PostLocationEvent(&location, this_id, event_flags, return_value);
+ gJdwpState->PostLocationEvent(&location, this_object, event_flags, return_value);
}
void Dbg::PostFieldAccessEvent(mirror::ArtMethod* m, int dex_pc,
@@ -2767,14 +2802,10 @@ void Dbg::PostFieldAccessEvent(mirror::ArtMethod* m, int dex_pc,
}
DCHECK(m != nullptr);
DCHECK(f != nullptr);
- JDWP::JdwpLocation location;
- SetLocation(&location, m, dex_pc);
+ JDWP::EventLocation location;
+ SetEventLocation(&location, m, dex_pc);
- JDWP::RefTypeId type_id = gRegistry->AddRefType(f->GetDeclaringClass());
- JDWP::FieldId field_id = ToFieldId(f);
- JDWP::ObjectId this_id = gRegistry->Add(this_object);
-
- gJdwpState->PostFieldEvent(&location, type_id, field_id, this_id, nullptr, false);
+ gJdwpState->PostFieldEvent(&location, f, this_object, nullptr, false);
}
void Dbg::PostFieldModificationEvent(mirror::ArtMethod* m, int dex_pc,
@@ -2786,14 +2817,10 @@ void Dbg::PostFieldModificationEvent(mirror::ArtMethod* m, int dex_pc,
DCHECK(m != nullptr);
DCHECK(f != nullptr);
DCHECK(field_value != nullptr);
- JDWP::JdwpLocation location;
- SetLocation(&location, m, dex_pc);
-
- JDWP::RefTypeId type_id = gRegistry->AddRefType(f->GetDeclaringClass());
- JDWP::FieldId field_id = ToFieldId(f);
- JDWP::ObjectId this_id = gRegistry->Add(this_object);
+ JDWP::EventLocation location;
+ SetEventLocation(&location, m, dex_pc);
- gJdwpState->PostFieldEvent(&location, type_id, field_id, this_id, field_value, true);
+ gJdwpState->PostFieldEvent(&location, f, this_object, field_value, true);
}
void Dbg::PostException(const ThrowLocation& throw_location,
@@ -2802,33 +2829,20 @@ void Dbg::PostException(const ThrowLocation& throw_location,
if (!IsDebuggerActive()) {
return;
}
+ JDWP::EventLocation exception_throw_location;
+ SetEventLocation(&exception_throw_location, throw_location.GetMethod(), throw_location.GetDexPc());
+ JDWP::EventLocation exception_catch_location;
+ SetEventLocation(&exception_catch_location, catch_method, catch_dex_pc);
- JDWP::JdwpLocation jdwp_throw_location;
- SetLocation(&jdwp_throw_location, throw_location.GetMethod(), throw_location.GetDexPc());
- JDWP::JdwpLocation catch_location;
- SetLocation(&catch_location, catch_method, catch_dex_pc);
-
- // We need 'this' for InstanceOnly filters only.
- JDWP::ObjectId this_id = GetThisObjectIdForEvent(throw_location.GetThis());
- JDWP::ObjectId exception_id = gRegistry->Add(exception_object);
- JDWP::RefTypeId exception_class_id = gRegistry->AddRefType(exception_object->GetClass());
-
- gJdwpState->PostException(&jdwp_throw_location, exception_id, exception_class_id, &catch_location,
- this_id);
+ gJdwpState->PostException(&exception_throw_location, exception_object, &exception_catch_location,
+ throw_location.GetThis());
}
void Dbg::PostClassPrepare(mirror::Class* c) {
if (!IsDebuggerActive()) {
return;
}
-
- // OLD-TODO - we currently always send both "verified" and "prepared" since
- // debuggers seem to like that. There might be some advantage to honesty,
- // since the class may not yet be verified.
- int state = JDWP::CS_VERIFIED | JDWP::CS_PREPARED;
- JDWP::JdwpTypeTag tag = GetTypeTag(c);
- std::string temp;
- gJdwpState->PostClassPrepare(tag, gRegistry->Add(c), c->GetDescriptor(&temp), state);
+ gJdwpState->PostClassPrepare(c);
}
void Dbg::UpdateDebugger(Thread* thread, mirror::Object* this_object,
@@ -3245,7 +3259,7 @@ class ScopedThreadSuspension {
self_suspend_ = true;
} else {
soa.Self()->TransitionFromRunnableToSuspended(kWaitingForDebuggerSuspension);
- jobject thread_peer = gRegistry->GetJObject(thread_id);
+ jobject thread_peer = Dbg::GetObjectRegistry()->GetJObject(thread_id);
bool timed_out;
Thread* suspended_thread;
{
@@ -3908,9 +3922,7 @@ void Dbg::DdmSetThreadNotification(bool enable) {
void Dbg::PostThreadStartOrStop(Thread* t, uint32_t type) {
if (IsDebuggerActive()) {
- ScopedObjectAccessUnchecked soa(Thread::Current());
- JDWP::ObjectId id = gRegistry->Add(t->GetPeer());
- gJdwpState->PostThreadChange(id, type == CHUNK_TYPE("THCR"));
+ gJdwpState->PostThreadChange(t, type == CHUNK_TYPE("THCR"));
}
Dbg::DdmSendThreadNotification(t, type);
}