Implement as much of VMDebug as we can reasonably do right now.

No hprof and no method tracing, but everything else.

Change-Id: Ifccd1f08e31f34b947c30f1211db788aae674d81
diff --git a/src/heap.cc b/src/heap.cc
index 094790a..4d8d176 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -40,6 +40,8 @@
 
 Mutex* Heap::lock_ = NULL;
 
+bool Heap::verify_objects_ = false;
+
 class ScopedHeapLock {
  public:
   ScopedHeapLock() {
@@ -169,8 +171,6 @@
   return true;
 }
 
-bool Heap::verify_objects_ = false;
-
 #if VERIFY_OBJECT_ENABLED
 void Heap::VerifyObject(const Object* obj) {
   if (!verify_objects_) {
@@ -237,6 +237,16 @@
   DCHECK_NE(size, 0u);
   num_bytes_allocated_ += size;
   num_objects_allocated_ += 1;
+
+  if (Runtime::Current()->HasStatsEnabled()) {
+    RuntimeStats* global_stats = Runtime::Current()->GetStats();
+    RuntimeStats* thread_stats = Thread::Current()->GetStats();
+    ++global_stats->allocated_objects;
+    ++thread_stats->allocated_objects;
+    global_stats->allocated_bytes += size;
+    thread_stats->allocated_bytes += size;
+  }
+
   live_bitmap_->Set(obj);
 }
 
@@ -253,6 +263,15 @@
   if (num_objects_allocated_ > 0) {
     num_objects_allocated_ -= 1;
   }
+
+  if (Runtime::Current()->HasStatsEnabled()) {
+    RuntimeStats* global_stats = Runtime::Current()->GetStats();
+    RuntimeStats* thread_stats = Thread::Current()->GetStats();
+    ++global_stats->freed_objects;
+    ++thread_stats->freed_objects;
+    global_stats->freed_bytes += size;
+    thread_stats->freed_bytes += size;
+  }
 }
 
 void Heap::RecordImageAllocations(Space* space) {
@@ -307,6 +326,10 @@
   // Another failure.  Our thread was starved or there may be too many
   // live objects.  Try a foreground GC.  This will have no effect if
   // the concurrent GC is already running.
+  if (Runtime::Current()->HasStatsEnabled()) {
+    ++Runtime::Current()->GetStats()->gc_for_alloc_count;
+    ++Thread::Current()->GetStats()->gc_for_alloc_count;
+  }
   CollectGarbageInternal();
   ptr = space->AllocWithoutGrowth(size);
   if (ptr != NULL) {
@@ -365,6 +388,46 @@
   return 0;
 }
 
+class InstanceCounter {
+ public:
+  InstanceCounter(Class* c, bool count_assignable)
+      : class_(c), count_assignable_(count_assignable), count_(0) {
+  }
+
+  size_t GetCount() {
+    return count_;
+  }
+
+  static void Callback(Object* o, void* arg) {
+    reinterpret_cast<InstanceCounter*>(arg)->VisitInstance(o);
+  }
+
+ private:
+  void VisitInstance(Object* o) {
+    Class* instance_class = o->GetClass();
+    if (count_assignable_) {
+      if (instance_class == class_) {
+        ++count_;
+      }
+    } else {
+      if (instance_class != NULL && class_->IsAssignableFrom(instance_class)) {
+        ++count_;
+      }
+    }
+  }
+
+  Class* class_;
+  bool count_assignable_;
+  size_t count_;
+};
+
+int64_t Heap::CountInstances(Class* c, bool count_assignable) {
+  ScopedHeapLock lock;
+  InstanceCounter counter(c, count_assignable);
+  live_bitmap_->Walk(InstanceCounter::Callback, &counter);
+  return counter.GetCount();
+}
+
 void Heap::CollectGarbage() {
   ScopedHeapLock lock;
   CollectGarbageInternal();