diff options
-rw-r--r-- | runtime/debugger.cc | 174 | ||||
-rw-r--r-- | runtime/debugger.h | 49 | ||||
-rw-r--r-- | runtime/jdwp/jdwp.h | 32 | ||||
-rw-r--r-- | runtime/jdwp/jdwp_event.cc | 401 |
4 files changed, 400 insertions, 256 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); } diff --git a/runtime/debugger.h b/runtime/debugger.h index e171d7854f..97985ec649 100644 --- a/runtime/debugger.h +++ b/runtime/debugger.h @@ -43,6 +43,8 @@ class Object; class Throwable; } // namespace mirror class AllocRecord; +class ObjectRegistry; +class ScopedObjectAccessUnchecked; class Thread; class ThrowLocation; @@ -250,6 +252,8 @@ class Dbg { */ 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 @@ class Dbg { 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 @@ class Dbg { 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 @@ class Dbg { 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 @@ class Dbg { 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 @@ class Dbg { 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 b5b6298b84..0c9451ceeb 100644 --- a/runtime/jdwp/jdwp.h +++ b/runtime/jdwp/jdwp.h @@ -36,8 +36,13 @@ union JValue; 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 expandBufAddObjectId(ExpandBuf* pReply, ObjectId id) { expand 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 @@ struct JdwpState { * 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 @@ struct JdwpState { * * "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 @@ struct JdwpState { * "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 @@ struct JdwpState { * * 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 fc39cc48d0..46db63ccd5 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 @@ namespace JDWP { * The rest will be zeroed. */ struct ModBasket { - ModBasket() : pLoc(NULL), threadId(0), classId(0), excepClassId(0), - caught(false), fieldTypeID(0), fieldId(0), thisPtr(0) { } - - 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 */ + ModBasket() : pLoc(nullptr), thread(nullptr), locationClass(nullptr), exceptionClass(nullptr), + caught(false), field(nullptr), thisPtr(nullptr) { } + + 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 @@ static bool ModsMatch(JdwpEvent* pEvent, const ModBasket& basket) 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 @@ static bool ModsMatch(JdwpEvent* pEvent, const ModBasket& basket) } 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 @@ bool JdwpState::PostVMStart() { } 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 @@ static void LogMatchingEventsAndThread(JdwpEvent** match_list, size_t match_coun << 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 @@ static void LogMatchingEventsAndThread(JdwpEvent** match_list, size_t match_coun * - 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 @@ bool JdwpState::PostLocationEvent(const JdwpLocation* pLoc, ObjectId thisPtr, in * 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 @@ bool JdwpState::PostLocationEvent(const JdwpLocation* pLoc, ObjectId thisPtr, in 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 @@ bool JdwpState::PostLocationEvent(const JdwpLocation* pLoc, ObjectId thisPtr, in 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 @@ bool JdwpState::PostFieldEvent(const JdwpLocation* pLoc, RefTypeId typeId, Field 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 @@ bool JdwpState::PostFieldEvent(const JdwpLocation* pLoc, RefTypeId typeId, Field * 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 @@ bool JdwpState::PostThreadChange(ObjectId threadId, bool start) { } 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 @@ bool JdwpState::PostThreadChange(ObjectId threadId, bool start) { 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 @@ bool JdwpState::PostVMDeath() { * 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 @@ bool JdwpState::PostException(const JdwpLocation* pThrowLoc, 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 @@ bool JdwpState::PostException(const JdwpLocation* pThrowLoc, 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 @@ bool JdwpState::PostException(const JdwpLocation* pThrowLoc, * 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 @@ bool JdwpState::PostClassPrepare(JdwpTypeTag tag, RefTypeId refTypeId, const std 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 @@ bool JdwpState::PostClassPrepare(JdwpTypeTag tag, RefTypeId refTypeId, const std 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; } |