Merge "Update JDWP event filtering to avoid useless ids"
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 6c37402..aced954 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -311,7 +311,7 @@
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 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::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 @@
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 @@
*
* 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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::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 @@
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 @@
}
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 @@
}
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 @@
DCHECK(m != nullptr);
DCHECK(f != nullptr);
DCHECK(field_value != 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, field_value, true);
+ gJdwpState->PostFieldEvent(&location, f, this_object, field_value, true);
}
void Dbg::PostException(const ThrowLocation& throw_location,
@@ -2802,33 +2829,20 @@
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 @@
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::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);
}
diff --git a/runtime/debugger.h b/runtime/debugger.h
index e171d78..97985ec 100644
--- a/runtime/debugger.h
+++ b/runtime/debugger.h
@@ -43,6 +43,8 @@
class Throwable;
} // namespace mirror
class AllocRecord;
+class ObjectRegistry;
+class ScopedObjectAccessUnchecked;
class Thread;
class ThrowLocation;
@@ -250,6 +252,8 @@
*/
static std::string GetClassName(JDWP::RefTypeId id)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ static std::string GetClassName(mirror::Class* klass)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
static JDWP::JdwpError GetClassObject(JDWP::RefTypeId id, JDWP::ObjectId* class_object_id)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
static JDWP::JdwpError GetSuperclass(JDWP::RefTypeId id, JDWP::RefTypeId* superclass_id)
@@ -294,7 +298,24 @@
JDWP::ObjectId* new_array)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static bool MatchType(JDWP::RefTypeId instance_class_id, JDWP::RefTypeId class_id)
+ //
+ // Event filtering.
+ //
+ static bool MatchThread(JDWP::ObjectId expected_thread_id, Thread* event_thread)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ static bool MatchLocation(const JDWP::JdwpLocation& expected_location,
+ const JDWP::EventLocation& event_location)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ static bool MatchType(mirror::Class* event_class, JDWP::RefTypeId class_id)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ static bool MatchField(JDWP::RefTypeId expected_type_id, JDWP::FieldId expected_field_id,
+ mirror::ArtField* event_field)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ static bool MatchInstance(JDWP::ObjectId expected_instance_id, mirror::Object* event_instance)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
//
@@ -431,8 +452,9 @@
LOCKS_EXCLUDED(Locks::thread_list_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static JDWP::ObjectId GetThreadSelfId()
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ static JDWP::ObjectId GetThreadSelfId() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ static JDWP::ObjectId GetThreadId(Thread* thread) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
static void SuspendVM()
LOCKS_EXCLUDED(Locks::thread_list_lock_,
Locks::thread_suspend_count_lock_);
@@ -602,6 +624,22 @@
static void DdmSendHeapSegments(bool native)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ static ObjectRegistry* GetObjectRegistry() {
+ return gRegistry;
+ }
+
+ static JDWP::JdwpTag TagFromObject(const ScopedObjectAccessUnchecked& soa, mirror::Object* o)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ static JDWP::JdwpTypeTag GetTypeTag(mirror::Class* klass)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ static JDWP::FieldId ToFieldId(const mirror::ArtField* f)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ static void SetJdwpLocation(JDWP::JdwpLocation* location, mirror::ArtMethod* m, uint32_t dex_pc)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
private:
static void DdmBroadcast(bool connect) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
static void PostThreadStartOrStop(Thread*, uint32_t)
@@ -612,9 +650,6 @@
const JValue* return_value)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static JDWP::ObjectId GetThisObjectIdForEvent(mirror::Object* this_object)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
static void ProcessDeoptimizationRequest(const DeoptimizationRequest& request)
EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -627,6 +662,8 @@
static size_t alloc_record_head_ GUARDED_BY(Locks::alloc_tracker_lock_);
static size_t alloc_record_count_ GUARDED_BY(Locks::alloc_tracker_lock_);
+ static ObjectRegistry* gRegistry;
+
// Deoptimization requests to be processed each time the event list is updated. This is used when
// registering and unregistering events so we do not deoptimize while holding the event list
// lock.
diff --git a/runtime/jdwp/jdwp.h b/runtime/jdwp/jdwp.h
index b5b6298..0c9451c 100644
--- a/runtime/jdwp/jdwp.h
+++ b/runtime/jdwp/jdwp.h
@@ -36,8 +36,13 @@
class Thread;
namespace mirror {
+ class ArtField;
class ArtMethod;
+ class Class;
+ class Object;
+ class Throwable;
} // namespace mirror
+class Thread;
namespace JDWP {
@@ -65,6 +70,11 @@
static inline void expandBufAddRefTypeId(ExpandBuf* pReply, RefTypeId id) { expandBufAdd8BE(pReply, id); }
static inline void expandBufAddFrameId(ExpandBuf* pReply, FrameId id) { expandBufAdd8BE(pReply, id); }
+struct EventLocation {
+ mirror::ArtMethod* method;
+ uint32_t dex_pc;
+};
+
/*
* Holds a JDWP "location".
*/
@@ -178,7 +188,7 @@
* The VM has finished initializing. Only called when the debugger is
* connected at the time initialization completes.
*/
- bool PostVMStart() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ bool PostVMStart() LOCKS_EXCLUDED(event_list_lock_) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
/*
* A location of interest has been reached. This is used for breakpoints,
@@ -192,8 +202,9 @@
*
* "returnValue" is non-null for MethodExit events only.
*/
- bool PostLocationEvent(const JdwpLocation* pLoc, ObjectId thisPtr, int eventFlags,
+ bool PostLocationEvent(const EventLocation* pLoc, mirror::Object* thisPtr, int eventFlags,
const JValue* returnValue)
+ LOCKS_EXCLUDED(event_list_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
/*
@@ -203,8 +214,9 @@
* "fieldValue" is non-null for field modification events only.
* "is_modification" is true for field modification, false for field access.
*/
- bool PostFieldEvent(const JdwpLocation* pLoc, RefTypeId typeId, FieldId fieldId,
- ObjectId thisPtr, const JValue* fieldValue, bool is_modification)
+ bool PostFieldEvent(const EventLocation* pLoc, mirror::ArtField* field, mirror::Object* thisPtr,
+ const JValue* fieldValue, bool is_modification)
+ LOCKS_EXCLUDED(event_list_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
/*
@@ -212,21 +224,23 @@
*
* Pass in a zeroed-out "*pCatchLoc" if the exception wasn't caught.
*/
- bool PostException(const JdwpLocation* pThrowLoc, ObjectId excepId, RefTypeId excepClassId,
- const JdwpLocation* pCatchLoc, ObjectId thisPtr)
+ bool PostException(const EventLocation* pThrowLoc, mirror::Throwable* exception_object,
+ const EventLocation* pCatchLoc, mirror::Object* thisPtr)
+ LOCKS_EXCLUDED(event_list_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
/*
* A thread has started or stopped.
*/
- bool PostThreadChange(ObjectId threadId, bool start)
+ bool PostThreadChange(Thread* thread, bool start)
+ LOCKS_EXCLUDED(event_list_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
/*
* Class has been prepared.
*/
- bool PostClassPrepare(JdwpTypeTag tag, RefTypeId refTypeId, const std::string& signature,
- int status)
+ bool PostClassPrepare(mirror::Class* klass)
+ LOCKS_EXCLUDED(event_list_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
/*
diff --git a/runtime/jdwp/jdwp_event.cc b/runtime/jdwp/jdwp_event.cc
index fc39cc4..46db63c 100644
--- a/runtime/jdwp/jdwp_event.cc
+++ b/runtime/jdwp/jdwp_event.cc
@@ -27,6 +27,9 @@
#include "jdwp/jdwp_constants.h"
#include "jdwp/jdwp_expand_buf.h"
#include "jdwp/jdwp_priv.h"
+#include "jdwp/object_registry.h"
+#include "mirror/art_field-inl.h"
+#include "scoped_thread_state_change.h"
#include "thread-inl.h"
/*
@@ -107,18 +110,17 @@
* The rest will be zeroed.
*/
struct ModBasket {
- ModBasket() : pLoc(NULL), threadId(0), classId(0), excepClassId(0),
- caught(false), fieldTypeID(0), fieldId(0), thisPtr(0) { }
+ ModBasket() : pLoc(nullptr), thread(nullptr), locationClass(nullptr), exceptionClass(nullptr),
+ caught(false), field(nullptr), thisPtr(nullptr) { }
- const JdwpLocation* pLoc; /* LocationOnly */
- std::string className; /* ClassMatch/ClassExclude */
- ObjectId threadId; /* ThreadOnly */
- RefTypeId classId; /* ClassOnly */
- RefTypeId excepClassId; /* ExceptionOnly */
- bool caught; /* ExceptionOnly */
- RefTypeId fieldTypeID; /* FieldOnly */
- FieldId fieldId; /* FieldOnly */
- ObjectId thisPtr; /* InstanceOnly */
+ const EventLocation* pLoc; /* LocationOnly */
+ std::string className; /* ClassMatch/ClassExclude */
+ Thread* thread; /* ThreadOnly */
+ mirror::Class* locationClass; /* ClassOnly */
+ mirror::Class* exceptionClass; /* ExceptionOnly */
+ bool caught; /* ExceptionOnly */
+ mirror::ArtField* field; /* FieldOnly */
+ mirror::Object* thisPtr; /* InstanceOnly */
/* nothing for StepOnly -- handled differently */
};
@@ -463,12 +465,12 @@
CHECK(false); // should not be getting these
break;
case MK_THREAD_ONLY:
- if (pMod->threadOnly.threadId != basket.threadId) {
+ if (!Dbg::MatchThread(pMod->threadOnly.threadId, basket.thread)) {
return false;
}
break;
case MK_CLASS_ONLY:
- if (!Dbg::MatchType(basket.classId, pMod->classOnly.refTypeId)) {
+ if (!Dbg::MatchType(basket.locationClass, pMod->classOnly.refTypeId)) {
return false;
}
break;
@@ -483,33 +485,32 @@
}
break;
case MK_LOCATION_ONLY:
- if (pMod->locationOnly.loc != *basket.pLoc) {
+ if (!Dbg::MatchLocation(pMod->locationOnly.loc, *basket.pLoc)) {
return false;
}
break;
case MK_EXCEPTION_ONLY:
- if (pMod->exceptionOnly.refTypeId != 0 && !Dbg::MatchType(basket.excepClassId, pMod->exceptionOnly.refTypeId)) {
+ if (pMod->exceptionOnly.refTypeId != 0 &&
+ !Dbg::MatchType(basket.exceptionClass, pMod->exceptionOnly.refTypeId)) {
return false;
}
- if ((basket.caught && !pMod->exceptionOnly.caught) || (!basket.caught && !pMod->exceptionOnly.uncaught)) {
+ if ((basket.caught && !pMod->exceptionOnly.caught) ||
+ (!basket.caught && !pMod->exceptionOnly.uncaught)) {
return false;
}
break;
case MK_FIELD_ONLY:
- if (pMod->fieldOnly.fieldId != basket.fieldId) {
- return false;
- }
- if (!Dbg::MatchType(basket.fieldTypeID, pMod->fieldOnly.refTypeId)) {
+ if (!Dbg::MatchField(pMod->fieldOnly.refTypeId, pMod->fieldOnly.fieldId, basket.field)) {
return false;
}
break;
case MK_STEP:
- if (pMod->step.threadId != basket.threadId) {
+ if (!Dbg::MatchThread(pMod->step.threadId, basket.thread)) {
return false;
}
break;
case MK_INSTANCE_ONLY:
- if (pMod->instanceOnly.objectId != basket.thisPtr) {
+ if (!Dbg::MatchInstance(pMod->instanceOnly.objectId, basket.thisPtr)) {
return false;
}
break;
@@ -773,7 +774,7 @@
}
static void LogMatchingEventsAndThread(JdwpEvent** match_list, size_t match_count,
- const ModBasket& basket)
+ ObjectId thread_id)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
for (size_t i = 0; i < match_count; ++i) {
JdwpEvent* pEvent = match_list[i];
@@ -781,11 +782,19 @@
<< StringPrintf(" (requestId=%#" PRIx32 ")", pEvent->requestId);
}
std::string thread_name;
- JdwpError error = Dbg::GetThreadName(basket.threadId, &thread_name);
+ JdwpError error = Dbg::GetThreadName(thread_id, &thread_name);
if (error != JDWP::ERR_NONE) {
thread_name = "<unknown>";
}
- VLOG(jdwp) << StringPrintf(" thread=%#" PRIx64, basket.threadId) << " " << thread_name;
+ VLOG(jdwp) << StringPrintf(" thread=%#" PRIx64, thread_id) << " " << thread_name;
+}
+
+static void SetJdwpLocationFromEventLocation(const JDWP::EventLocation* event_location,
+ JDWP::JdwpLocation* jdwp_location)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ DCHECK(event_location != nullptr);
+ DCHECK(jdwp_location != nullptr);
+ Dbg::SetJdwpLocation(jdwp_location, event_location->method, event_location->dex_pc);
}
/*
@@ -809,14 +818,18 @@
* - Single-step to a line with a breakpoint. Should get a single
* event message with both events in it.
*/
-bool JdwpState::PostLocationEvent(const JdwpLocation* pLoc, ObjectId thisPtr, int eventFlags,
- const JValue* returnValue) {
+bool JdwpState::PostLocationEvent(const EventLocation* pLoc, mirror::Object* thisPtr,
+ int eventFlags, const JValue* returnValue) {
+ DCHECK(pLoc != nullptr);
+ DCHECK(pLoc->method != nullptr);
+ DCHECK_EQ(pLoc->method->IsStatic(), thisPtr == nullptr);
+
ModBasket basket;
basket.pLoc = pLoc;
- basket.classId = pLoc->class_id;
+ basket.locationClass = pLoc->method->GetDeclaringClass();
basket.thisPtr = thisPtr;
- basket.threadId = Dbg::GetThreadSelfId();
- basket.className = Dbg::GetClassName(pLoc->class_id);
+ basket.thread = Thread::Current();
+ basket.className = Dbg::GetClassName(basket.locationClass);
/*
* On rare occasions we may need to execute interpreted code in the VM
@@ -824,7 +837,7 @@
* while doing so. (I don't think we currently do this at all, so
* this is mostly paranoia.)
*/
- if (basket.threadId == debug_thread_id_) {
+ if (basket.thread == GetDebugThread()) {
VLOG(jdwp) << "Ignoring location event in JDWP thread";
return false;
}
@@ -846,29 +859,36 @@
size_t match_count = 0;
ExpandBuf* pReq = NULL;
JdwpSuspendPolicy suspend_policy = SP_NONE;
+ JdwpEvent** match_list = nullptr;
+ ObjectId thread_id = 0;
{
- MutexLock mu(Thread::Current(), event_list_lock_);
- JdwpEvent** match_list = AllocMatchList(event_list_size_);
- if ((eventFlags & Dbg::kBreakpoint) != 0) {
- FindMatchingEvents(EK_BREAKPOINT, basket, match_list, &match_count);
- }
- if ((eventFlags & Dbg::kSingleStep) != 0) {
- FindMatchingEvents(EK_SINGLE_STEP, basket, match_list, &match_count);
- }
- if ((eventFlags & Dbg::kMethodEntry) != 0) {
- FindMatchingEvents(EK_METHOD_ENTRY, basket, match_list, &match_count);
- }
- if ((eventFlags & Dbg::kMethodExit) != 0) {
- FindMatchingEvents(EK_METHOD_EXIT, basket, match_list, &match_count);
- FindMatchingEvents(EK_METHOD_EXIT_WITH_RETURN_VALUE, basket, match_list, &match_count);
+ {
+ MutexLock mu(Thread::Current(), event_list_lock_);
+ match_list = AllocMatchList(event_list_size_);
+ if ((eventFlags & Dbg::kBreakpoint) != 0) {
+ FindMatchingEvents(EK_BREAKPOINT, basket, match_list, &match_count);
+ }
+ if ((eventFlags & Dbg::kSingleStep) != 0) {
+ FindMatchingEvents(EK_SINGLE_STEP, basket, match_list, &match_count);
+ }
+ if ((eventFlags & Dbg::kMethodEntry) != 0) {
+ FindMatchingEvents(EK_METHOD_ENTRY, basket, match_list, &match_count);
+ }
+ if ((eventFlags & Dbg::kMethodExit) != 0) {
+ FindMatchingEvents(EK_METHOD_EXIT, basket, match_list, &match_count);
+ FindMatchingEvents(EK_METHOD_EXIT_WITH_RETURN_VALUE, basket, match_list, &match_count);
+ }
}
if (match_count != 0) {
suspend_policy = scanSuspendPolicy(match_list, match_count);
+ thread_id = Dbg::GetThreadId(basket.thread);
+ JDWP::JdwpLocation jdwp_location;
+ SetJdwpLocationFromEventLocation(pLoc, &jdwp_location);
+
if (VLOG_IS_ON(jdwp)) {
- LogMatchingEventsAndThread(match_list, match_count, basket);
- VLOG(jdwp) << " location=" << *pLoc;
- VLOG(jdwp) << StringPrintf(" this=%#" PRIx64, basket.thisPtr);
+ LogMatchingEventsAndThread(match_list, match_count, thread_id);
+ VLOG(jdwp) << " location=" << jdwp_location;
VLOG(jdwp) << " suspend_policy=" << suspend_policy;
}
@@ -879,79 +899,81 @@
for (size_t i = 0; i < match_count; i++) {
expandBufAdd1(pReq, match_list[i]->eventKind);
expandBufAdd4BE(pReq, match_list[i]->requestId);
- expandBufAdd8BE(pReq, basket.threadId);
- expandBufAddLocation(pReq, *pLoc);
+ expandBufAdd8BE(pReq, thread_id);
+ expandBufAddLocation(pReq, jdwp_location);
if (match_list[i]->eventKind == EK_METHOD_EXIT_WITH_RETURN_VALUE) {
- Dbg::OutputMethodReturnValue(pLoc->method_id, returnValue, pReq);
+ Dbg::OutputMethodReturnValue(jdwp_location.method_id, returnValue, pReq);
}
}
}
- CleanupMatchList(match_list, match_count);
+ {
+ MutexLock mu(Thread::Current(), event_list_lock_);
+ CleanupMatchList(match_list, match_count);
+ }
}
Dbg::ManageDeoptimization();
- SendRequestAndPossiblySuspend(pReq, suspend_policy, basket.threadId);
+ SendRequestAndPossiblySuspend(pReq, suspend_policy, thread_id);
return match_count != 0;
}
-bool JdwpState::PostFieldEvent(const JdwpLocation* pLoc, RefTypeId typeId, FieldId fieldId,
- ObjectId thisPtr, const JValue* fieldValue, bool is_modification) {
+bool JdwpState::PostFieldEvent(const EventLocation* pLoc, mirror::ArtField* field,
+ mirror::Object* this_object, const JValue* fieldValue,
+ bool is_modification) {
+ DCHECK(pLoc != nullptr);
+ DCHECK(field != nullptr);
+ DCHECK_EQ(fieldValue != nullptr, is_modification);
+ DCHECK_EQ(field->IsStatic(), this_object == nullptr);
+
ModBasket basket;
basket.pLoc = pLoc;
- basket.classId = pLoc->class_id;
- basket.thisPtr = thisPtr;
- basket.threadId = Dbg::GetThreadSelfId();
- basket.className = Dbg::GetClassName(pLoc->class_id);
- basket.fieldTypeID = typeId;
- basket.fieldId = fieldId;
-
- DCHECK_EQ(fieldValue != nullptr, is_modification);
+ basket.locationClass = pLoc->method->GetDeclaringClass();
+ basket.thisPtr = this_object;
+ basket.thread = Thread::Current();
+ basket.className = Dbg::GetClassName(basket.locationClass);
+ basket.field = field;
if (InvokeInProgress()) {
VLOG(jdwp) << "Not posting field event during invoke";
return false;
}
- // Get field's reference type tag.
- JDWP::JdwpTypeTag type_tag;
- uint32_t class_status; // unused here.
- JdwpError error = Dbg::GetClassInfo(typeId, &type_tag, &class_status, NULL);
- if (error != ERR_NONE) {
- return false;
- }
-
- // Get instance type tag.
- uint8_t tag;
- error = Dbg::GetObjectTag(thisPtr, &tag);
- if (error != ERR_NONE) {
- return false;
- }
-
size_t match_count = 0;
ExpandBuf* pReq = NULL;
JdwpSuspendPolicy suspend_policy = SP_NONE;
+ JdwpEvent** match_list = nullptr;
+ ObjectId thread_id = 0;
{
- MutexLock mu(Thread::Current(), event_list_lock_);
- JdwpEvent** match_list = AllocMatchList(event_list_size_);
-
- if (is_modification) {
- FindMatchingEvents(EK_FIELD_MODIFICATION, basket, match_list, &match_count);
- } else {
- FindMatchingEvents(EK_FIELD_ACCESS, basket, match_list, &match_count);
+ {
+ MutexLock mu(Thread::Current(), event_list_lock_);
+ match_list = AllocMatchList(event_list_size_);
+ if (is_modification) {
+ FindMatchingEvents(EK_FIELD_MODIFICATION, basket, match_list, &match_count);
+ } else {
+ FindMatchingEvents(EK_FIELD_ACCESS, basket, match_list, &match_count);
+ }
}
if (match_count != 0) {
suspend_policy = scanSuspendPolicy(match_list, match_count);
+ thread_id = Dbg::GetThreadId(basket.thread);
+ ObjectRegistry* registry = Dbg::GetObjectRegistry();
+ ObjectId instance_id = registry->Add(basket.thisPtr);
+ RefTypeId field_type_id = registry->AddRefType(field->GetDeclaringClass());
+ FieldId field_id = Dbg::ToFieldId(field);
+ JDWP::JdwpLocation jdwp_location;
+ SetJdwpLocationFromEventLocation(pLoc, &jdwp_location);
+
if (VLOG_IS_ON(jdwp)) {
- LogMatchingEventsAndThread(match_list, match_count, basket);
- VLOG(jdwp) << " location=" << *pLoc;
- VLOG(jdwp) << StringPrintf(" this=%#" PRIx64, basket.thisPtr);
- VLOG(jdwp) << StringPrintf(" type=%#" PRIx64, basket.fieldTypeID) << " "
- << Dbg::GetClassName(basket.fieldTypeID);
- VLOG(jdwp) << StringPrintf(" field=%#" PRIx32, basket.fieldId) << " "
- << Dbg::GetFieldName(basket.fieldId);
+ LogMatchingEventsAndThread(match_list, match_count, thread_id);
+ VLOG(jdwp) << " location=" << jdwp_location;
+ VLOG(jdwp) << StringPrintf(" this=%#" PRIx64, instance_id);
+ VLOG(jdwp) << StringPrintf(" type=%#" PRIx64, field_type_id) << " "
+ << Dbg::GetClassName(field_id);
+ VLOG(jdwp) << StringPrintf(" field=%#" PRIx32, field_id) << " "
+ << Dbg::GetFieldName(field_id);
VLOG(jdwp) << " suspend_policy=" << suspend_policy;
}
@@ -959,28 +981,41 @@
expandBufAdd1(pReq, suspend_policy);
expandBufAdd4BE(pReq, match_count);
+ // Get field's reference type tag.
+ JDWP::JdwpTypeTag type_tag = Dbg::GetTypeTag(field->GetDeclaringClass());
+
+ // Get instance type tag.
+ uint8_t tag;
+ {
+ ScopedObjectAccessUnchecked soa(Thread::Current());
+ tag = Dbg::TagFromObject(soa, basket.thisPtr);
+ }
+
for (size_t i = 0; i < match_count; i++) {
expandBufAdd1(pReq, match_list[i]->eventKind);
expandBufAdd4BE(pReq, match_list[i]->requestId);
- expandBufAdd8BE(pReq, basket.threadId);
- expandBufAddLocation(pReq, *pLoc);
+ expandBufAdd8BE(pReq, thread_id);
+ expandBufAddLocation(pReq, jdwp_location);
expandBufAdd1(pReq, type_tag);
- expandBufAddRefTypeId(pReq, typeId);
- expandBufAddFieldId(pReq, fieldId);
+ expandBufAddRefTypeId(pReq, field_type_id);
+ expandBufAddFieldId(pReq, field_id);
expandBufAdd1(pReq, tag);
- expandBufAddObjectId(pReq, thisPtr);
+ expandBufAddObjectId(pReq, instance_id);
if (is_modification) {
- Dbg::OutputFieldValue(fieldId, fieldValue, pReq);
+ Dbg::OutputFieldValue(field_id, fieldValue, pReq);
}
}
}
- CleanupMatchList(match_list, match_count);
+ {
+ MutexLock mu(Thread::Current(), event_list_lock_);
+ CleanupMatchList(match_list, match_count);
+ }
}
Dbg::ManageDeoptimization();
- SendRequestAndPossiblySuspend(pReq, suspend_policy, basket.threadId);
+ SendRequestAndPossiblySuspend(pReq, suspend_policy, thread_id);
return match_count != 0;
}
@@ -990,8 +1025,8 @@
* Valid mods:
* Count, ThreadOnly
*/
-bool JdwpState::PostThreadChange(ObjectId threadId, bool start) {
- CHECK_EQ(threadId, Dbg::GetThreadSelfId());
+bool JdwpState::PostThreadChange(Thread* thread, bool start) {
+ CHECK_EQ(thread, Thread::Current());
/*
* I don't think this can happen.
@@ -1002,27 +1037,32 @@
}
ModBasket basket;
- basket.threadId = threadId;
+ basket.thread = thread;
ExpandBuf* pReq = NULL;
JdwpSuspendPolicy suspend_policy = SP_NONE;
+ JdwpEvent** match_list = nullptr;
size_t match_count = 0;
+ ObjectId thread_id = 0;
{
- // Don't allow the list to be updated while we scan it.
- MutexLock mu(Thread::Current(), event_list_lock_);
- JdwpEvent** match_list = AllocMatchList(event_list_size_);
-
- if (start) {
- FindMatchingEvents(EK_THREAD_START, basket, match_list, &match_count);
- } else {
- FindMatchingEvents(EK_THREAD_DEATH, basket, match_list, &match_count);
+ {
+ // Don't allow the list to be updated while we scan it.
+ MutexLock mu(Thread::Current(), event_list_lock_);
+ match_list = AllocMatchList(event_list_size_);
+ if (start) {
+ FindMatchingEvents(EK_THREAD_START, basket, match_list, &match_count);
+ } else {
+ FindMatchingEvents(EK_THREAD_DEATH, basket, match_list, &match_count);
+ }
}
if (match_count != 0) {
suspend_policy = scanSuspendPolicy(match_list, match_count);
+ thread_id = Dbg::GetThreadId(basket.thread);
+
if (VLOG_IS_ON(jdwp)) {
- LogMatchingEventsAndThread(match_list, match_count, basket);
+ LogMatchingEventsAndThread(match_list, match_count, thread_id);
VLOG(jdwp) << " suspend_policy=" << suspend_policy;
}
@@ -1033,16 +1073,19 @@
for (size_t i = 0; i < match_count; i++) {
expandBufAdd1(pReq, match_list[i]->eventKind);
expandBufAdd4BE(pReq, match_list[i]->requestId);
- expandBufAdd8BE(pReq, basket.threadId);
+ expandBufAdd8BE(pReq, thread_id);
}
}
- CleanupMatchList(match_list, match_count);
+ {
+ MutexLock mu(Thread::Current(), event_list_lock_);
+ CleanupMatchList(match_list, match_count);
+ }
}
Dbg::ManageDeoptimization();
- SendRequestAndPossiblySuspend(pReq, suspend_policy, basket.threadId);
+ SendRequestAndPossiblySuspend(pReq, suspend_policy, thread_id);
return match_count != 0;
}
@@ -1076,17 +1119,21 @@
* because there's a pretty good chance that we're not going to send it
* up the debugger.
*/
-bool JdwpState::PostException(const JdwpLocation* pThrowLoc,
- ObjectId exceptionId, RefTypeId exceptionClassId,
- const JdwpLocation* pCatchLoc, ObjectId thisPtr) {
- ModBasket basket;
+bool JdwpState::PostException(const EventLocation* pThrowLoc, mirror::Throwable* exception_object,
+ const EventLocation* pCatchLoc, mirror::Object* thisPtr) {
+ DCHECK(exception_object != nullptr);
+ DCHECK(pThrowLoc != nullptr);
+ DCHECK(pCatchLoc != nullptr);
+ DCHECK(pThrowLoc->method != nullptr);
+ DCHECK_EQ(pThrowLoc->method->IsStatic(), thisPtr == nullptr);
+ ModBasket basket;
basket.pLoc = pThrowLoc;
- basket.classId = pThrowLoc->class_id;
- basket.threadId = Dbg::GetThreadSelfId();
- basket.className = Dbg::GetClassName(basket.classId);
- basket.excepClassId = exceptionClassId;
- basket.caught = (pCatchLoc->class_id != 0);
+ basket.locationClass = pThrowLoc->method->GetDeclaringClass();
+ basket.thread = Thread::Current();
+ basket.className = Dbg::GetClassName(basket.locationClass);
+ basket.exceptionClass = exception_object->GetClass();
+ basket.caught = (pCatchLoc->method != 0);
basket.thisPtr = thisPtr;
/* don't try to post an exception caused by the debugger */
@@ -1098,24 +1145,37 @@
size_t match_count = 0;
ExpandBuf* pReq = NULL;
JdwpSuspendPolicy suspend_policy = SP_NONE;
+ JdwpEvent** match_list = nullptr;
+ ObjectId thread_id = 0;
{
- MutexLock mu(Thread::Current(), event_list_lock_);
- JdwpEvent** match_list = AllocMatchList(event_list_size_);
- FindMatchingEvents(EK_EXCEPTION, basket, match_list, &match_count);
+ {
+ MutexLock mu(Thread::Current(), event_list_lock_);
+ match_list = AllocMatchList(event_list_size_);
+ FindMatchingEvents(EK_EXCEPTION, basket, match_list, &match_count);
+ }
if (match_count != 0) {
suspend_policy = scanSuspendPolicy(match_list, match_count);
+ thread_id = Dbg::GetThreadId(basket.thread);
+ ObjectRegistry* registry = Dbg::GetObjectRegistry();
+ ObjectId exceptionId = registry->Add(exception_object);
+ JDWP::JdwpLocation jdwp_throw_location;
+ JDWP::JdwpLocation jdwp_catch_location;
+ SetJdwpLocationFromEventLocation(pThrowLoc, &jdwp_throw_location);
+ SetJdwpLocationFromEventLocation(pCatchLoc, &jdwp_catch_location);
+
if (VLOG_IS_ON(jdwp)) {
- LogMatchingEventsAndThread(match_list, match_count, basket);
- VLOG(jdwp) << " throwLocation=" << *pThrowLoc;
- if (pCatchLoc->class_id == 0) {
+ std::string exceptionClassName(PrettyDescriptor(exception_object->GetClass()));
+
+ LogMatchingEventsAndThread(match_list, match_count, thread_id);
+ VLOG(jdwp) << " throwLocation=" << jdwp_throw_location;
+ if (jdwp_catch_location.class_id == 0) {
VLOG(jdwp) << " catchLocation=uncaught";
} else {
- VLOG(jdwp) << " catchLocation=" << *pCatchLoc;
+ VLOG(jdwp) << " catchLocation=" << jdwp_catch_location;
}
- VLOG(jdwp) << StringPrintf(" this=%#" PRIx64, basket.thisPtr);
- VLOG(jdwp) << StringPrintf(" exceptionClass=%#" PRIx64, basket.excepClassId) << " "
- << Dbg::GetClassName(basket.excepClassId);
+ VLOG(jdwp) << StringPrintf(" exception=%#" PRIx64, exceptionId) << " "
+ << exceptionClassName;
VLOG(jdwp) << " suspend_policy=" << suspend_policy;
}
@@ -1126,21 +1186,23 @@
for (size_t i = 0; i < match_count; i++) {
expandBufAdd1(pReq, match_list[i]->eventKind);
expandBufAdd4BE(pReq, match_list[i]->requestId);
- expandBufAdd8BE(pReq, basket.threadId);
-
- expandBufAddLocation(pReq, *pThrowLoc);
+ expandBufAdd8BE(pReq, thread_id);
+ expandBufAddLocation(pReq, jdwp_throw_location);
expandBufAdd1(pReq, JT_OBJECT);
expandBufAdd8BE(pReq, exceptionId);
- expandBufAddLocation(pReq, *pCatchLoc);
+ expandBufAddLocation(pReq, jdwp_catch_location);
}
}
- CleanupMatchList(match_list, match_count);
+ {
+ MutexLock mu(Thread::Current(), event_list_lock_);
+ CleanupMatchList(match_list, match_count);
+ }
}
Dbg::ManageDeoptimization();
- SendRequestAndPossiblySuspend(pReq, suspend_policy, basket.threadId);
+ SendRequestAndPossiblySuspend(pReq, suspend_policy, thread_id);
return match_count != 0;
}
@@ -1151,13 +1213,13 @@
* Valid mods:
* Count, ThreadOnly, ClassOnly, ClassMatch, ClassExclude
*/
-bool JdwpState::PostClassPrepare(JdwpTypeTag tag, RefTypeId refTypeId, const std::string& signature,
- int status) {
- ModBasket basket;
+bool JdwpState::PostClassPrepare(mirror::Class* klass) {
+ DCHECK(klass != nullptr);
- basket.classId = refTypeId;
- basket.threadId = Dbg::GetThreadSelfId();
- basket.className = Dbg::GetClassName(basket.classId);
+ ModBasket basket;
+ basket.locationClass = klass;
+ basket.thread = Thread::Current();
+ basket.className = Dbg::GetClassName(basket.locationClass);
/* suppress class prep caused by debugger */
if (InvokeInProgress()) {
@@ -1167,28 +1229,44 @@
ExpandBuf* pReq = NULL;
JdwpSuspendPolicy suspend_policy = SP_NONE;
+ JdwpEvent** match_list = nullptr;
size_t match_count = 0;
+ ObjectId thread_id = 0;
{
- MutexLock mu(Thread::Current(), event_list_lock_);
- JdwpEvent** match_list = AllocMatchList(event_list_size_);
- FindMatchingEvents(EK_CLASS_PREPARE, basket, match_list, &match_count);
+ {
+ MutexLock mu(Thread::Current(), event_list_lock_);
+ match_list = AllocMatchList(event_list_size_);
+ FindMatchingEvents(EK_CLASS_PREPARE, basket, match_list, &match_count);
+ }
if (match_count != 0) {
suspend_policy = scanSuspendPolicy(match_list, match_count);
+ thread_id = Dbg::GetThreadId(basket.thread);
+ ObjectRegistry* registry = Dbg::GetObjectRegistry();
+ RefTypeId class_id = registry->AddRefType(basket.locationClass);
+
+ // 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 status = JDWP::CS_VERIFIED | JDWP::CS_PREPARED;
+ JDWP::JdwpTypeTag tag = Dbg::GetTypeTag(basket.locationClass);
+ std::string temp;
+ std::string signature(basket.locationClass->GetDescriptor(&temp));
+
if (VLOG_IS_ON(jdwp)) {
- LogMatchingEventsAndThread(match_list, match_count, basket);
- VLOG(jdwp) << StringPrintf(" type=%#" PRIx64, basket.classId)<< " " << signature;
+ LogMatchingEventsAndThread(match_list, match_count, thread_id);
+ VLOG(jdwp) << StringPrintf(" type=%#" PRIx64, class_id) << " " << signature;
VLOG(jdwp) << " suspend_policy=" << suspend_policy;
}
- if (basket.threadId == debug_thread_id_) {
+ if (thread_id == debug_thread_id_) {
/*
* JDWP says that, for a class prep in the debugger thread, we
- * should set threadId to null and if any threads were supposed
+ * should set thread to null and if any threads were supposed
* to be suspended then we suspend all other threads.
*/
VLOG(jdwp) << " NOTE: class prepare in debugger thread!";
- basket.threadId = 0;
+ thread_id = 0;
if (suspend_policy == SP_EVENT_THREAD) {
suspend_policy = SP_ALL;
}
@@ -1201,20 +1279,23 @@
for (size_t i = 0; i < match_count; i++) {
expandBufAdd1(pReq, match_list[i]->eventKind);
expandBufAdd4BE(pReq, match_list[i]->requestId);
- expandBufAdd8BE(pReq, basket.threadId);
-
+ expandBufAdd8BE(pReq, thread_id);
expandBufAdd1(pReq, tag);
- expandBufAdd8BE(pReq, refTypeId);
+ expandBufAdd8BE(pReq, class_id);
expandBufAddUtf8String(pReq, signature);
expandBufAdd4BE(pReq, status);
}
}
- CleanupMatchList(match_list, match_count);
+
+ {
+ MutexLock mu(Thread::Current(), event_list_lock_);
+ CleanupMatchList(match_list, match_count);
+ }
}
Dbg::ManageDeoptimization();
- SendRequestAndPossiblySuspend(pReq, suspend_policy, basket.threadId);
+ SendRequestAndPossiblySuspend(pReq, suspend_policy, thread_id);
return match_count != 0;
}