Make debugger / jdwp compaction safe.

Fixed GetInstances, GetReferringObjects, CountInstances to use
VisitObjects instead of the live bitmap.

We now treat the object registry as system weaks and update the
objects when/if they move. Also added the recent_allocation_records_
as roots.

Bug: 12936165

Change-Id: I615c289efbf2977ceab5c4ffa73d216d799e6e33
diff --git a/runtime/jdwp/object_registry.cc b/runtime/jdwp/object_registry.cc
index 369eddd..40ba3e3 100644
--- a/runtime/jdwp/object_registry.cc
+++ b/runtime/jdwp/object_registry.cc
@@ -31,7 +31,8 @@
 }
 
 ObjectRegistry::ObjectRegistry()
-    : lock_("ObjectRegistry lock", kJdwpObjectRegistryLock), next_id_(1) {
+    : lock_("ObjectRegistry lock", kJdwpObjectRegistryLock), allow_new_objects_(true),
+      condition_("object registry condition", lock_), next_id_(1) {
 }
 
 JDWP::RefTypeId ObjectRegistry::AddRefType(mirror::Class* c) {
@@ -49,58 +50,59 @@
 
   ScopedObjectAccessUnchecked soa(Thread::Current());
   MutexLock mu(soa.Self(), lock_);
-  ObjectRegistryEntry dummy;
-  dummy.jni_reference_type = JNIWeakGlobalRefType;
-  dummy.jni_reference = NULL;
-  dummy.reference_count = 0;
-  dummy.id = 0;
-  std::pair<object_iterator, bool> result = object_to_entry_.insert(std::make_pair(o, dummy));
-  ObjectRegistryEntry& entry = result.first->second;
-  if (!result.second) {
-    // This object was already in our map.
-    entry.reference_count += 1;
-    return entry.id;
+  while (UNLIKELY(!allow_new_objects_)) {
+    condition_.WaitHoldingLocks(soa.Self());
   }
+  ObjectRegistryEntry* entry;
+  auto it = object_to_entry_.find(o);
+  if (it != object_to_entry_.end()) {
+    // This object was already in our map.
+    entry = it->second;
+    ++entry->reference_count;
+  } else {
+    entry = new ObjectRegistryEntry;
+    entry->jni_reference_type = JNIWeakGlobalRefType;
+    entry->jni_reference = nullptr;
+    entry->reference_count = 0;
+    entry->id = 0;
+    object_to_entry_.insert(std::make_pair(o, entry));
 
-  // This object isn't in the registry yet, so add it.
-  JNIEnv* env = soa.Env();
+    // This object isn't in the registry yet, so add it.
+    JNIEnv* env = soa.Env();
 
-  jobject local_reference = soa.AddLocalReference<jobject>(o);
+    jobject local_reference = soa.AddLocalReference<jobject>(o);
 
-  entry.jni_reference_type = JNIWeakGlobalRefType;
-  entry.jni_reference = env->NewWeakGlobalRef(local_reference);
-  entry.reference_count = 1;
-  entry.id = next_id_++;
+    entry->jni_reference_type = JNIWeakGlobalRefType;
+    entry->jni_reference = env->NewWeakGlobalRef(local_reference);
+    entry->reference_count = 1;
+    entry->id = next_id_++;
 
-  id_to_entry_.Put(entry.id, &entry);
+    id_to_entry_.Put(entry->id, entry);
 
-  env->DeleteLocalRef(local_reference);
-
-  return entry.id;
+    env->DeleteLocalRef(local_reference);
+  }
+  return entry->id;
 }
 
 bool ObjectRegistry::Contains(mirror::Object* o) {
-  Thread* self = Thread::Current();
-  MutexLock mu(self, lock_);
-  return (object_to_entry_.find(o) != object_to_entry_.end());
+  MutexLock mu(Thread::Current(), lock_);
+  return object_to_entry_.find(o) != object_to_entry_.end();
 }
 
 void ObjectRegistry::Clear() {
   Thread* self = Thread::Current();
   MutexLock mu(self, lock_);
   VLOG(jdwp) << "Object registry contained " << object_to_entry_.size() << " entries";
-
   // Delete all the JNI references.
   JNIEnv* env = self->GetJniEnv();
-  for (object_iterator it = object_to_entry_.begin(); it != object_to_entry_.end(); ++it) {
-    ObjectRegistryEntry& entry = (it->second);
+  for (const auto& pair : object_to_entry_) {
+    const ObjectRegistryEntry& entry = *pair.second;
     if (entry.jni_reference_type == JNIWeakGlobalRefType) {
       env->DeleteWeakGlobalRef(entry.jni_reference);
     } else {
       env->DeleteGlobalRef(entry.jni_reference);
     }
   }
-
   // Clear the maps.
   object_to_entry_.clear();
   id_to_entry_.clear();
@@ -109,11 +111,11 @@
 mirror::Object* ObjectRegistry::InternalGet(JDWP::ObjectId id) {
   Thread* self = Thread::Current();
   MutexLock mu(self, lock_);
-  id_iterator it = id_to_entry_.find(id);
+  auto it = id_to_entry_.find(id);
   if (it == id_to_entry_.end()) {
     return kInvalidObject;
   }
-  ObjectRegistryEntry& entry = *(it->second);
+  ObjectRegistryEntry& entry = *it->second;
   return self->DecodeJObject(entry.jni_reference);
 }
 
@@ -123,26 +125,26 @@
   }
   Thread* self = Thread::Current();
   MutexLock mu(self, lock_);
-  id_iterator it = id_to_entry_.find(id);
+  auto it = id_to_entry_.find(id);
   CHECK(it != id_to_entry_.end()) << id;
-  ObjectRegistryEntry& entry = *(it->second);
+  ObjectRegistryEntry& entry = *it->second;
   return entry.jni_reference;
 }
 
 void ObjectRegistry::DisableCollection(JDWP::ObjectId id) {
   Thread* self = Thread::Current();
   MutexLock mu(self, lock_);
-  id_iterator it = id_to_entry_.find(id);
+  auto it = id_to_entry_.find(id);
   CHECK(it != id_to_entry_.end());
-  Promote(*(it->second));
+  Promote(*it->second);
 }
 
 void ObjectRegistry::EnableCollection(JDWP::ObjectId id) {
   Thread* self = Thread::Current();
   MutexLock mu(self, lock_);
-  id_iterator it = id_to_entry_.find(id);
+  auto it = id_to_entry_.find(id);
   CHECK(it != id_to_entry_.end());
-  Demote(*(it->second));
+  Demote(*it->second);
 }
 
 void ObjectRegistry::Demote(ObjectRegistryEntry& entry) {
@@ -170,10 +172,9 @@
 bool ObjectRegistry::IsCollected(JDWP::ObjectId id) {
   Thread* self = Thread::Current();
   MutexLock mu(self, lock_);
-  id_iterator it = id_to_entry_.find(id);
+  auto it = id_to_entry_.find(id);
   CHECK(it != id_to_entry_.end());
-
-  ObjectRegistryEntry& entry = *(it->second);
+  ObjectRegistryEntry& entry = *it->second;
   if (entry.jni_reference_type == JNIWeakGlobalRefType) {
     JNIEnv* env = self->GetJniEnv();
     return env->IsSameObject(entry.jni_reference, NULL);  // Has the jweak been collected?
@@ -185,24 +186,55 @@
 void ObjectRegistry::DisposeObject(JDWP::ObjectId id, uint32_t reference_count) {
   Thread* self = Thread::Current();
   MutexLock mu(self, lock_);
-  id_iterator it = id_to_entry_.find(id);
+  auto it = id_to_entry_.find(id);
   if (it == id_to_entry_.end()) {
     return;
   }
-
-  ObjectRegistryEntry& entry = *(it->second);
-  entry.reference_count -= reference_count;
-  if (entry.reference_count <= 0) {
+  ObjectRegistryEntry* entry = it->second;
+  entry->reference_count -= reference_count;
+  if (entry->reference_count <= 0) {
     JNIEnv* env = self->GetJniEnv();
-    mirror::Object* object = self->DecodeJObject(entry.jni_reference);
-    if (entry.jni_reference_type == JNIWeakGlobalRefType) {
-      env->DeleteWeakGlobalRef(entry.jni_reference);
+    mirror::Object* object = self->DecodeJObject(entry->jni_reference);
+    if (entry->jni_reference_type == JNIWeakGlobalRefType) {
+      env->DeleteWeakGlobalRef(entry->jni_reference);
     } else {
-      env->DeleteGlobalRef(entry.jni_reference);
+      env->DeleteGlobalRef(entry->jni_reference);
     }
     object_to_entry_.erase(object);
     id_to_entry_.erase(id);
+    delete entry;
   }
 }
 
+void ObjectRegistry::UpdateObjectPointers(RootVisitor visitor, void* arg) {
+  MutexLock mu(Thread::Current(), lock_);
+  if (object_to_entry_.empty()) {
+    return;
+  }
+  std::map<mirror::Object*, ObjectRegistryEntry*> new_object_to_entry;
+  for (auto& pair : object_to_entry_) {
+    mirror::Object* new_obj;
+    if (pair.first != nullptr) {
+      new_obj = visitor(pair.first, arg);
+      if (new_obj != nullptr) {
+        new_object_to_entry.insert(std::make_pair(new_obj, pair.second));
+      }
+    }
+  }
+  object_to_entry_ = new_object_to_entry;
+}
+
+void ObjectRegistry::AllowNewObjects() {
+  Thread* self = Thread::Current();
+  MutexLock mu(self, lock_);
+  allow_new_objects_ = true;
+  condition_.Broadcast(self);
+}
+
+void ObjectRegistry::DisallowNewObjects() {
+  Thread* self = Thread::Current();
+  MutexLock mu(self, lock_);
+  allow_new_objects_ = false;
+}
+
 }  // namespace art