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[] = {