Implement JDWP VirtualMachine.InstanceCounts.
Change-Id: I6df66787dee8af67f65460023bcf223eec1ec7da
diff --git a/src/debugger.cc b/src/debugger.cc
index 1ddb525..44785ba 100644
--- a/src/debugger.cc
+++ b/src/debugger.cc
@@ -739,6 +739,26 @@
return JDWP::ERR_NONE;
}
+JDWP::JdwpError Dbg::GetInstanceCounts(const std::vector<JDWP::RefTypeId>& class_ids,
+ std::vector<uint64_t>& counts)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+
+ std::vector<Class*> classes;
+ counts.clear();
+ for (size_t i = 0; i < class_ids.size(); ++i) {
+ JDWP::JdwpError status;
+ Class* c = DecodeClass(class_ids[i], status);
+ if (c == NULL) {
+ return status;
+ }
+ classes.push_back(c);
+ counts.push_back(0);
+ }
+
+ Runtime::Current()->GetHeap()->CountInstances(classes, false, &counts[0]);
+ 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 1acd09b..1bad6cc 100644
--- a/src/debugger.h
+++ b/src/debugger.h
@@ -151,15 +151,6 @@
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
static size_t GetTagWidth(JDWP::JdwpTag tag);
- static JDWP::JdwpError GetMonitorInfo(JDWP::ObjectId object_id, JDWP::ExpandBuf* reply)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static JDWP::JdwpError GetOwnedMonitors(JDWP::ObjectId thread_id,
- std::vector<JDWP::ObjectId>& monitors,
- std::vector<uint32_t>& stack_depths)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static JDWP::JdwpError GetContendedMonitor(JDWP::ObjectId thread_id, JDWP::ObjectId& contended_monitor)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
static JDWP::JdwpError GetArrayLength(JDWP::ObjectId array_id, int& length)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
static JDWP::JdwpError OutputArray(JDWP::ObjectId array_id, int offset, int count,
@@ -180,6 +171,25 @@
static bool MatchType(JDWP::RefTypeId instance_class_id, JDWP::RefTypeId class_id)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ //
+ // Monitors.
+ //
+ static JDWP::JdwpError GetMonitorInfo(JDWP::ObjectId object_id, JDWP::ExpandBuf* reply)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ static JDWP::JdwpError GetOwnedMonitors(JDWP::ObjectId thread_id,
+ std::vector<JDWP::ObjectId>& monitors,
+ std::vector<uint32_t>& stack_depths)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ static JDWP::JdwpError GetContendedMonitor(JDWP::ObjectId thread_id, JDWP::ObjectId& contended_monitor)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ //
+ // Heap.
+ //
+ static JDWP::JdwpError GetInstanceCounts(const std::vector<JDWP::RefTypeId>& class_ids,
+ std::vector<uint64_t>& counts)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
/*
* Method and Field
*/
diff --git a/src/heap.cc b/src/heap.cc
index fa84e49..989a0b9 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -837,37 +837,46 @@
class InstanceCounter {
public:
- InstanceCounter(Class* c, bool count_assignable, size_t* const count)
+ InstanceCounter(const std::vector<Class*>& classes, bool use_is_assignable_from, uint64_t* counts)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
- : class_(c), count_assignable_(count_assignable), count_(count) {
-
+ : classes_(classes), use_is_assignable_from_(use_is_assignable_from), counts_(counts) {
}
void operator()(const Object* o) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- const Class* instance_class = o->GetClass();
- if (count_assignable_) {
- if (instance_class == class_) {
- ++*count_;
- }
- } else {
- if (instance_class != NULL && class_->IsAssignableFrom(instance_class)) {
- ++*count_;
+ for (size_t i = 0; i < classes_.size(); ++i) {
+ const Class* instance_class = o->GetClass();
+ if (use_is_assignable_from_) {
+ if (instance_class != NULL && classes_[i]->IsAssignableFrom(instance_class)) {
+ ++counts_[i];
+ }
+ } else {
+ if (instance_class == classes_[i]) {
+ ++counts_[i];
+ }
}
}
}
private:
- Class* class_;
- bool count_assignable_;
- size_t* const count_;
+ const std::vector<Class*>& classes_;
+ bool use_is_assignable_from_;
+ uint64_t* const counts_;
+
+ DISALLOW_COPY_AND_ASSIGN(InstanceCounter);
};
-int64_t Heap::CountInstances(Class* c, bool count_assignable) {
- size_t count = 0;
- InstanceCounter counter(c, count_assignable, &count);
- ReaderMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
+void Heap::CountInstances(const std::vector<Class*>& classes, bool use_is_assignable_from,
+ uint64_t* counts) {
+ // 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();
+
+ InstanceCounter counter(classes, use_is_assignable_from, counts);
+ ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
GetLiveBitmap()->Visit(counter);
- return count;
}
void Heap::CollectGarbage(bool clear_soft_references) {
diff --git a/src/heap.h b/src/heap.h
index 68ee923..bd9945d 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -167,8 +167,10 @@
// Implements java.lang.Runtime.freeMemory.
int64_t GetFreeMemory() const;
- // Implements VMDebug.countInstancesOfClass.
- int64_t CountInstances(Class* c, bool count_assignable)
+ // Implements VMDebug.countInstancesOfClass and JDWP VM_InstanceCount.
+ // The boolean decides whether to use IsAssignableFrom or == when comparing classes.
+ void CountInstances(const std::vector<Class*>& classes, bool use_is_assignable_from,
+ uint64_t* counts)
LOCKS_EXCLUDED(Locks::heap_bitmap_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/src/jdwp/jdwp_handler.cc b/src/jdwp/jdwp_handler.cc
index 94aff1c..f68e560 100644
--- a/src/jdwp/jdwp_handler.cc
+++ b/src/jdwp/jdwp_handler.cc
@@ -393,7 +393,7 @@
expandBufAdd1(reply, false); // canGetSourceDebugExtension
expandBufAdd1(reply, false); // canRequestVMDeathEvent
expandBufAdd1(reply, false); // canSetDefaultStratum
- expandBufAdd1(reply, false); // 1.6: canGetInstanceInfo
+ expandBufAdd1(reply, true); // 1.6: canGetInstanceInfo
expandBufAdd1(reply, false); // 1.6: canRequestMonitorEvents
expandBufAdd1(reply, true); // 1.6: canGetMonitorFrameInfo
expandBufAdd1(reply, false); // 1.6: canUseSourceNameFilters
@@ -448,6 +448,30 @@
return VM_AllClassesImpl(pReply, true, true);
}
+static JdwpError VM_InstanceCounts(JdwpState*, const uint8_t* buf, int, ExpandBuf* pReply)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ int32_t class_count = static_cast<int32_t>(Read4BE(&buf));
+ if (class_count < 0) {
+ return ERR_ILLEGAL_ARGUMENT;
+ }
+ std::vector<RefTypeId> class_ids;
+ for (int32_t i = 0; i < class_count; ++i) {
+ class_ids.push_back(ReadRefTypeId(&buf));
+ }
+
+ std::vector<uint64_t> counts;
+ JdwpError rc = Dbg::GetInstanceCounts(class_ids, counts);
+ if (rc != ERR_NONE) {
+ return rc;
+ }
+
+ expandBufAdd4BE(pReply, counts.size());
+ for (size_t i = 0; i < counts.size(); ++i) {
+ expandBufAdd8BE(pReply, counts[i]);
+ }
+ return ERR_NONE;
+}
+
static JdwpError RT_Modifiers(JdwpState*, const uint8_t* buf, int, ExpandBuf* pReply)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
RefTypeId refTypeId = ReadRefTypeId(&buf);
@@ -1574,7 +1598,7 @@
{ 1, 18, NULL, "VirtualMachine.RedefineClasses" },
{ 1, 19, NULL, "VirtualMachine.SetDefaultStratum" },
{ 1, 20, VM_AllClassesWithGeneric, "VirtualMachine.AllClassesWithGeneric" },
- { 1, 21, NULL, "VirtualMachine.InstanceCounts" },
+ { 1, 21, VM_InstanceCounts, "VirtualMachine.InstanceCounts" },
/* ReferenceType command set (2) */
{ 2, 1, RT_Signature, "ReferenceType.Signature" },
diff --git a/src/native/dalvik_system_VMDebug.cc b/src/native/dalvik_system_VMDebug.cc
index 3799bbe..e5a398a 100644
--- a/src/native/dalvik_system_VMDebug.cc
+++ b/src/native/dalvik_system_VMDebug.cc
@@ -224,7 +224,11 @@
if (c == NULL) {
return 0;
}
- return Runtime::Current()->GetHeap()->CountInstances(c, countAssignable);
+ std::vector<Class*> classes;
+ classes.push_back(c);
+ uint64_t count = 0;
+ Runtime::Current()->GetHeap()->CountInstances(classes, countAssignable, &count);
+ return count;
}
static JNINativeMethod gMethods[] = {