diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/debugger.cc | 16 | ||||
| -rw-r--r-- | src/debugger.h | 3 | ||||
| -rw-r--r-- | src/heap.cc | 43 | ||||
| -rw-r--r-- | src/heap.h | 4 | ||||
| -rw-r--r-- | src/jdwp/jdwp_handler.cc | 40 |
5 files changed, 97 insertions, 9 deletions
diff --git a/src/debugger.cc b/src/debugger.cc index f52c42ae90..1df7fe94ab 100644 --- a/src/debugger.cc +++ b/src/debugger.cc @@ -775,6 +775,22 @@ JDWP::JdwpError Dbg::GetInstances(JDWP::RefTypeId class_id, int32_t max_count, s return JDWP::ERR_NONE; } +JDWP::JdwpError Dbg::GetReferringObjects(JDWP::ObjectId object_id, int32_t max_count, + std::vector<JDWP::ObjectId>& referring_objects) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + Object* o = gRegistry->Get<Object*>(object_id); + if (o == NULL || o == kInvalidObject) { + return JDWP::ERR_INVALID_OBJECT; + } + + std::vector<Object*> raw_instances; + Runtime::Current()->GetHeap()->GetReferringObjects(o, max_count, raw_instances); + for (size_t i = 0; i < raw_instances.size(); ++i) { + referring_objects.push_back(gRegistry->Add(raw_instances[i])); + } + return JDWP::ERR_NONE; +} + JDWP::JdwpError Dbg::GetReflectedType(JDWP::RefTypeId class_id, JDWP::ExpandBuf* pReply) { JDWP::JdwpError status; Class* c = DecodeClass(class_id, status); diff --git a/src/debugger.h b/src/debugger.h index ebcff081a5..c03adeadd8 100644 --- a/src/debugger.h +++ b/src/debugger.h @@ -192,6 +192,9 @@ class Dbg { static JDWP::JdwpError GetInstances(JDWP::RefTypeId class_id, int32_t max_count, std::vector<JDWP::ObjectId>& instances) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + static JDWP::JdwpError GetReferringObjects(JDWP::ObjectId object_id, int32_t max_count, + std::vector<JDWP::ObjectId>& referring_objects) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); /* * Method and Field diff --git a/src/heap.cc b/src/heap.cc index db49c61ddc..656aae7330 100644 --- a/src/heap.cc +++ b/src/heap.cc @@ -916,6 +916,49 @@ void Heap::GetInstances(Class* c, int32_t max_count, std::vector<Object*>& insta GetLiveBitmap()->Visit(collector); } +class ReferringObjectsFinder { + public: + ReferringObjectsFinder(Object* object, int32_t max_count, std::vector<Object*>& referring_objects) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) + : object_(object), max_count_(max_count), referring_objects_(referring_objects) { + } + + // For bitmap Visit. + // TODO: Fix lock analysis to not use NO_THREAD_SAFETY_ANALYSIS, requires support for + // annotalysis on visitors. + void operator()(const Object* o) const NO_THREAD_SAFETY_ANALYSIS { + MarkSweep::VisitObjectReferences(o, *this); + } + + // For MarkSweep::VisitObjectReferences. + void operator ()(const Object* referrer, const Object* object, const MemberOffset&, bool) const { + if (object == object_ && (max_count_ == 0 || referring_objects_.size() < max_count_)) { + referring_objects_.push_back(const_cast<Object*>(referrer)); + } + } + + private: + Object* object_; + uint32_t max_count_; + std::vector<Object*>& referring_objects_; + + DISALLOW_COPY_AND_ASSIGN(ReferringObjectsFinder); +}; + +void Heap::GetReferringObjects(Object* o, int32_t max_count, + std::vector<Object*>& referring_objects) { + // We only want reachable instances, so do a GC. This also ensures that the alloc stack + // is empty, so the live bitmap is the only place we need to look. + Thread* self = Thread::Current(); + self->TransitionFromRunnableToSuspended(kNative); + CollectGarbage(false); + self->TransitionFromSuspendedToRunnable(); + + ReferringObjectsFinder finder(o, max_count, referring_objects); + ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_); + GetLiveBitmap()->Visit(finder); +} + void Heap::CollectGarbage(bool clear_soft_references) { // Even if we waited for a GC we still need to do another GC since weaks allocated during the // last GC will not have necessarily been cleared. diff --git a/src/heap.h b/src/heap.h index fd08f2968e..78cbe99fc6 100644 --- a/src/heap.h +++ b/src/heap.h @@ -177,6 +177,10 @@ class Heap { void GetInstances(Class* c, int32_t max_count, std::vector<Object*>& instances) LOCKS_EXCLUDED(Locks::heap_bitmap_lock_) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + // Implements JDWP OR_ReferringObjects. + void GetReferringObjects(Object* o, int32_t max_count, std::vector<Object*>& referring_objects) + LOCKS_EXCLUDED(Locks::heap_bitmap_lock_) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Removes the growth limit on the alloc space so it may grow to its maximum capacity. Used to // implement dalvik.system.VMRuntime.clearGrowthLimit. diff --git a/src/jdwp/jdwp_handler.cc b/src/jdwp/jdwp_handler.cc index 86ecffed78..23a31308d8 100644 --- a/src/jdwp/jdwp_handler.cc +++ b/src/jdwp/jdwp_handler.cc @@ -95,6 +95,18 @@ static JdwpError WriteTaggedObject(ExpandBuf* reply, ObjectId object_id) return rc; } +static JdwpError WriteTaggedObjectList(ExpandBuf* reply, const std::vector<ObjectId>& objects) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + expandBufAdd4BE(reply, objects.size()); + for (size_t i = 0; i < objects.size(); ++i) { + JdwpError rc = WriteTaggedObject(reply, objects[i]); + if (rc != ERR_NONE) { + return rc; + } + } + return ERR_NONE; +} + /* * Common code for *_InvokeMethod requests. * @@ -663,14 +675,7 @@ static JdwpError RT_Instances(JdwpState*, const uint8_t* buf, int, ExpandBuf* re return rc; } - expandBufAdd4BE(reply, instances.size()); - for (size_t i = 0; i < instances.size(); ++i) { - rc = WriteTaggedObject(reply, instances[i]); - if (rc != ERR_NONE) { - return rc; - } - } - return ERR_NONE; + return WriteTaggedObjectList(reply, instances); } /* @@ -949,6 +954,23 @@ static JdwpError OR_IsCollected(JdwpState*, const uint8_t* buf, int, ExpandBuf* return ERR_NONE; } +static JdwpError OR_ReferringObjects(JdwpState*, const uint8_t* buf, int, ExpandBuf* reply) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + ObjectId object_id = ReadObjectId(&buf); + int32_t max_count = Read4BE(&buf); + if (max_count < 0) { + return ERR_ILLEGAL_ARGUMENT; + } + + std::vector<ObjectId> referring_objects; + JdwpError rc = Dbg::GetReferringObjects(object_id, max_count, referring_objects); + if (rc != ERR_NONE) { + return rc; + } + + return WriteTaggedObjectList(reply, referring_objects); +} + /* * Return the string value in a string object. */ @@ -1674,7 +1696,7 @@ static const JdwpHandlerMap gHandlerMap[] = { { 9, 7, OR_DisableCollection, "ObjectReference.DisableCollection" }, { 9, 8, OR_EnableCollection, "ObjectReference.EnableCollection" }, { 9, 9, OR_IsCollected, "ObjectReference.IsCollected" }, - { 9, 10, NULL, "ObjectReference.ReferringObjects" }, + { 9, 10, OR_ReferringObjects, "ObjectReference.ReferringObjects" }, /* StringReference command set (10) */ { 10, 1, SR_Value, "StringReference.Value" }, |