Remove Object* weak roots from the debugger.

The weak roots were converted to JNI weak refs.

Since the weak roots are now normal JNI weak refs, we eliminate the
need to insert read barriers for those weak roots in the debugger and
the need for the GC to have a separate step to update them as part of
the system weak sweeping.

Bug: 12687968
Change-Id: If16396d4713457b8af4f1ea6a0c6ec6799cb615e
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index a0cecb0..349700a 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -62,45 +62,98 @@
 static const size_t kMaxAllocRecordStackDepth = 16;  // Max 255.
 static const size_t kDefaultNumAllocRecords = 64*1024;  // Must be a power of 2.
 
-struct AllocRecordStackTraceElement {
-  mirror::ArtMethod* method;
-  uint32_t dex_pc;
-
-  AllocRecordStackTraceElement() : method(nullptr), dex_pc(0) {
+class AllocRecordStackTraceElement {
+ public:
+  AllocRecordStackTraceElement() : method_(nullptr), dex_pc_(0) {
   }
 
-  int32_t LineNumber() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return method->GetLineNumFromDexPC(dex_pc);
+  int32_t LineNumber() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    mirror::ArtMethod* method = Method();
+    DCHECK(method != nullptr);
+    return method->GetLineNumFromDexPC(DexPc());
   }
+
+  mirror::ArtMethod* Method() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    mirror::ArtMethod* method = reinterpret_cast<mirror::ArtMethod*>(
+        Thread::Current()->DecodeJObject(method_));
+    return method;
+  }
+
+  void SetMethod(mirror::ArtMethod* m) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    ScopedObjectAccessUnchecked soa(Thread::Current());
+    JNIEnv* env = soa.Env();
+    if (method_ != nullptr) {
+      env->DeleteWeakGlobalRef(method_);
+    }
+    method_ = env->NewWeakGlobalRef(soa.AddLocalReference<jobject>(m));
+  }
+
+  uint32_t DexPc() const {
+    return dex_pc_;
+  }
+
+  void SetDexPc(uint32_t pc) {
+    dex_pc_ = pc;
+  }
+
+ private:
+  jobject method_;  // This is a weak global.
+  uint32_t dex_pc_;
 };
 
-struct AllocRecord {
-  mirror::Class* type;
-  size_t byte_count;
-  uint16_t thin_lock_id;
-  AllocRecordStackTraceElement stack[kMaxAllocRecordStackDepth];  // Unused entries have NULL method.
+class AllocRecord {
+ public:
+  AllocRecord() : type_(nullptr), byte_count_(0), thin_lock_id_(0) {}
 
-  size_t GetDepth() {
+  mirror::Class* Type() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    mirror::Class* type = reinterpret_cast<mirror::Class*>(
+        Thread::Current()->DecodeJObject(type_));
+    return type;
+  }
+
+  void SetType(mirror::Class* t) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    ScopedObjectAccessUnchecked soa(Thread::Current());
+    JNIEnv* env = soa.Env();
+    if (type_ != nullptr) {
+      env->DeleteWeakGlobalRef(type_);
+    }
+    type_ = env->NewWeakGlobalRef(soa.AddLocalReference<jobject>(t));
+  }
+
+  size_t GetDepth() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     size_t depth = 0;
-    while (depth < kMaxAllocRecordStackDepth && stack[depth].method != NULL) {
+    while (depth < kMaxAllocRecordStackDepth && stack_[depth].Method() != NULL) {
       ++depth;
     }
     return depth;
   }
 
-  void UpdateObjectPointers(IsMarkedCallback* callback, void* arg)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    if (type != nullptr) {
-      type = down_cast<mirror::Class*>(callback(type, arg));
-    }
-    for (size_t stack_frame = 0; stack_frame < kMaxAllocRecordStackDepth; ++stack_frame) {
-      mirror::ArtMethod*& m = stack[stack_frame].method;
-      if (m == nullptr) {
-        break;
-      }
-      m = down_cast<mirror::ArtMethod*>(callback(m, arg));
-    }
+  size_t ByteCount() const {
+    return byte_count_;
   }
+
+  void SetByteCount(size_t count) {
+    byte_count_ = count;
+  }
+
+  uint16_t ThinLockId() const {
+    return thin_lock_id_;
+  }
+
+  void SetThinLockId(uint16_t id) {
+    thin_lock_id_ = id;
+  }
+
+  AllocRecordStackTraceElement* StackElement(size_t index) {
+    DCHECK_LT(index, kMaxAllocRecordStackDepth);
+    return &stack_[index];
+  }
+
+ private:
+  jobject type_;  // This is a weak global.
+  size_t byte_count_;
+  uint16_t thin_lock_id_;
+  AllocRecordStackTraceElement stack_[kMaxAllocRecordStackDepth];  // Unused entries have NULL method.
 };
 
 struct Breakpoint {
@@ -848,21 +901,13 @@
 JDWP::JdwpError Dbg::GetOwnedMonitors(JDWP::ObjectId thread_id,
                                       std::vector<JDWP::ObjectId>& monitors,
                                       std::vector<uint32_t>& stack_depths) {
-  ScopedObjectAccessUnchecked soa(Thread::Current());
-  MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
-  Thread* thread;
-  JDWP::JdwpError error = DecodeThread(soa, thread_id, thread);
-  if (error != JDWP::ERR_NONE) {
-    return error;
-  }
-  if (!IsSuspendedForDebugger(soa, thread)) {
-    return JDWP::ERR_THREAD_NOT_SUSPENDED;
-  }
-
   struct OwnedMonitorVisitor : public StackVisitor {
-    OwnedMonitorVisitor(Thread* thread, Context* context)
+    OwnedMonitorVisitor(Thread* thread, Context* context,
+                        std::vector<mirror::Object*>* monitor_vector,
+                        std::vector<uint32_t>* stack_depth_vector)
         SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-        : StackVisitor(thread, context), current_stack_depth(0) {}
+      : StackVisitor(thread, context), current_stack_depth(0),
+        monitors(monitor_vector), stack_depths(stack_depth_vector) {}
 
     // TODO: Enable annotalysis. We know lock is held in constructor, but abstraction confuses
     // annotalysis.
@@ -876,21 +921,38 @@
 
     static void AppendOwnedMonitors(mirror::Object* owned_monitor, void* arg) {
       OwnedMonitorVisitor* visitor = reinterpret_cast<OwnedMonitorVisitor*>(arg);
-      visitor->monitors.push_back(owned_monitor);
-      visitor->stack_depths.push_back(visitor->current_stack_depth);
+      visitor->monitors->push_back(owned_monitor);
+      visitor->stack_depths->push_back(visitor->current_stack_depth);
     }
 
     size_t current_stack_depth;
-    std::vector<mirror::Object*> monitors;
-    std::vector<uint32_t> stack_depths;
+    std::vector<mirror::Object*>* monitors;
+    std::vector<uint32_t>* stack_depths;
   };
-  std::unique_ptr<Context> context(Context::Create());
-  OwnedMonitorVisitor visitor(thread, context.get());
-  visitor.WalkStack();
 
-  for (size_t i = 0; i < visitor.monitors.size(); ++i) {
-    monitors.push_back(gRegistry->Add(visitor.monitors[i]));
-    stack_depths.push_back(visitor.stack_depths[i]);
+  std::vector<mirror::Object*> monitor_vector;
+  std::vector<uint32_t> stack_depth_vector;
+  ScopedObjectAccessUnchecked soa(Thread::Current());
+  {
+    MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
+    Thread* thread;
+    JDWP::JdwpError error = DecodeThread(soa, thread_id, thread);
+    if (error != JDWP::ERR_NONE) {
+      return error;
+    }
+    if (!IsSuspendedForDebugger(soa, thread)) {
+      return JDWP::ERR_THREAD_NOT_SUSPENDED;
+    }
+    std::unique_ptr<Context> context(Context::Create());
+    OwnedMonitorVisitor visitor(thread, context.get(), &monitor_vector, &stack_depth_vector);
+    visitor.WalkStack();
+  }
+
+  // Add() requires the thread_list_lock_ not held to avoid the lock
+  // level violation.
+  for (size_t i = 0; i < monitor_vector.size(); ++i) {
+    monitors.push_back(gRegistry->Add(monitor_vector[i]));
+    stack_depths.push_back(stack_depth_vector[i]);
   }
 
   return JDWP::ERR_NONE;
@@ -898,19 +960,23 @@
 
 JDWP::JdwpError Dbg::GetContendedMonitor(JDWP::ObjectId thread_id,
                                          JDWP::ObjectId& contended_monitor) {
+  mirror::Object* contended_monitor_obj;
   ScopedObjectAccessUnchecked soa(Thread::Current());
-  MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
-  Thread* thread;
-  JDWP::JdwpError error = DecodeThread(soa, thread_id, thread);
-  if (error != JDWP::ERR_NONE) {
-    return error;
+  {
+    MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
+    Thread* thread;
+    JDWP::JdwpError error = DecodeThread(soa, thread_id, thread);
+    if (error != JDWP::ERR_NONE) {
+      return error;
+    }
+    if (!IsSuspendedForDebugger(soa, thread)) {
+      return JDWP::ERR_THREAD_NOT_SUSPENDED;
+    }
+    contended_monitor_obj = Monitor::GetContendedMonitor(thread);
   }
-  if (!IsSuspendedForDebugger(soa, thread)) {
-    return JDWP::ERR_THREAD_NOT_SUSPENDED;
-  }
-
-  contended_monitor = gRegistry->Add(Monitor::GetContendedMonitor(thread));
-
+  // Add() requires the thread_list_lock_ not held to avoid the lock
+  // level violation.
+  contended_monitor = gRegistry->Add(contended_monitor_obj);
   return JDWP::ERR_NONE;
 }
 
@@ -1845,9 +1911,12 @@
   }
   const char* old_cause = soa.Self()->StartAssertNoThreadSuspension("Debugger: GetThreadGroup");
   // Okay, so it's an object, but is it actually a thread?
-  MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
-  Thread* thread;
-  JDWP::JdwpError error = DecodeThread(soa, thread_id, thread);
+  JDWP::JdwpError error;
+  {
+    MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
+    Thread* thread;
+    error = DecodeThread(soa, thread_id, thread);
+  }
   if (error == JDWP::ERR_THREAD_NOT_ALIVE) {
     // Zombie threads are in the null group.
     expandBufAddObjectId(pReply, JDWP::ObjectId(0));
@@ -1856,9 +1925,9 @@
     mirror::Class* c = soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_Thread);
     CHECK(c != nullptr);
     mirror::ArtField* f = c->FindInstanceField("group", "Ljava/lang/ThreadGroup;");
-    CHECK(f != NULL);
+    CHECK(f != nullptr);
     mirror::Object* group = f->GetObject(thread_object);
-    CHECK(group != NULL);
+    CHECK(group != nullptr);
     JDWP::ObjectId thread_group_id = gRegistry->Add(group);
     expandBufAddObjectId(pReply, thread_group_id);
   }
@@ -4146,8 +4215,8 @@
     }
     mirror::ArtMethod* m = GetMethod();
     if (!m->IsRuntimeMethod()) {
-      record->stack[depth].method = m;
-      record->stack[depth].dex_pc = GetDexPc();
+      record->StackElement(depth)->SetMethod(m);
+      record->StackElement(depth)->SetDexPc(GetDexPc());
       ++depth;
     }
     return true;
@@ -4156,8 +4225,8 @@
   ~AllocRecordStackVisitor() {
     // Clear out any unused stack trace elements.
     for (; depth < kMaxAllocRecordStackDepth; ++depth) {
-      record->stack[depth].method = NULL;
-      record->stack[depth].dex_pc = 0;
+      record->StackElement(depth)->SetMethod(nullptr);
+      record->StackElement(depth)->SetDexPc(0);
     }
   }
 
@@ -4181,9 +4250,9 @@
 
   // Fill in the basics.
   AllocRecord* record = &recent_allocation_records_[alloc_record_head_];
-  record->type = type;
-  record->byte_count = byte_count;
-  record->thin_lock_id = self->GetThreadId();
+  record->SetType(type);
+  record->SetByteCount(byte_count);
+  record->SetThinLockId(self->GetThreadId());
 
   // Fill in the stack trace.
   AllocRecordStackVisitor visitor(self, record);
@@ -4224,15 +4293,16 @@
   while (count--) {
     AllocRecord* record = &recent_allocation_records_[i];
 
-    LOG(INFO) << StringPrintf(" Thread %-2d %6zd bytes ", record->thin_lock_id, record->byte_count)
-              << PrettyClass(record->type);
+    LOG(INFO) << StringPrintf(" Thread %-2d %6zd bytes ", record->ThinLockId(), record->ByteCount())
+              << PrettyClass(record->Type());
 
     for (size_t stack_frame = 0; stack_frame < kMaxAllocRecordStackDepth; ++stack_frame) {
-      mirror::ArtMethod* m = record->stack[stack_frame].method;
+      AllocRecordStackTraceElement* stack_element = record->StackElement(stack_frame);
+      mirror::ArtMethod* m = stack_element->Method();
       if (m == NULL) {
         break;
       }
-      LOG(INFO) << "    " << PrettyMethod(m) << " line " << record->stack[stack_frame].LineNumber();
+      LOG(INFO) << "    " << PrettyMethod(m) << " line " << stack_element->LineNumber();
     }
 
     // pause periodically to help logcat catch up
@@ -4244,35 +4314,6 @@
   }
 }
 
-void Dbg::UpdateObjectPointers(IsMarkedCallback* callback, void* arg) {
-  if (recent_allocation_records_ != nullptr) {
-    MutexLock mu(Thread::Current(), *alloc_tracker_lock_);
-    size_t i = HeadIndex();
-    size_t count = alloc_record_count_;
-    while (count--) {
-      AllocRecord* record = &recent_allocation_records_[i];
-      DCHECK(record != nullptr);
-      record->UpdateObjectPointers(callback, arg);
-      i = (i + 1) & (alloc_record_max_ - 1);
-    }
-  }
-  if (gRegistry != nullptr) {
-    gRegistry->UpdateObjectPointers(callback, arg);
-  }
-}
-
-void Dbg::AllowNewObjectRegistryObjects() {
-  if (gRegistry != nullptr) {
-    gRegistry->AllowNewObjects();
-  }
-}
-
-void Dbg::DisallowNewObjectRegistryObjects() {
-  if (gRegistry != nullptr) {
-    gRegistry->DisallowNewObjects();
-  }
-}
-
 class StringTable {
  public:
   StringTable() {
@@ -4379,10 +4420,10 @@
     while (count--) {
       AllocRecord* record = &recent_allocation_records_[idx];
 
-      class_names.Add(record->type->GetDescriptor().c_str());
+      class_names.Add(record->Type()->GetDescriptor().c_str());
 
       for (size_t i = 0; i < kMaxAllocRecordStackDepth; i++) {
-        mirror::ArtMethod* m = record->stack[i].method;
+        mirror::ArtMethod* m = record->StackElement(i)->Method();
         if (m != NULL) {
           class_names.Add(m->GetDeclaringClassDescriptor());
           method_names.Add(m->GetName());
@@ -4432,9 +4473,9 @@
       AllocRecord* record = &recent_allocation_records_[idx];
       size_t stack_depth = record->GetDepth();
       size_t allocated_object_class_name_index =
-          class_names.IndexOf(record->type->GetDescriptor().c_str());
-      JDWP::Append4BE(bytes, record->byte_count);
-      JDWP::Append2BE(bytes, record->thin_lock_id);
+          class_names.IndexOf(record->Type()->GetDescriptor().c_str());
+      JDWP::Append4BE(bytes, record->ByteCount());
+      JDWP::Append2BE(bytes, record->ThinLockId());
       JDWP::Append2BE(bytes, allocated_object_class_name_index);
       JDWP::Append1BE(bytes, stack_depth);
 
@@ -4444,14 +4485,14 @@
         // (2b) method name
         // (2b) method source file
         // (2b) line number, clipped to 32767; -2 if native; -1 if no source
-        mirror::ArtMethod* m = record->stack[stack_frame].method;
+        mirror::ArtMethod* m = record->StackElement(stack_frame)->Method();
         size_t class_name_index = class_names.IndexOf(m->GetDeclaringClassDescriptor());
         size_t method_name_index = method_names.IndexOf(m->GetName());
         size_t file_name_index = filenames.IndexOf(GetMethodSourceFile(m));
         JDWP::Append2BE(bytes, class_name_index);
         JDWP::Append2BE(bytes, method_name_index);
         JDWP::Append2BE(bytes, file_name_index);
-        JDWP::Append2BE(bytes, record->stack[stack_frame].LineNumber());
+        JDWP::Append2BE(bytes, record->StackElement(stack_frame)->LineNumber());
       }
 
       idx = (idx + 1) & (alloc_record_max_ - 1);
diff --git a/runtime/debugger.h b/runtime/debugger.h
index 31ffd6e..1cf0b0c 100644
--- a/runtime/debugger.h
+++ b/runtime/debugger.h
@@ -41,7 +41,7 @@
 class Object;
 class Throwable;
 }  // namespace mirror
-struct AllocRecord;
+class AllocRecord;
 class Thread;
 class ThrowLocation;
 
@@ -531,11 +531,6 @@
   static size_t HeadIndex() EXCLUSIVE_LOCKS_REQUIRED(alloc_tracker_lock_);
   static void DumpRecentAllocations() LOCKS_EXCLUDED(alloc_tracker_lock_);
 
-  // Updates the stored direct object pointers (called from SweepSystemWeaks).
-  static void UpdateObjectPointers(IsMarkedCallback* callback, void* arg)
-      LOCKS_EXCLUDED(alloc_tracker_lock_)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
   enum HpifWhen {
     HPIF_WHEN_NEVER = 0,
     HPIF_WHEN_NOW = 1,
@@ -560,9 +555,6 @@
   static void DdmSendHeapSegments(bool native)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  static void AllowNewObjectRegistryObjects() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  static void DisallowNewObjectRegistryObjects() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
  private:
   static void DdmBroadcast(bool connect) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static void PostThreadStartOrStop(Thread*, uint32_t)
diff --git a/runtime/jdwp/object_registry.cc b/runtime/jdwp/object_registry.cc
index 49dceb2..d637a94 100644
--- a/runtime/jdwp/object_registry.cc
+++ b/runtime/jdwp/object_registry.cc
@@ -31,8 +31,7 @@
 }
 
 ObjectRegistry::ObjectRegistry()
-    : lock_("ObjectRegistry lock", kJdwpObjectRegistryLock), allow_new_objects_(true),
-      condition_("object registry condition", lock_), next_id_(1) {
+    : lock_("ObjectRegistry lock", kJdwpObjectRegistryLock), next_id_(1) {
 }
 
 JDWP::RefTypeId ObjectRegistry::AddRefType(mirror::Class* c) {
@@ -44,20 +43,17 @@
 }
 
 JDWP::ObjectId ObjectRegistry::InternalAdd(mirror::Object* o) {
-  if (o == NULL) {
+  if (o == nullptr) {
     return 0;
   }
 
+  // Call IdentityHashCode here to avoid a lock level violation between lock_ and monitor_lock.
+  int32_t identity_hash_code = o->IdentityHashCode();
   ScopedObjectAccessUnchecked soa(Thread::Current());
   MutexLock mu(soa.Self(), lock_);
-  while (UNLIKELY(!allow_new_objects_)) {
-    condition_.WaitHoldingLocks(soa.Self());
-  }
-  ObjectRegistryEntry* entry;
-  auto it = object_to_entry_.find(o);
-  if (it != object_to_entry_.end()) {
+  ObjectRegistryEntry* entry = nullptr;
+  if (ContainsLocked(soa.Self(), o, identity_hash_code, &entry)) {
     // This object was already in our map.
-    entry = it->second;
     ++entry->reference_count;
   } else {
     entry = new ObjectRegistryEntry;
@@ -65,7 +61,8 @@
     entry->jni_reference = nullptr;
     entry->reference_count = 0;
     entry->id = 0;
-    object_to_entry_.insert(std::make_pair(o, entry));
+    entry->identity_hash_code = identity_hash_code;
+    object_to_entry_.insert(std::make_pair(identity_hash_code, entry));
 
     // This object isn't in the registry yet, so add it.
     JNIEnv* env = soa.Env();
@@ -84,9 +81,31 @@
   return entry->id;
 }
 
-bool ObjectRegistry::Contains(mirror::Object* o) {
-  MutexLock mu(Thread::Current(), lock_);
-  return object_to_entry_.find(o) != object_to_entry_.end();
+bool ObjectRegistry::Contains(mirror::Object* o, ObjectRegistryEntry** out_entry) {
+  if (o == nullptr) {
+    return false;
+  }
+  // Call IdentityHashCode here to avoid a lock level violation between lock_ and monitor_lock.
+  int32_t identity_hash_code = o->IdentityHashCode();
+  Thread* self = Thread::Current();
+  MutexLock mu(self, lock_);
+  return ContainsLocked(self, o, identity_hash_code, out_entry);
+}
+
+bool ObjectRegistry::ContainsLocked(Thread* self, mirror::Object* o, int32_t identity_hash_code,
+                                    ObjectRegistryEntry** out_entry) {
+  DCHECK(o != nullptr);
+  for (auto it = object_to_entry_.lower_bound(identity_hash_code), end = object_to_entry_.end();
+       it != end && it->first == identity_hash_code; ++it) {
+    ObjectRegistryEntry* entry = it->second;
+    if (o == self->DecodeJObject(entry->jni_reference)) {
+      if (out_entry != nullptr) {
+        *out_entry = entry;
+      }
+      return true;
+    }
+  }
+  return false;
 }
 
 void ObjectRegistry::Clear() {
@@ -194,47 +213,24 @@
   entry->reference_count -= reference_count;
   if (entry->reference_count <= 0) {
     JNIEnv* env = self->GetJniEnv();
-    mirror::Object* object = self->DecodeJObject(entry->jni_reference);
+    // Erase the object from the maps. Note object may be null if it's
+    // a weak ref and the GC has cleared it.
+    int32_t hash_code = entry->identity_hash_code;
+    for (auto it = object_to_entry_.lower_bound(hash_code), end = object_to_entry_.end();
+         it != end && it->first == hash_code; ++it) {
+      if (entry == it->second) {
+        object_to_entry_.erase(it);
+        break;
+      }
+    }
     if (entry->jni_reference_type == JNIWeakGlobalRefType) {
       env->DeleteWeakGlobalRef(entry->jni_reference);
     } else {
       env->DeleteGlobalRef(entry->jni_reference);
     }
-    object_to_entry_.erase(object);
     id_to_entry_.erase(id);
     delete entry;
   }
 }
 
-void ObjectRegistry::UpdateObjectPointers(IsMarkedCallback* callback, 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 = callback(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
diff --git a/runtime/jdwp/object_registry.h b/runtime/jdwp/object_registry.h
index 3c6cb15..e1a6875 100644
--- a/runtime/jdwp/object_registry.h
+++ b/runtime/jdwp/object_registry.h
@@ -43,6 +43,10 @@
 
   // The corresponding id, so we only need one map lookup in Add.
   JDWP::ObjectId id;
+
+  // The identity hash code of the object. This is the same as the key
+  // for object_to_entry_. Store this for DisposeObject().
+  int32_t identity_hash_code;
 };
 std::ostream& operator<<(std::ostream& os, const ObjectRegistryEntry& rhs);
 
@@ -55,7 +59,8 @@
  public:
   ObjectRegistry();
 
-  JDWP::ObjectId Add(mirror::Object* o) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  JDWP::ObjectId Add(mirror::Object* o)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(Locks::thread_list_lock_);
   JDWP::RefTypeId AddRefType(mirror::Class* c) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   template<typename T> T Get(JDWP::ObjectId id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -65,7 +70,9 @@
     return reinterpret_cast<T>(InternalGet(id));
   }
 
-  bool Contains(mirror::Object* o) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  bool Contains(mirror::Object* o) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    return Contains(o, nullptr);
+  }
 
   void Clear() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -84,26 +91,20 @@
   // Avoid using this and use standard Get when possible.
   jobject GetJObject(JDWP::ObjectId id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  // Visit, objects are treated as system weaks.
-  void UpdateObjectPointers(IsMarkedCallback* callback, void* arg)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
-  // We have allow / disallow functionality since we use system weak sweeping logic to update moved
-  // objects inside of the object_to_entry_ map.
-  void AllowNewObjects() LOCKS_EXCLUDED(lock_);
-  void DisallowNewObjects() LOCKS_EXCLUDED(lock_);
-
  private:
-  JDWP::ObjectId InternalAdd(mirror::Object* o) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  JDWP::ObjectId InternalAdd(mirror::Object* o)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(Locks::thread_list_lock_);
   mirror::Object* InternalGet(JDWP::ObjectId id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void Demote(ObjectRegistryEntry& entry) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_, lock_);
   void Promote(ObjectRegistryEntry& entry) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_, lock_);
+  bool Contains(mirror::Object* o, ObjectRegistryEntry** out_entry)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  bool ContainsLocked(Thread* self, mirror::Object* o, int32_t identity_hash_code,
+                      ObjectRegistryEntry** out_entry)
+      EXCLUSIVE_LOCKS_REQUIRED(lock_) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   Mutex lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
-  bool allow_new_objects_ GUARDED_BY(lock_);
-  ConditionVariable condition_ GUARDED_BY(lock_);
-
-  std::map<mirror::Object*, ObjectRegistryEntry*> object_to_entry_ GUARDED_BY(lock_);
+  std::multimap<int32_t, ObjectRegistryEntry*> object_to_entry_ GUARDED_BY(lock_);
   SafeMap<JDWP::ObjectId, ObjectRegistryEntry*> id_to_entry_ GUARDED_BY(lock_);
 
   size_t next_id_ GUARDED_BY(lock_);
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index bcb4eb3..ccf478c 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -309,7 +309,6 @@
   GetInternTable()->SweepInternTableWeaks(visitor, arg);
   GetMonitorList()->SweepMonitorList(visitor, arg);
   GetJavaVM()->SweepJniWeakGlobals(visitor, arg);
-  Dbg::UpdateObjectPointers(visitor, arg);
 }
 
 bool Runtime::Create(const Options& options, bool ignore_unrecognized) {
@@ -1043,14 +1042,12 @@
   monitor_list_->DisallowNewMonitors();
   intern_table_->DisallowNewInterns();
   java_vm_->DisallowNewWeakGlobals();
-  Dbg::DisallowNewObjectRegistryObjects();
 }
 
 void Runtime::AllowNewSystemWeaks() {
   monitor_list_->AllowNewMonitors();
   intern_table_->AllowNewInterns();
   java_vm_->AllowNewWeakGlobals();
-  Dbg::AllowNewObjectRegistryObjects();
 }
 
 void Runtime::SetInstructionSet(InstructionSet instruction_set) {