Remove abuse of mirror::Object* to reference special values.

Remove kInvalidIndirectRefObject, kClearedJniWeakGlobal and
ObjectRegistry::kInvalidObject. Handle error conditions by passing in or
returning an error value.
GetObjectRefType is simplified to be faster and not return invalid references
that are not expected according to the spec. Adjust check JNI and
jni_internal_test appropriately.
Fix cases in the debugger/JDWP of out arguments being passed by reference.
Bug: 17376993

Change-Id: I3ce8a28c01827e163f4dc288449959464da788b1
diff --git a/runtime/check_jni.cc b/runtime/check_jni.cc
index b0f8e22..95223d8 100644
--- a/runtime/check_jni.cc
+++ b/runtime/check_jni.cc
@@ -650,6 +650,24 @@
     }
 
     mirror::Object* obj = soa.Decode<mirror::Object*>(java_object);
+    if (obj == nullptr) {
+      // Either java_object is invalid or is a cleared weak.
+      IndirectRef ref = reinterpret_cast<IndirectRef>(java_object);
+      bool okay;
+      if (GetIndirectRefKind(ref) != kWeakGlobal) {
+        okay = false;
+      } else {
+        obj = soa.Vm()->DecodeWeakGlobal(soa.Self(), ref);
+        okay = Runtime::Current()->IsClearedJniWeakGlobal(obj);
+      }
+      if (!okay) {
+        AbortF("%s is an invalid %s: %p (%p)",
+               what, ToStr<IndirectRefKind>(GetIndirectRefKind(java_object)).c_str(),
+               java_object, obj);
+        return false;
+      }
+    }
+
     if (!Runtime::Current()->GetHeap()->IsValidObjectAddress(obj)) {
       Runtime::Current()->GetHeap()->DumpSpaces(LOG(ERROR));
       AbortF("%s is an invalid %s: %p (%p)",
@@ -784,8 +802,7 @@
         mirror::Class* c = soa.Decode<mirror::Class*>(jc);
         if (c == nullptr) {
           *msg += "NULL";
-        } else if (c == kInvalidIndirectRefObject ||
-            !Runtime::Current()->GetHeap()->IsValidObjectAddress(c)) {
+        } else if (!Runtime::Current()->GetHeap()->IsValidObjectAddress(c)) {
           StringAppendF(msg, "INVALID POINTER:%p", jc);
         } else if (!c->IsClass()) {
           *msg += "INVALID NON-CLASS OBJECT OF TYPE:" + PrettyTypeOf(c);
@@ -1453,12 +1470,13 @@
   }
 
   static jobjectRefType GetObjectRefType(JNIEnv* env, jobject obj) {
-    // Note: we use "Ep" rather than "EL" because this is the one JNI function that it's okay to
-    // pass an invalid reference to.
+    // Note: we use "EL" here but "Ep" has been used in the past on the basis that we'd like to
+    // know the object is invalid. The spec says that passing invalid objects or even ones that
+    // are deleted isn't supported.
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_Default, __FUNCTION__);
-    JniValueType args[2] = {{.E = env }, {.p = obj}};
-    if (sc.Check(soa, true, "Ep", args)) {
+    JniValueType args[2] = {{.E = env }, {.L = obj}};
+    if (sc.Check(soa, true, "EL", args)) {
       JniValueType result;
       result.w = baseEnv(env)->GetObjectRefType(env, obj);
       if (sc.Check(soa, false, "w", &result)) {
diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h
index d05f7af..1306546 100644
--- a/runtime/class_linker-inl.h
+++ b/runtime/class_linker-inl.h
@@ -155,6 +155,11 @@
   return resolved_field;
 }
 
+inline mirror::Object* ClassLinker::AllocObject(Thread* self) {
+  return GetClassRoot(kJavaLangObject)->Alloc<false, false>(self,
+      Runtime::Current()->GetHeap()->GetCurrentAllocator());
+}
+
 template <class T>
 inline mirror::ObjectArray<T>* ClassLinker::AllocObjectArray(Thread* self, size_t length) {
   return mirror::ObjectArray<T>::Alloc(self, GetClassRoot(kObjectArrayClass), length);
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 064a85d..a7a68b7 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -288,6 +288,9 @@
                                            InstructionSet instruction_set,
                                            std::string* error_msg);
 
+  // Allocate an instance of a java.lang.Object.
+  mirror::Object* AllocObject(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   // TODO: replace this with multiple methods that allocate the correct managed type.
   template <class T>
   mirror::ObjectArray<T>* AllocObjectArray(Thread* self, size_t length)
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 9136f9f..8b8e7c8 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -132,12 +132,12 @@
   }
 
   void SetType(mirror::Class* t) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    type_ = Dbg::GetTypeCache().Add(t);
+    type_ = Dbg::GetTypeCache()->Add(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() != nullptr) {
       ++depth;
     }
     return depth;
@@ -168,7 +168,7 @@
   jobject type_;  // This is a weak global.
   size_t byte_count_;
   uint16_t thin_lock_id_;
-  AllocRecordStackTraceElement stack_[kMaxAllocRecordStackDepth];  // Unused entries have NULL method.
+  AllocRecordStackTraceElement stack_[kMaxAllocRecordStackDepth];  // Unused entries have nullptr method.
 };
 
 class Breakpoint {
@@ -287,7 +287,7 @@
 static JDWP::JdwpOptions gJdwpOptions;
 
 // Runtime JDWP state.
-static JDWP::JdwpState* gJdwpState = NULL;
+static JDWP::JdwpState* gJdwpState = nullptr;
 static bool gDebuggerConnected;  // debugger or DDMS is connected.
 static bool gDebuggerActive;     // debugger is making requests.
 static bool gDisposed;           // debugger called VirtualMachine.Dispose, so we should drop the connection.
@@ -391,58 +391,60 @@
   return thread->IsSuspended() && thread->GetDebugSuspendCount() > 0;
 }
 
-static mirror::Array* DecodeArray(JDWP::RefTypeId id, JDWP::JdwpError& status)
+static mirror::Array* DecodeNonNullArray(JDWP::RefTypeId id, JDWP::JdwpError* error)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  mirror::Object* o = gRegistry->Get<mirror::Object*>(id);
-  if (o == NULL || o == ObjectRegistry::kInvalidObject) {
-    status = JDWP::ERR_INVALID_OBJECT;
-    return NULL;
+  mirror::Object* o = gRegistry->Get<mirror::Object*>(id, error);
+  if (o == nullptr) {
+    *error = JDWP::ERR_INVALID_OBJECT;
+    return nullptr;
   }
   if (!o->IsArrayInstance()) {
-    status = JDWP::ERR_INVALID_ARRAY;
-    return NULL;
+    *error = JDWP::ERR_INVALID_ARRAY;
+    return nullptr;
   }
-  status = JDWP::ERR_NONE;
+  *error = JDWP::ERR_NONE;
   return o->AsArray();
 }
 
-static mirror::Class* DecodeClass(JDWP::RefTypeId id, JDWP::JdwpError& status)
+static mirror::Class* DecodeClass(JDWP::RefTypeId id, JDWP::JdwpError* error)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  mirror::Object* o = gRegistry->Get<mirror::Object*>(id);
-  if (o == NULL || o == ObjectRegistry::kInvalidObject) {
-    status = JDWP::ERR_INVALID_OBJECT;
-    return NULL;
+  mirror::Object* o = gRegistry->Get<mirror::Object*>(id, error);
+  if (o == nullptr) {
+    *error = JDWP::ERR_INVALID_OBJECT;
+    return nullptr;
   }
   if (!o->IsClass()) {
-    status = JDWP::ERR_INVALID_CLASS;
-    return NULL;
+    *error = JDWP::ERR_INVALID_CLASS;
+    return nullptr;
   }
-  status = JDWP::ERR_NONE;
+  *error = JDWP::ERR_NONE;
   return o->AsClass();
 }
 
-static JDWP::JdwpError DecodeThread(ScopedObjectAccessUnchecked& soa, JDWP::ObjectId thread_id, Thread*& thread)
+static Thread* DecodeThread(ScopedObjectAccessUnchecked& soa, JDWP::ObjectId thread_id,
+                            JDWP::JdwpError* error)
     EXCLUSIVE_LOCKS_REQUIRED(Locks::thread_list_lock_)
     LOCKS_EXCLUDED(Locks::thread_suspend_count_lock_)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  mirror::Object* thread_peer = gRegistry->Get<mirror::Object*>(thread_id);
-  if (thread_peer == NULL || thread_peer == ObjectRegistry::kInvalidObject) {
+  mirror::Object* thread_peer = gRegistry->Get<mirror::Object*>(thread_id, error);
+  if (thread_peer == nullptr) {
     // This isn't even an object.
-    return JDWP::ERR_INVALID_OBJECT;
+    *error = JDWP::ERR_INVALID_OBJECT;
+    return nullptr;
   }
 
   mirror::Class* java_lang_Thread = soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_Thread);
   if (!java_lang_Thread->IsAssignableFrom(thread_peer->GetClass())) {
     // This isn't a thread.
-    return JDWP::ERR_INVALID_THREAD;
+    *error = JDWP::ERR_INVALID_THREAD;
+    return nullptr;
   }
 
-  thread = Thread::FromManagedThread(soa, thread_peer);
-  if (thread == NULL) {
-    // This is a java.lang.Thread without a Thread*. Must be a zombie.
-    return JDWP::ERR_THREAD_NOT_ALIVE;
-  }
-  return JDWP::ERR_NONE;
+  Thread* thread = Thread::FromManagedThread(soa, thread_peer);
+  // If thread is null then this a java.lang.Thread without a Thread*. Must be a un-started or a
+  // zombie.
+  *error = (thread == nullptr) ? JDWP::ERR_THREAD_NOT_ALIVE : JDWP::ERR_NONE;
+  return thread;
 }
 
 static JDWP::JdwpTag BasicTagFromDescriptor(const char* descriptor) {
@@ -460,7 +462,7 @@
 
 static JDWP::JdwpTag TagFromClass(const ScopedObjectAccessUnchecked& soa, mirror::Class* c)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  CHECK(c != NULL);
+  CHECK(c != nullptr);
   if (c->IsArrayClass()) {
     return JDWP::JT_ARRAY;
   }
@@ -503,7 +505,7 @@
  */
 static JDWP::JdwpTag TagFromObject(const ScopedObjectAccessUnchecked& soa, mirror::Object* o)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return (o == NULL) ? JDWP::JT_OBJECT : TagFromClass(soa, o->GetClass());
+  return (o == nullptr) ? JDWP::JT_OBJECT : TagFromClass(soa, o->GetClass());
 }
 
 static bool IsPrimitiveTag(JDWP::JdwpTag tag) {
@@ -646,7 +648,7 @@
   // debugger, passively listen for a debugger, or block waiting for a
   // debugger.
   gJdwpState = JDWP::JdwpState::Create(&gJdwpOptions);
-  if (gJdwpState == NULL) {
+  if (gJdwpState == nullptr) {
     // We probably failed because some other process has the port already, which means that
     // if we don't abort the user is likely to think they're talking to us when they're actually
     // talking to that other process.
@@ -708,7 +710,7 @@
 }
 
 Thread* Dbg::GetDebugThread() {
-  return (gJdwpState != NULL) ? gJdwpState->GetDebugThread() : NULL;
+  return (gJdwpState != nullptr) ? gJdwpState->GetDebugThread() : nullptr;
 }
 
 void Dbg::ClearWaitForEventThread() {
@@ -826,12 +828,14 @@
 }
 
 std::string Dbg::GetClassName(JDWP::RefTypeId class_id) {
-  mirror::Object* o = gRegistry->Get<mirror::Object*>(class_id);
-  if (o == NULL) {
-    return "NULL";
-  }
-  if (o == ObjectRegistry::kInvalidObject) {
-    return StringPrintf("invalid object %p", reinterpret_cast<void*>(class_id));
+  JDWP::JdwpError error;
+  mirror::Object* o = gRegistry->Get<mirror::Object*>(class_id, &error);
+  if (o == nullptr) {
+    if (error == JDWP::ERR_NONE) {
+      return "NULL";
+    } else {
+      return StringPrintf("invalid object %p", reinterpret_cast<void*>(class_id));
+    }
   }
   if (!o->IsClass()) {
     return StringPrintf("non-class %p", o);  // This is only used for debugging output anyway.
@@ -840,34 +844,37 @@
   return DescriptorToName(o->AsClass()->GetDescriptor(&temp));
 }
 
-JDWP::JdwpError Dbg::GetClassObject(JDWP::RefTypeId id, JDWP::ObjectId& class_object_id) {
+JDWP::JdwpError Dbg::GetClassObject(JDWP::RefTypeId id, JDWP::ObjectId* class_object_id) {
   JDWP::JdwpError status;
-  mirror::Class* c = DecodeClass(id, status);
-  if (c == NULL) {
+  mirror::Class* c = DecodeClass(id, &status);
+  if (c == nullptr) {
+    *class_object_id = 0;
     return status;
   }
-  class_object_id = gRegistry->Add(c);
+  *class_object_id = gRegistry->Add(c);
   return JDWP::ERR_NONE;
 }
 
-JDWP::JdwpError Dbg::GetSuperclass(JDWP::RefTypeId id, JDWP::RefTypeId& superclass_id) {
+JDWP::JdwpError Dbg::GetSuperclass(JDWP::RefTypeId id, JDWP::RefTypeId* superclass_id) {
   JDWP::JdwpError status;
-  mirror::Class* c = DecodeClass(id, status);
-  if (c == NULL) {
+  mirror::Class* c = DecodeClass(id, &status);
+  if (c == nullptr) {
+    *superclass_id = 0;
     return status;
   }
   if (c->IsInterface()) {
     // http://code.google.com/p/android/issues/detail?id=20856
-    superclass_id = 0;
+    *superclass_id = 0;
   } else {
-    superclass_id = gRegistry->Add(c->GetSuperClass());
+    *superclass_id = gRegistry->Add(c->GetSuperClass());
   }
   return JDWP::ERR_NONE;
 }
 
 JDWP::JdwpError Dbg::GetClassLoader(JDWP::RefTypeId id, JDWP::ExpandBuf* pReply) {
-  mirror::Object* o = gRegistry->Get<mirror::Object*>(id);
-  if (o == NULL || o == ObjectRegistry::kInvalidObject) {
+  JDWP::JdwpError error;
+  mirror::Object* o = gRegistry->Get<mirror::Object*>(id, &error);
+  if (o == nullptr) {
     return JDWP::ERR_INVALID_OBJECT;
   }
   expandBufAddObjectId(pReply, gRegistry->Add(o->GetClass()->GetClassLoader()));
@@ -875,10 +882,10 @@
 }
 
 JDWP::JdwpError Dbg::GetModifiers(JDWP::RefTypeId id, JDWP::ExpandBuf* pReply) {
-  JDWP::JdwpError status;
-  mirror::Class* c = DecodeClass(id, status);
-  if (c == NULL) {
-    return status;
+  JDWP::JdwpError error;
+  mirror::Class* c = DecodeClass(id, &error);
+  if (c == nullptr) {
+    return error;
   }
 
   uint32_t access_flags = c->GetAccessFlags() & kAccJavaFlagsMask;
@@ -895,10 +902,10 @@
   return JDWP::ERR_NONE;
 }
 
-JDWP::JdwpError Dbg::GetMonitorInfo(JDWP::ObjectId object_id, JDWP::ExpandBuf* reply)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  mirror::Object* o = gRegistry->Get<mirror::Object*>(object_id);
-  if (o == NULL || o == ObjectRegistry::kInvalidObject) {
+JDWP::JdwpError Dbg::GetMonitorInfo(JDWP::ObjectId object_id, JDWP::ExpandBuf* reply) {
+  JDWP::JdwpError error;
+  mirror::Object* o = gRegistry->Get<mirror::Object*>(object_id, &error);
+  if (o == nullptr) {
     return JDWP::ERR_INVALID_OBJECT;
   }
 
@@ -913,10 +920,10 @@
   Runtime::Current()->GetThreadList()->ResumeAll();
   self->TransitionFromSuspendedToRunnable();
 
-  if (monitor_info.owner_ != NULL) {
+  if (monitor_info.owner_ != nullptr) {
     expandBufAddObjectId(reply, gRegistry->Add(monitor_info.owner_->GetPeer()));
   } else {
-    expandBufAddObjectId(reply, gRegistry->Add(NULL));
+    expandBufAddObjectId(reply, gRegistry->Add(nullptr));
   }
   expandBufAdd4BE(reply, monitor_info.entry_count_);
   expandBufAdd4BE(reply, monitor_info.waiters_.size());
@@ -927,8 +934,8 @@
 }
 
 JDWP::JdwpError Dbg::GetOwnedMonitors(JDWP::ObjectId thread_id,
-                                      std::vector<JDWP::ObjectId>& monitors,
-                                      std::vector<uint32_t>& stack_depths) {
+                                      std::vector<JDWP::ObjectId>* monitors,
+                                      std::vector<uint32_t>* stack_depths) {
   struct OwnedMonitorVisitor : public StackVisitor {
     OwnedMonitorVisitor(Thread* thread, Context* context,
                         std::vector<JDWP::ObjectId>* monitor_vector,
@@ -955,16 +962,17 @@
     }
 
     size_t current_stack_depth;
-    std::vector<JDWP::ObjectId>* monitors;
-    std::vector<uint32_t>* stack_depths;
+    std::vector<JDWP::ObjectId>* const monitors;
+    std::vector<uint32_t>* const stack_depths;
   };
 
   ScopedObjectAccessUnchecked soa(Thread::Current());
   Thread* thread;
   {
     MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
-    JDWP::JdwpError error = DecodeThread(soa, thread_id, thread);
-    if (error != JDWP::ERR_NONE) {
+    JDWP::JdwpError error;
+    thread = DecodeThread(soa, thread_id, &error);
+    if (thread == nullptr) {
       return error;
     }
     if (!IsSuspendedForDebugger(soa, thread)) {
@@ -972,20 +980,21 @@
     }
   }
   std::unique_ptr<Context> context(Context::Create());
-  OwnedMonitorVisitor visitor(thread, context.get(), &monitors, &stack_depths);
+  OwnedMonitorVisitor visitor(thread, context.get(), monitors, stack_depths);
   visitor.WalkStack();
   return JDWP::ERR_NONE;
 }
 
 JDWP::JdwpError Dbg::GetContendedMonitor(JDWP::ObjectId thread_id,
-                                         JDWP::ObjectId& contended_monitor) {
+                                         JDWP::ObjectId* contended_monitor) {
   mirror::Object* contended_monitor_obj;
   ScopedObjectAccessUnchecked soa(Thread::Current());
+  *contended_monitor = 0;
   {
     MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
-    Thread* thread;
-    JDWP::JdwpError error = DecodeThread(soa, thread_id, thread);
-    if (error != JDWP::ERR_NONE) {
+    JDWP::JdwpError error;
+    Thread* thread = DecodeThread(soa, thread_id, &error);
+    if (thread == nullptr) {
       return error;
     }
     if (!IsSuspendedForDebugger(soa, thread)) {
@@ -995,108 +1004,105 @@
   }
   // Add() requires the thread_list_lock_ not held to avoid the lock
   // level violation.
-  contended_monitor = gRegistry->Add(contended_monitor_obj);
+  *contended_monitor = gRegistry->Add(contended_monitor_obj);
   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<uint64_t>* counts) {
   gc::Heap* heap = Runtime::Current()->GetHeap();
   heap->CollectGarbage(false);
   std::vector<mirror::Class*> classes;
-  counts.clear();
+  counts->clear();
   for (size_t i = 0; i < class_ids.size(); ++i) {
-    JDWP::JdwpError status;
-    mirror::Class* c = DecodeClass(class_ids[i], status);
-    if (c == NULL) {
-      return status;
+    JDWP::JdwpError error;
+    mirror::Class* c = DecodeClass(class_ids[i], &error);
+    if (c == nullptr) {
+      return error;
     }
     classes.push_back(c);
-    counts.push_back(0);
+    counts->push_back(0);
   }
-  heap->CountInstances(classes, false, &counts[0]);
+  heap->CountInstances(classes, false, &(*counts)[0]);
   return JDWP::ERR_NONE;
 }
 
-JDWP::JdwpError Dbg::GetInstances(JDWP::RefTypeId class_id, int32_t max_count, std::vector<JDWP::ObjectId>& instances)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+JDWP::JdwpError Dbg::GetInstances(JDWP::RefTypeId class_id, int32_t max_count,
+                                  std::vector<JDWP::ObjectId>* instances) {
   gc::Heap* heap = Runtime::Current()->GetHeap();
   // We only want reachable instances, so do a GC.
   heap->CollectGarbage(false);
-  JDWP::JdwpError status;
-  mirror::Class* c = DecodeClass(class_id, status);
+  JDWP::JdwpError error;
+  mirror::Class* c = DecodeClass(class_id, &error);
   if (c == nullptr) {
-    return status;
+    return error;
   }
   std::vector<mirror::Object*> raw_instances;
   Runtime::Current()->GetHeap()->GetInstances(c, max_count, raw_instances);
   for (size_t i = 0; i < raw_instances.size(); ++i) {
-    instances.push_back(gRegistry->Add(raw_instances[i]));
+    instances->push_back(gRegistry->Add(raw_instances[i]));
   }
   return JDWP::ERR_NONE;
 }
 
 JDWP::JdwpError Dbg::GetReferringObjects(JDWP::ObjectId object_id, int32_t max_count,
-                                         std::vector<JDWP::ObjectId>& referring_objects)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+                                         std::vector<JDWP::ObjectId>* referring_objects) {
   gc::Heap* heap = Runtime::Current()->GetHeap();
   heap->CollectGarbage(false);
-  mirror::Object* o = gRegistry->Get<mirror::Object*>(object_id);
-  if (o == NULL || o == ObjectRegistry::kInvalidObject) {
+  JDWP::JdwpError error;
+  mirror::Object* o = gRegistry->Get<mirror::Object*>(object_id, &error);
+  if (o == nullptr) {
     return JDWP::ERR_INVALID_OBJECT;
   }
   std::vector<mirror::Object*> raw_instances;
   heap->GetReferringObjects(o, max_count, raw_instances);
   for (size_t i = 0; i < raw_instances.size(); ++i) {
-    referring_objects.push_back(gRegistry->Add(raw_instances[i]));
+    referring_objects->push_back(gRegistry->Add(raw_instances[i]));
   }
   return JDWP::ERR_NONE;
 }
 
-JDWP::JdwpError Dbg::DisableCollection(JDWP::ObjectId object_id)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  mirror::Object* o = gRegistry->Get<mirror::Object*>(object_id);
-  if (o == NULL || o == ObjectRegistry::kInvalidObject) {
+JDWP::JdwpError Dbg::DisableCollection(JDWP::ObjectId object_id) {
+  JDWP::JdwpError error;
+  mirror::Object* o = gRegistry->Get<mirror::Object*>(object_id, &error);
+  if (o == nullptr) {
     return JDWP::ERR_INVALID_OBJECT;
   }
   gRegistry->DisableCollection(object_id);
   return JDWP::ERR_NONE;
 }
 
-JDWP::JdwpError Dbg::EnableCollection(JDWP::ObjectId object_id)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  mirror::Object* o = gRegistry->Get<mirror::Object*>(object_id);
+JDWP::JdwpError Dbg::EnableCollection(JDWP::ObjectId object_id) {
+  JDWP::JdwpError error;
+  mirror::Object* o = gRegistry->Get<mirror::Object*>(object_id, &error);
   // Unlike DisableCollection, JDWP specs do not state an invalid object causes an error. The RI
   // also ignores these cases and never return an error. However it's not obvious why this command
   // should behave differently from DisableCollection and IsCollected commands. So let's be more
   // strict and return an error if this happens.
-  if (o == NULL || o == ObjectRegistry::kInvalidObject) {
+  if (o == nullptr) {
     return JDWP::ERR_INVALID_OBJECT;
   }
   gRegistry->EnableCollection(object_id);
   return JDWP::ERR_NONE;
 }
 
-JDWP::JdwpError Dbg::IsCollected(JDWP::ObjectId object_id, bool& is_collected)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+JDWP::JdwpError Dbg::IsCollected(JDWP::ObjectId object_id, bool* is_collected) {
+  *is_collected = true;
   if (object_id == 0) {
     // Null object id is invalid.
     return JDWP::ERR_INVALID_OBJECT;
   }
   // JDWP specs state an INVALID_OBJECT error is returned if the object ID is not valid. However
   // the RI seems to ignore this and assume object has been collected.
-  mirror::Object* o = gRegistry->Get<mirror::Object*>(object_id);
-  if (o == NULL || o == ObjectRegistry::kInvalidObject) {
-    is_collected = true;
-  } else {
-    is_collected = gRegistry->IsCollected(object_id);
+  JDWP::JdwpError error;
+  mirror::Object* o = gRegistry->Get<mirror::Object*>(object_id, &error);
+  if (o != nullptr) {
+    *is_collected = gRegistry->IsCollected(object_id);
   }
   return JDWP::ERR_NONE;
 }
 
-void Dbg::DisposeObject(JDWP::ObjectId object_id, uint32_t reference_count)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+void Dbg::DisposeObject(JDWP::ObjectId object_id, uint32_t reference_count) {
   gRegistry->DisposeObject(object_id, reference_count);
 }
 
@@ -1113,10 +1119,10 @@
 }
 
 JDWP::JdwpError Dbg::GetReflectedType(JDWP::RefTypeId class_id, JDWP::ExpandBuf* pReply) {
-  JDWP::JdwpError status;
-  mirror::Class* c = DecodeClass(class_id, status);
-  if (c == NULL) {
-    return status;
+  JDWP::JdwpError error;
+  mirror::Class* c = DecodeClass(class_id, &error);
+  if (c == nullptr) {
+    return error;
   }
 
   JDWP::JdwpTypeTag type_tag = GetTypeTag(c);
@@ -1125,12 +1131,12 @@
   return JDWP::ERR_NONE;
 }
 
-void Dbg::GetClassList(std::vector<JDWP::RefTypeId>& classes) {
+void Dbg::GetClassList(std::vector<JDWP::RefTypeId>* classes) {
   // Get the complete list of reference classes (i.e. all classes except
   // the primitive types).
   // Returns a newly-allocated buffer full of RefTypeId values.
   struct ClassListCreator {
-    explicit ClassListCreator(std::vector<JDWP::RefTypeId>& classes) : classes(classes) {
+    explicit ClassListCreator(std::vector<JDWP::RefTypeId>* classes) : classes(classes) {
     }
 
     static bool Visit(mirror::Class* c, void* arg) {
@@ -1141,12 +1147,12 @@
     // annotalysis.
     bool Visit(mirror::Class* c) NO_THREAD_SAFETY_ANALYSIS {
       if (!c->IsPrimitive()) {
-        classes.push_back(gRegistry->AddRefType(c));
+        classes->push_back(gRegistry->AddRefType(c));
       }
       return true;
     }
 
-    std::vector<JDWP::RefTypeId>& classes;
+    std::vector<JDWP::RefTypeId>* const classes;
   };
 
   ClassListCreator clc(classes);
@@ -1155,10 +1161,10 @@
 
 JDWP::JdwpError Dbg::GetClassInfo(JDWP::RefTypeId class_id, JDWP::JdwpTypeTag* pTypeTag,
                                   uint32_t* pStatus, std::string* pDescriptor) {
-  JDWP::JdwpError status;
-  mirror::Class* c = DecodeClass(class_id, status);
-  if (c == NULL) {
-    return status;
+  JDWP::JdwpError error;
+  mirror::Class* c = DecodeClass(class_id, &error);
+  if (c == nullptr) {
+    return error;
   }
 
   if (c->IsArrayClass()) {
@@ -1173,26 +1179,26 @@
     *pTypeTag = c->IsInterface() ? JDWP::TT_INTERFACE : JDWP::TT_CLASS;
   }
 
-  if (pDescriptor != NULL) {
+  if (pDescriptor != nullptr) {
     std::string temp;
     *pDescriptor = c->GetDescriptor(&temp);
   }
   return JDWP::ERR_NONE;
 }
 
-void Dbg::FindLoadedClassBySignature(const char* descriptor, std::vector<JDWP::RefTypeId>& ids) {
+void Dbg::FindLoadedClassBySignature(const char* descriptor, std::vector<JDWP::RefTypeId>* ids) {
   std::vector<mirror::Class*> classes;
   Runtime::Current()->GetClassLinker()->LookupClasses(descriptor, classes);
-  ids.clear();
+  ids->clear();
   for (size_t i = 0; i < classes.size(); ++i) {
-    ids.push_back(gRegistry->Add(classes[i]));
+    ids->push_back(gRegistry->Add(classes[i]));
   }
 }
 
-JDWP::JdwpError Dbg::GetReferenceType(JDWP::ObjectId object_id, JDWP::ExpandBuf* pReply)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  mirror::Object* o = gRegistry->Get<mirror::Object*>(object_id);
-  if (o == NULL || o == ObjectRegistry::kInvalidObject) {
+JDWP::JdwpError Dbg::GetReferenceType(JDWP::ObjectId object_id, JDWP::ExpandBuf* pReply) {
+  JDWP::JdwpError error;
+  mirror::Object* o = gRegistry->Get<mirror::Object*>(object_id, &error);
+  if (o == nullptr) {
     return JDWP::ERR_INVALID_OBJECT;
   }
 
@@ -1206,37 +1212,39 @@
 }
 
 JDWP::JdwpError Dbg::GetSignature(JDWP::RefTypeId class_id, std::string* signature) {
-  JDWP::JdwpError status;
-  mirror::Class* c = DecodeClass(class_id, status);
-  if (c == NULL) {
-    return status;
+  JDWP::JdwpError error;
+  mirror::Class* c = DecodeClass(class_id, &error);
+  if (c == nullptr) {
+    return error;
   }
   std::string temp;
   *signature = c->GetDescriptor(&temp);
   return JDWP::ERR_NONE;
 }
 
-JDWP::JdwpError Dbg::GetSourceFile(JDWP::RefTypeId class_id, std::string& result) {
-  JDWP::JdwpError status;
-  mirror::Class* c = DecodeClass(class_id, status);
+JDWP::JdwpError Dbg::GetSourceFile(JDWP::RefTypeId class_id, std::string* result) {
+  JDWP::JdwpError error;
+  mirror::Class* c = DecodeClass(class_id, &error);
   if (c == nullptr) {
-    return status;
+    return error;
   }
   const char* source_file = c->GetSourceFile();
   if (source_file == nullptr) {
     return JDWP::ERR_ABSENT_INFORMATION;
   }
-  result = source_file;
+  *result = source_file;
   return JDWP::ERR_NONE;
 }
 
-JDWP::JdwpError Dbg::GetObjectTag(JDWP::ObjectId object_id, uint8_t& tag) {
+JDWP::JdwpError Dbg::GetObjectTag(JDWP::ObjectId object_id, uint8_t* tag) {
   ScopedObjectAccessUnchecked soa(Thread::Current());
-  mirror::Object* o = gRegistry->Get<mirror::Object*>(object_id);
-  if (o == ObjectRegistry::kInvalidObject) {
-    return JDWP::ERR_INVALID_OBJECT;
+  JDWP::JdwpError error;
+  mirror::Object* o = gRegistry->Get<mirror::Object*>(object_id, &error);
+  if (error != JDWP::ERR_NONE) {
+    *tag = JDWP::JT_VOID;
+    return error;
   }
-  tag = TagFromObject(soa, o);
+  *tag = TagFromObject(soa, o);
   return JDWP::ERR_NONE;
 }
 
@@ -1270,21 +1278,21 @@
   }
 }
 
-JDWP::JdwpError Dbg::GetArrayLength(JDWP::ObjectId array_id, int& length) {
-  JDWP::JdwpError status;
-  mirror::Array* a = DecodeArray(array_id, status);
-  if (a == NULL) {
-    return status;
+JDWP::JdwpError Dbg::GetArrayLength(JDWP::ObjectId array_id, int32_t* length) {
+  JDWP::JdwpError error;
+  mirror::Array* a = DecodeNonNullArray(array_id, &error);
+  if (a == nullptr) {
+    return error;
   }
-  length = a->GetLength();
+  *length = a->GetLength();
   return JDWP::ERR_NONE;
 }
 
 JDWP::JdwpError Dbg::OutputArray(JDWP::ObjectId array_id, int offset, int count, JDWP::ExpandBuf* pReply) {
-  JDWP::JdwpError status;
-  mirror::Array* a = DecodeArray(array_id, status);
+  JDWP::JdwpError error;
+  mirror::Array* a = DecodeNonNullArray(array_id, &error);
   if (a == nullptr) {
-    return status;
+    return error;
   }
 
   if (offset < 0 || count < 0 || offset > a->GetLength() || a->GetLength() - offset < count) {
@@ -1327,24 +1335,23 @@
 }
 
 template <typename T>
-static void CopyArrayData(mirror::Array* a, JDWP::Request& src, int offset, int count)
+static void CopyArrayData(mirror::Array* a, JDWP::Request* src, int offset, int count)
     NO_THREAD_SAFETY_ANALYSIS {
   // TODO: fix when annotalysis correctly handles non-member functions.
   DCHECK(a->GetClass()->IsPrimitiveArray());
 
   T* dst = reinterpret_cast<T*>(a->GetRawData(sizeof(T), offset));
   for (int i = 0; i < count; ++i) {
-    *dst++ = src.ReadValue(sizeof(T));
+    *dst++ = src->ReadValue(sizeof(T));
   }
 }
 
 JDWP::JdwpError Dbg::SetArrayElements(JDWP::ObjectId array_id, int offset, int count,
-                                      JDWP::Request& request)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  JDWP::JdwpError status;
-  mirror::Array* dst = DecodeArray(array_id, status);
-  if (dst == NULL) {
-    return status;
+                                      JDWP::Request* request) {
+  JDWP::JdwpError error;
+  mirror::Array* dst = DecodeNonNullArray(array_id, &error);
+  if (dst == nullptr) {
+    return error;
   }
 
   if (offset < 0 || count < 0 || offset > dst->GetLength() || dst->GetLength() - offset < count) {
@@ -1367,10 +1374,11 @@
   } else {
     mirror::ObjectArray<mirror::Object>* oa = dst->AsObjectArray<mirror::Object>();
     for (int i = 0; i < count; ++i) {
-      JDWP::ObjectId id = request.ReadObjectId();
-      mirror::Object* o = gRegistry->Get<mirror::Object*>(id);
-      if (o == ObjectRegistry::kInvalidObject) {
-        return JDWP::ERR_INVALID_OBJECT;
+      JDWP::ObjectId id = request->ReadObjectId();
+      JDWP::JdwpError error;
+      mirror::Object* o = gRegistry->Get<mirror::Object*>(id, &error);
+      if (error != JDWP::ERR_NONE) {
+        return error;
       }
       oa->Set<false>(offset + i, o);
     }
@@ -1383,13 +1391,14 @@
   return gRegistry->Add(mirror::String::AllocFromModifiedUtf8(Thread::Current(), str.c_str()));
 }
 
-JDWP::JdwpError Dbg::CreateObject(JDWP::RefTypeId class_id, JDWP::ObjectId& new_object) {
-  JDWP::JdwpError status;
-  mirror::Class* c = DecodeClass(class_id, status);
-  if (c == NULL) {
-    return status;
+JDWP::JdwpError Dbg::CreateObject(JDWP::RefTypeId class_id, JDWP::ObjectId* new_object) {
+  JDWP::JdwpError error;
+  mirror::Class* c = DecodeClass(class_id, &error);
+  if (c == nullptr) {
+    *new_object = 0;
+    return error;
   }
-  new_object = gRegistry->Add(c->AllocObject(Thread::Current()));
+  *new_object = gRegistry->Add(c->AllocObject(Thread::Current()));
   return JDWP::ERR_NONE;
 }
 
@@ -1397,24 +1406,25 @@
  * Used by Eclipse's "Display" view to evaluate "new byte[5]" to get "(byte[]) [0, 0, 0, 0, 0]".
  */
 JDWP::JdwpError Dbg::CreateArrayObject(JDWP::RefTypeId array_class_id, uint32_t length,
-                                       JDWP::ObjectId& new_array) {
-  JDWP::JdwpError status;
-  mirror::Class* c = DecodeClass(array_class_id, status);
-  if (c == NULL) {
-    return status;
+                                       JDWP::ObjectId* new_array) {
+  JDWP::JdwpError error;
+  mirror::Class* c = DecodeClass(array_class_id, &error);
+  if (c == nullptr) {
+    *new_array = 0;
+    return error;
   }
-  new_array = gRegistry->Add(mirror::Array::Alloc<true>(Thread::Current(), c, length,
-                                                        c->GetComponentSize(),
-                                                        Runtime::Current()->GetHeap()->GetCurrentAllocator()));
+  *new_array = gRegistry->Add(mirror::Array::Alloc<true>(Thread::Current(), c, length,
+                                                         c->GetComponentSize(),
+                                                         Runtime::Current()->GetHeap()->GetCurrentAllocator()));
   return JDWP::ERR_NONE;
 }
 
 bool Dbg::MatchType(JDWP::RefTypeId instance_class_id, JDWP::RefTypeId class_id) {
-  JDWP::JdwpError status;
-  mirror::Class* c1 = DecodeClass(instance_class_id, status);
-  CHECK(c1 != NULL);
-  mirror::Class* c2 = DecodeClass(class_id, status);
-  CHECK(c2 != NULL);
+  JDWP::JdwpError error;
+  mirror::Class* c1 = DecodeClass(instance_class_id, &error);
+  CHECK(c1 != nullptr);
+  mirror::Class* c2 = DecodeClass(class_id, &error);
+  CHECK(c2 != nullptr);
   return c2->IsAssignableFrom(c1);
 }
 
@@ -1442,27 +1452,25 @@
   return reinterpret_cast<mirror::ArtMethod*>(static_cast<uintptr_t>(mid));
 }
 
-static void SetLocation(JDWP::JdwpLocation& location, mirror::ArtMethod* m, uint32_t dex_pc)
+static void SetLocation(JDWP::JdwpLocation* location, mirror::ArtMethod* m, uint32_t dex_pc)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  if (m == NULL) {
+  if (m == nullptr) {
     memset(&location, 0, sizeof(location));
   } else {
     mirror::Class* c = m->GetDeclaringClass();
-    location.type_tag = GetTypeTag(c);
-    location.class_id = gRegistry->AddRefType(c);
-    location.method_id = ToMethodId(m);
-    location.dex_pc = (m->IsNative() || m->IsProxyMethod()) ? static_cast<uint64_t>(-1) : dex_pc;
+    location->type_tag = GetTypeTag(c);
+    location->class_id = gRegistry->AddRefType(c);
+    location->method_id = ToMethodId(m);
+    location->dex_pc = (m->IsNative() || m->IsProxyMethod()) ? static_cast<uint64_t>(-1) : dex_pc;
   }
 }
 
-std::string Dbg::GetMethodName(JDWP::MethodId method_id)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+std::string Dbg::GetMethodName(JDWP::MethodId method_id) {
   mirror::ArtMethod* m = FromMethodId(method_id);
   return m->GetName();
 }
 
-std::string Dbg::GetFieldName(JDWP::FieldId field_id)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+std::string Dbg::GetFieldName(JDWP::FieldId field_id) {
   return FromFieldId(field_id)->GetName();
 }
 
@@ -1525,10 +1533,10 @@
 }
 
 JDWP::JdwpError Dbg::OutputDeclaredFields(JDWP::RefTypeId class_id, bool with_generic, JDWP::ExpandBuf* pReply) {
-  JDWP::JdwpError status;
-  mirror::Class* c = DecodeClass(class_id, status);
-  if (c == NULL) {
-    return status;
+  JDWP::JdwpError error;
+  mirror::Class* c = DecodeClass(class_id, &error);
+  if (c == nullptr) {
+    return error;
   }
 
   size_t instance_field_count = c->NumInstanceFields();
@@ -1552,10 +1560,10 @@
 
 JDWP::JdwpError Dbg::OutputDeclaredMethods(JDWP::RefTypeId class_id, bool with_generic,
                                            JDWP::ExpandBuf* pReply) {
-  JDWP::JdwpError status;
-  mirror::Class* c = DecodeClass(class_id, status);
-  if (c == NULL) {
-    return status;
+  JDWP::JdwpError error;
+  mirror::Class* c = DecodeClass(class_id, &error);
+  if (c == nullptr) {
+    return error;
   }
 
   size_t direct_method_count = c->NumDirectMethods();
@@ -1578,12 +1586,12 @@
 }
 
 JDWP::JdwpError Dbg::OutputDeclaredInterfaces(JDWP::RefTypeId class_id, JDWP::ExpandBuf* pReply) {
-  JDWP::JdwpError status;
+  JDWP::JdwpError error;
   Thread* self = Thread::Current();
   StackHandleScope<1> hs(self);
-  Handle<mirror::Class> c(hs.NewHandle(DecodeClass(class_id, status)));
+  Handle<mirror::Class> c(hs.NewHandle(DecodeClass(class_id, &error)));
   if (c.Get() == nullptr) {
-    return status;
+    return error;
   }
   size_t interface_count = c->NumDirectInterfaces();
   expandBufAdd4BE(pReply, interface_count);
@@ -1594,8 +1602,7 @@
   return JDWP::ERR_NONE;
 }
 
-void Dbg::OutputLineTable(JDWP::RefTypeId, JDWP::MethodId method_id, JDWP::ExpandBuf* pReply)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+void Dbg::OutputLineTable(JDWP::RefTypeId, JDWP::MethodId method_id, JDWP::ExpandBuf* pReply) {
   struct DebugCallbackContext {
     int numItems;
     JDWP::ExpandBuf* pReply;
@@ -1634,7 +1641,7 @@
 
   if (code_item != nullptr) {
     m->GetDexFile()->DecodeDebugInfo(code_item, m->IsStatic(), m->GetDexMethodIndex(),
-                                     DebugCallbackContext::Callback, NULL, &context);
+                                     DebugCallbackContext::Callback, nullptr, &context);
   }
 
   JDWP::Set4BE(expandBufGetBuffer(pReply) + numLinesOffset, context.numItems);
@@ -1692,7 +1699,7 @@
   const DexFile::CodeItem* code_item = m->GetCodeItem();
   if (code_item != nullptr) {
     m->GetDexFile()->DecodeDebugInfo(
-        code_item, m->IsStatic(), m->GetDexMethodIndex(), NULL, DebugCallbackContext::Callback,
+        code_item, m->IsStatic(), m->GetDexMethodIndex(), nullptr, DebugCallbackContext::Callback,
         &context);
   }
 
@@ -1714,10 +1721,9 @@
 }
 
 JDWP::JdwpError Dbg::GetBytecodes(JDWP::RefTypeId, JDWP::MethodId method_id,
-                                  std::vector<uint8_t>& bytecodes)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+                                  std::vector<uint8_t>* bytecodes) {
   mirror::ArtMethod* m = FromMethodId(method_id);
-  if (m == NULL) {
+  if (m == nullptr) {
     return JDWP::ERR_INVALID_METHODID;
   }
   const DexFile::CodeItem* code_item = m->GetCodeItem();
@@ -1725,7 +1731,7 @@
   const uint8_t* begin = reinterpret_cast<const uint8_t*>(code_item->insns_);
   const uint8_t* end = begin + byte_count;
   for (const uint8_t* p = begin; p != end; ++p) {
-    bytecodes.push_back(*p);
+    bytecodes->push_back(*p);
   }
   return JDWP::ERR_NONE;
 }
@@ -1742,24 +1748,24 @@
                                          JDWP::FieldId field_id, JDWP::ExpandBuf* pReply,
                                          bool is_static)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  JDWP::JdwpError status;
-  mirror::Class* c = DecodeClass(ref_type_id, status);
-  if (ref_type_id != 0 && c == NULL) {
-    return status;
+  JDWP::JdwpError error;
+  mirror::Class* c = DecodeClass(ref_type_id, &error);
+  if (ref_type_id != 0 && c == nullptr) {
+    return error;
   }
 
-  mirror::Object* o = gRegistry->Get<mirror::Object*>(object_id);
-  if ((!is_static && o == NULL) || o == ObjectRegistry::kInvalidObject) {
+  mirror::Object* o = gRegistry->Get<mirror::Object*>(object_id, &error);
+  if ((!is_static && o == nullptr) || error != JDWP::ERR_NONE) {
     return JDWP::ERR_INVALID_OBJECT;
   }
   mirror::ArtField* f = FromFieldId(field_id);
 
   mirror::Class* receiver_class = c;
-  if (receiver_class == NULL && o != NULL) {
+  if (receiver_class == nullptr && o != nullptr) {
     receiver_class = o->GetClass();
   }
-  // TODO: should we give up now if receiver_class is NULL?
-  if (receiver_class != NULL && !f->GetDeclaringClass()->IsAssignableFrom(receiver_class)) {
+  // TODO: should we give up now if receiver_class is nullptr?
+  if (receiver_class != nullptr && !f->GetDeclaringClass()->IsAssignableFrom(receiver_class)) {
     LOG(INFO) << "ERR_INVALID_FIELDID: " << PrettyField(f) << " " << PrettyClass(receiver_class);
     return JDWP::ERR_INVALID_FIELDID;
   }
@@ -1772,7 +1778,8 @@
     }
   } else {
     if (f->IsStatic()) {
-      LOG(WARNING) << "Ignoring non-NULL receiver for ObjectReference.SetValues on static field " << PrettyField(f);
+      LOG(WARNING) << "Ignoring non-nullptr receiver for ObjectReference.SetValues on static field "
+          << PrettyField(f);
     }
   }
   if (f->IsStatic()) {
@@ -1800,15 +1807,17 @@
   return GetFieldValueImpl(0, object_id, field_id, pReply, false);
 }
 
-JDWP::JdwpError Dbg::GetStaticFieldValue(JDWP::RefTypeId ref_type_id, JDWP::FieldId field_id, JDWP::ExpandBuf* pReply) {
+JDWP::JdwpError Dbg::GetStaticFieldValue(JDWP::RefTypeId ref_type_id, JDWP::FieldId field_id,
+                                         JDWP::ExpandBuf* pReply) {
   return GetFieldValueImpl(ref_type_id, 0, field_id, pReply, true);
 }
 
 static JDWP::JdwpError SetFieldValueImpl(JDWP::ObjectId object_id, JDWP::FieldId field_id,
                                          uint64_t value, int width, bool is_static)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  mirror::Object* o = gRegistry->Get<mirror::Object*>(object_id);
-  if ((!is_static && o == NULL) || o == ObjectRegistry::kInvalidObject) {
+  JDWP::JdwpError error;
+  mirror::Object* o = gRegistry->Get<mirror::Object*>(object_id, &error);
+  if ((!is_static && o == nullptr) || error != JDWP::ERR_NONE) {
     return JDWP::ERR_INVALID_OBJECT;
   }
   mirror::ArtField* f = FromFieldId(field_id);
@@ -1821,7 +1830,7 @@
     }
   } else {
     if (f->IsStatic()) {
-      LOG(WARNING) << "Ignoring non-NULL receiver for ObjectReference.SetValues on static field " << PrettyField(f);
+      LOG(WARNING) << "Ignoring non-nullptr receiver for ObjectReference.SetValues on static field " << PrettyField(f);
     }
   }
   if (f->IsStatic()) {
@@ -1841,11 +1850,11 @@
       f->Set32<false>(o, value);
     }
   } else {
-    mirror::Object* v = gRegistry->Get<mirror::Object*>(value);
-    if (v == ObjectRegistry::kInvalidObject) {
+    mirror::Object* v = gRegistry->Get<mirror::Object*>(value, &error);
+    if (error != JDWP::ERR_NONE) {
       return JDWP::ERR_INVALID_OBJECT;
     }
-    if (v != NULL) {
+    if (v != nullptr) {
       mirror::Class* field_type;
       {
         StackHandleScope<3> hs(Thread::Current());
@@ -1875,7 +1884,9 @@
 }
 
 std::string Dbg::StringToUtf8(JDWP::ObjectId string_id) {
-  mirror::String* s = gRegistry->Get<mirror::String*>(string_id);
+  JDWP::JdwpError error;
+  mirror::String* s = gRegistry->Get<mirror::String*>(string_id, &error);
+  CHECK(s != nullptr) << error;
   return s->ToModifiedUtf8();
 }
 
@@ -1901,40 +1912,42 @@
   }
 }
 
-JDWP::JdwpError Dbg::GetThreadName(JDWP::ObjectId thread_id, std::string& name) {
+JDWP::JdwpError Dbg::GetThreadName(JDWP::ObjectId thread_id, std::string* name) {
   ScopedObjectAccessUnchecked soa(Thread::Current());
   MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
-  Thread* thread;
-  JDWP::JdwpError error = DecodeThread(soa, thread_id, thread);
+  JDWP::JdwpError error;
+  Thread* thread = DecodeThread(soa, thread_id, &error);
+  UNUSED(thread);
   if (error != JDWP::ERR_NONE && error != JDWP::ERR_THREAD_NOT_ALIVE) {
     return error;
   }
 
   // We still need to report the zombie threads' names, so we can't just call Thread::GetThreadName.
-  mirror::Object* thread_object = gRegistry->Get<mirror::Object*>(thread_id);
+  mirror::Object* thread_object = gRegistry->Get<mirror::Object*>(thread_id, &error);
+  CHECK(thread_object != nullptr) << error;
   mirror::ArtField* java_lang_Thread_name_field =
       soa.DecodeField(WellKnownClasses::java_lang_Thread_name);
   mirror::String* s =
       reinterpret_cast<mirror::String*>(java_lang_Thread_name_field->GetObject(thread_object));
-  if (s != NULL) {
-    name = s->ToModifiedUtf8();
+  if (s != nullptr) {
+    *name = s->ToModifiedUtf8();
   }
   return JDWP::ERR_NONE;
 }
 
 JDWP::JdwpError Dbg::GetThreadGroup(JDWP::ObjectId thread_id, JDWP::ExpandBuf* pReply) {
   ScopedObjectAccess soa(Thread::Current());
-  mirror::Object* thread_object = gRegistry->Get<mirror::Object*>(thread_id);
-  if (thread_object == ObjectRegistry::kInvalidObject) {
+  JDWP::JdwpError error;
+  mirror::Object* thread_object = gRegistry->Get<mirror::Object*>(thread_id, &error);
+  if (error != JDWP::ERR_NONE) {
     return JDWP::ERR_INVALID_OBJECT;
   }
   const char* old_cause = soa.Self()->StartAssertNoThreadSuspension("Debugger: GetThreadGroup");
   // Okay, so it's an object, but is it actually a thread?
-  JDWP::JdwpError error;
   {
     MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
-    Thread* thread;
-    error = DecodeThread(soa, thread_id, thread);
+    Thread* thread = DecodeThread(soa, thread_id, &error);
+    UNUSED(thread);
   }
   if (error == JDWP::ERR_THREAD_NOT_ALIVE) {
     // Zombie threads are in the null group.
@@ -1956,13 +1969,14 @@
 
 std::string Dbg::GetThreadGroupName(JDWP::ObjectId thread_group_id) {
   ScopedObjectAccess soa(Thread::Current());
-  mirror::Object* thread_group = gRegistry->Get<mirror::Object*>(thread_group_id);
-  CHECK(thread_group != nullptr);
+  JDWP::JdwpError error;
+  mirror::Object* thread_group = gRegistry->Get<mirror::Object*>(thread_group_id, &error);
+  CHECK(thread_group != nullptr) << error;
   const char* old_cause = soa.Self()->StartAssertNoThreadSuspension("Debugger: GetThreadGroupName");
   mirror::Class* c = soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_ThreadGroup);
   CHECK(c != nullptr);
   mirror::ArtField* f = c->FindInstanceField("name", "Ljava/lang/String;");
-  CHECK(f != NULL);
+  CHECK(f != nullptr);
   mirror::String* s = reinterpret_cast<mirror::String*>(f->GetObject(thread_group));
   soa.Self()->EndAssertNoThreadSuspension(old_cause);
   return s->ToModifiedUtf8();
@@ -1970,13 +1984,14 @@
 
 JDWP::ObjectId Dbg::GetThreadGroupParent(JDWP::ObjectId thread_group_id) {
   ScopedObjectAccessUnchecked soa(Thread::Current());
-  mirror::Object* thread_group = gRegistry->Get<mirror::Object*>(thread_group_id);
-  CHECK(thread_group != nullptr);
+  JDWP::JdwpError error;
+  mirror::Object* thread_group = gRegistry->Get<mirror::Object*>(thread_group_id, &error);
+  CHECK(thread_group != nullptr) << error;
   const char* old_cause = soa.Self()->StartAssertNoThreadSuspension("Debugger: GetThreadGroupParent");
   mirror::Class* c = soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_ThreadGroup);
   CHECK(c != nullptr);
   mirror::ArtField* f = c->FindInstanceField("parent", "Ljava/lang/ThreadGroup;");
-  CHECK(f != NULL);
+  CHECK(f != nullptr);
   mirror::Object* parent = f->GetObject(thread_group);
   soa.Self()->EndAssertNoThreadSuspension(old_cause);
   return gRegistry->Add(parent);
@@ -2037,8 +2052,8 @@
   *pSuspendStatus = JDWP::SUSPEND_STATUS_NOT_SUSPENDED;
 
   MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
-  Thread* thread;
-  JDWP::JdwpError error = DecodeThread(soa, thread_id, thread);
+  JDWP::JdwpError error;
+  Thread* thread = DecodeThread(soa, thread_id, &error);
   if (error != JDWP::ERR_NONE) {
     if (error == JDWP::ERR_THREAD_NOT_ALIVE) {
       *pThreadStatus = JDWP::TS_ZOMBIE;
@@ -2058,8 +2073,8 @@
 JDWP::JdwpError Dbg::GetThreadDebugSuspendCount(JDWP::ObjectId thread_id, JDWP::ExpandBuf* pReply) {
   ScopedObjectAccess soa(Thread::Current());
   MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
-  Thread* thread;
-  JDWP::JdwpError error = DecodeThread(soa, thread_id, thread);
+  JDWP::JdwpError error;
+  Thread* thread = DecodeThread(soa, thread_id, &error);
   if (error != JDWP::ERR_NONE) {
     return error;
   }
@@ -2071,8 +2086,8 @@
 JDWP::JdwpError Dbg::Interrupt(JDWP::ObjectId thread_id) {
   ScopedObjectAccess soa(Thread::Current());
   MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
-  Thread* thread;
-  JDWP::JdwpError error = DecodeThread(soa, thread_id, thread);
+  JDWP::JdwpError error;
+  Thread* thread = DecodeThread(soa, thread_id, &error);
   if (error != JDWP::ERR_NONE) {
     return error;
   }
@@ -2080,11 +2095,11 @@
   return JDWP::ERR_NONE;
 }
 
-void Dbg::GetThreads(JDWP::ObjectId thread_group_id, std::vector<JDWP::ObjectId>& thread_ids) {
+void Dbg::GetThreads(JDWP::ObjectId thread_group_id, std::vector<JDWP::ObjectId>* thread_ids) {
   class ThreadListVisitor {
    public:
     ThreadListVisitor(const ScopedObjectAccessUnchecked& soa, mirror::Object* desired_thread_group,
-                      std::vector<JDWP::ObjectId>& thread_ids)
+                      std::vector<JDWP::ObjectId>* thread_ids)
         SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
         : soa_(soa), desired_thread_group_(desired_thread_group), thread_ids_(thread_ids) {}
 
@@ -2107,15 +2122,15 @@
       }
       mirror::Object* peer = t->GetPeer();
       if (IsInDesiredThreadGroup(peer)) {
-        thread_ids_.push_back(gRegistry->Add(peer));
+        thread_ids_->push_back(gRegistry->Add(peer));
       }
     }
 
    private:
     bool IsInDesiredThreadGroup(mirror::Object* peer)
         SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-      // peer might be NULL if the thread is still starting up.
-      if (peer == NULL) {
+      // peer might be nullptr if the thread is still starting up.
+      if (peer == nullptr) {
         // We can't tell the debugger about this thread yet.
         // TODO: if we identified threads to the debugger by their Thread*
         // rather than their peer's mirror::Object*, we could fix this.
@@ -2123,7 +2138,7 @@
         return false;
       }
       // Do we want threads from all thread groups?
-      if (desired_thread_group_ == NULL) {
+      if (desired_thread_group_ == nullptr) {
         return true;
       }
       mirror::Object* group = soa_.DecodeField(WellKnownClasses::java_lang_Thread_group)->GetObject(peer);
@@ -2132,19 +2147,24 @@
 
     const ScopedObjectAccessUnchecked& soa_;
     mirror::Object* const desired_thread_group_;
-    std::vector<JDWP::ObjectId>& thread_ids_;
+    std::vector<JDWP::ObjectId>* const thread_ids_;
   };
 
   ScopedObjectAccessUnchecked soa(Thread::Current());
-  mirror::Object* thread_group = gRegistry->Get<mirror::Object*>(thread_group_id);
+  JDWP::JdwpError error;
+  mirror::Object* thread_group = gRegistry->Get<mirror::Object*>(thread_group_id, &error);
+  CHECK_EQ(error, JDWP::ERR_NONE);
   ThreadListVisitor tlv(soa, thread_group, thread_ids);
   MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
   Runtime::Current()->GetThreadList()->ForEach(ThreadListVisitor::Visit, &tlv);
 }
 
-void Dbg::GetChildThreadGroups(JDWP::ObjectId thread_group_id, std::vector<JDWP::ObjectId>& child_thread_group_ids) {
+void Dbg::GetChildThreadGroups(JDWP::ObjectId thread_group_id,
+                               std::vector<JDWP::ObjectId>* child_thread_group_ids) {
   ScopedObjectAccess soa(Thread::Current());
-  mirror::Object* thread_group = gRegistry->Get<mirror::Object*>(thread_group_id);
+  JDWP::JdwpError error;
+  mirror::Object* thread_group = gRegistry->Get<mirror::Object*>(thread_group_id, &error);
+  CHECK(thread_group != nullptr) << error;
 
   // Get the ArrayList<ThreadGroup> "groups" out of this thread group...
   mirror::ArtField* groups_field = thread_group->GetClass()->FindInstanceField("groups", "Ljava/util/List;");
@@ -2159,15 +2179,14 @@
 
   // Copy the first 'size' elements out of the array into the result.
   for (int32_t i = 0; i < size; ++i) {
-    child_thread_group_ids.push_back(gRegistry->Add(groups_array->Get(i)));
+    child_thread_group_ids->push_back(gRegistry->Add(groups_array->Get(i)));
   }
 }
 
-static int GetStackDepth(Thread* thread)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+static int GetStackDepth(Thread* thread) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   struct CountStackDepthVisitor : public StackVisitor {
     explicit CountStackDepthVisitor(Thread* thread)
-        : StackVisitor(thread, NULL), depth(0) {}
+        : StackVisitor(thread, nullptr), depth(0) {}
 
     // TODO: Enable annotalysis. We know lock is held in constructor, but abstraction confuses
     // annotalysis.
@@ -2185,18 +2204,19 @@
   return visitor.depth;
 }
 
-JDWP::JdwpError Dbg::GetThreadFrameCount(JDWP::ObjectId thread_id, size_t& result) {
+JDWP::JdwpError Dbg::GetThreadFrameCount(JDWP::ObjectId thread_id, size_t* result) {
   ScopedObjectAccess soa(Thread::Current());
   MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
-  Thread* thread;
-  JDWP::JdwpError error = DecodeThread(soa, thread_id, thread);
+  JDWP::JdwpError error;
+  *result = 0;
+  Thread* thread = DecodeThread(soa, thread_id, &error);
   if (error != JDWP::ERR_NONE) {
     return error;
   }
   if (!IsSuspendedForDebugger(soa, thread)) {
     return JDWP::ERR_THREAD_NOT_SUSPENDED;
   }
-  result = GetStackDepth(thread);
+  *result = GetStackDepth(thread);
   return JDWP::ERR_NONE;
 }
 
@@ -2206,7 +2226,7 @@
    public:
     GetFrameVisitor(Thread* thread, size_t start_frame, size_t frame_count, JDWP::ExpandBuf* buf)
         SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-        : StackVisitor(thread, NULL), depth_(0),
+        : StackVisitor(thread, nullptr), depth_(0),
           start_frame_(start_frame), frame_count_(frame_count), buf_(buf) {
       expandBufAdd4BE(buf_, frame_count_);
     }
@@ -2223,7 +2243,7 @@
       if (depth_ >= start_frame_) {
         JDWP::FrameId frame_id(GetFrameId());
         JDWP::JdwpLocation location;
-        SetLocation(location, GetMethod(), GetDexPc());
+        SetLocation(&location, GetMethod(), GetDexPc());
         VLOG(jdwp) << StringPrintf("    Frame %3zd: id=%3" PRIu64 " ", depth_, frame_id) << location;
         expandBufAdd8BE(buf_, frame_id);
         expandBufAddLocation(buf_, location);
@@ -2241,8 +2261,8 @@
 
   ScopedObjectAccessUnchecked soa(Thread::Current());
   MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
-  Thread* thread;
-  JDWP::JdwpError error = DecodeThread(soa, thread_id, thread);
+  JDWP::JdwpError error;
+  Thread* thread = DecodeThread(soa, thread_id, &error);
   if (error != JDWP::ERR_NONE) {
     return error;
   }
@@ -2269,12 +2289,13 @@
 
 JDWP::JdwpError Dbg::SuspendThread(JDWP::ObjectId thread_id, bool request_suspension) {
   Thread* self = Thread::Current();
-  ScopedLocalRef<jobject> peer(self->GetJniEnv(), NULL);
+  ScopedLocalRef<jobject> peer(self->GetJniEnv(), nullptr);
   {
     ScopedObjectAccess soa(self);
-    peer.reset(soa.AddLocalReference<jobject>(gRegistry->Get<mirror::Object*>(thread_id)));
+    JDWP::JdwpError error;
+    peer.reset(soa.AddLocalReference<jobject>(gRegistry->Get<mirror::Object*>(thread_id, &error)));
   }
-  if (peer.get() == NULL) {
+  if (peer.get() == nullptr) {
     return JDWP::ERR_THREAD_NOT_ALIVE;
   }
   // Suspend thread to build stack trace. Take suspend thread lock to avoid races with threads
@@ -2284,7 +2305,7 @@
   ThreadList* thread_list = Runtime::Current()->GetThreadList();
   Thread* thread = thread_list->SuspendThreadByPeer(peer.get(), request_suspension, true,
                                                     &timed_out);
-  if (thread != NULL) {
+  if (thread != nullptr) {
     return JDWP::ERR_NONE;
   } else if (timed_out) {
     return JDWP::ERR_INTERNAL;
@@ -2295,13 +2316,15 @@
 
 void Dbg::ResumeThread(JDWP::ObjectId thread_id) {
   ScopedObjectAccessUnchecked soa(Thread::Current());
-  mirror::Object* peer = gRegistry->Get<mirror::Object*>(thread_id);
+  JDWP::JdwpError error;
+  mirror::Object* peer = gRegistry->Get<mirror::Object*>(thread_id, &error);
+  CHECK(peer != nullptr) << error;
   Thread* thread;
   {
     MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
     thread = Thread::FromManagedThread(soa, peer);
   }
-  if (thread == NULL) {
+  if (thread == nullptr) {
     LOG(WARNING) << "No such thread for resume: " << peer;
     return;
   }
@@ -2322,7 +2345,7 @@
 struct GetThisVisitor : public StackVisitor {
   GetThisVisitor(Thread* thread, Context* context, JDWP::FrameId frame_id)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-      : StackVisitor(thread, context), this_object(NULL), frame_id(frame_id) {}
+      : StackVisitor(thread, context), this_object(nullptr), frame_id(frame_id) {}
 
   // TODO: Enable annotalysis. We know lock is held in constructor, but abstraction confuses
   // annotalysis.
@@ -2345,7 +2368,8 @@
   Thread* thread;
   {
     MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
-    JDWP::JdwpError error = DecodeThread(soa, thread_id, thread);
+    JDWP::JdwpError error;
+    thread = DecodeThread(soa, thread_id, &error);
     if (error != JDWP::ERR_NONE) {
       return error;
     }
@@ -2514,8 +2538,8 @@
 
   ScopedObjectAccessUnchecked soa(Thread::Current());
   MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
-  Thread* thread;
-  JDWP::JdwpError error = DecodeThread(soa, thread_id, thread);
+  JDWP::JdwpError error;
+  Thread* thread = DecodeThread(soa, thread_id, &error);
   if (error != JDWP::ERR_NONE) {
     return error;
   }
@@ -2596,9 +2620,11 @@
         case JDWP::JT_THREAD:
         case JDWP::JT_THREAD_GROUP: {
           CHECK_EQ(width_, sizeof(JDWP::ObjectId));
-          mirror::Object* o = gRegistry->Get<mirror::Object*>(static_cast<JDWP::ObjectId>(value_));
-          if (o == ObjectRegistry::kInvalidObject) {
-            VLOG(jdwp) << tag_ << " object " << o << " is an invalid object";
+          JDWP::JdwpError error;
+          mirror::Object* o =
+              gRegistry->Get<mirror::Object*>(static_cast<JDWP::ObjectId>(value_), &error);
+          if (error != JDWP::ERR_NONE) {
+            VLOG(jdwp) << tag_ << " object " << value_ << " is an invalid object";
             error_ = JDWP::ERR_INVALID_OBJECT;
           } else if (!SetVReg(m, reg, static_cast<uint32_t>(reinterpret_cast<uintptr_t>(o)),
                               kReferenceVReg)) {
@@ -2642,8 +2668,8 @@
 
   ScopedObjectAccessUnchecked soa(Thread::Current());
   MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
-  Thread* thread;
-  JDWP::JdwpError error = DecodeThread(soa, thread_id, thread);
+  JDWP::JdwpError error;
+  Thread* thread = DecodeThread(soa, thread_id, &error);
   if (error != JDWP::ERR_NONE) {
     return error;
   }
@@ -2674,7 +2700,7 @@
   DCHECK(m != nullptr);
   DCHECK_EQ(m->IsStatic(), this_object == nullptr);
   JDWP::JdwpLocation location;
-  SetLocation(location, m, dex_pc);
+  SetLocation(&location, m, dex_pc);
 
   // We need 'this' for InstanceOnly filters only.
   JDWP::ObjectId this_id = GetThisObjectIdForEvent(this_object);
@@ -2689,7 +2715,7 @@
   DCHECK(m != nullptr);
   DCHECK(f != nullptr);
   JDWP::JdwpLocation location;
-  SetLocation(location, m, dex_pc);
+  SetLocation(&location, m, dex_pc);
 
   JDWP::RefTypeId type_id = gRegistry->AddRefType(f->GetDeclaringClass());
   JDWP::FieldId field_id = ToFieldId(f);
@@ -2708,7 +2734,7 @@
   DCHECK(f != nullptr);
   DCHECK(field_value != nullptr);
   JDWP::JdwpLocation location;
-  SetLocation(location, m, dex_pc);
+  SetLocation(&location, m, dex_pc);
 
   JDWP::RefTypeId type_id = gRegistry->AddRefType(f->GetDeclaringClass());
   JDWP::FieldId field_id = ToFieldId(f);
@@ -2725,9 +2751,9 @@
   }
 
   JDWP::JdwpLocation jdwp_throw_location;
-  SetLocation(jdwp_throw_location, throw_location.GetMethod(), throw_location.GetDexPc());
+  SetLocation(&jdwp_throw_location, throw_location.GetMethod(), throw_location.GetDexPc());
   JDWP::JdwpLocation catch_location;
-  SetLocation(catch_location, catch_method, catch_dex_pc);
+  SetLocation(&catch_location, catch_method, catch_dex_pc);
 
   // We need 'this' for InstanceOnly filters only.
   JDWP::ObjectId this_id = GetThisObjectIdForEvent(throw_location.GetThis());
@@ -3159,7 +3185,7 @@
     ScopedObjectAccessUnchecked soa(self);
     {
       MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
-      error_ = DecodeThread(soa, thread_id, thread_);
+      thread_ = DecodeThread(soa, thread_id, &error_);
     }
     if (error_ == JDWP::ERR_NONE) {
       if (thread_ == soa.Self()) {
@@ -3225,10 +3251,10 @@
     explicit SingleStepStackVisitor(Thread* thread, SingleStepControl* single_step_control,
                                     int32_t* line_number)
         SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-        : StackVisitor(thread, NULL), single_step_control_(single_step_control),
+        : StackVisitor(thread, nullptr), single_step_control_(single_step_control),
           line_number_(line_number) {
       DCHECK_EQ(single_step_control_, thread->GetSingleStepControl());
-      single_step_control_->method = NULL;
+      single_step_control_->method = nullptr;
       single_step_control_->stack_depth = 0;
     }
 
@@ -3238,11 +3264,11 @@
       mirror::ArtMethod* m = GetMethod();
       if (!m->IsRuntimeMethod()) {
         ++single_step_control_->stack_depth;
-        if (single_step_control_->method == NULL) {
+        if (single_step_control_->method == nullptr) {
           mirror::DexCache* dex_cache = m->GetDeclaringClass()->GetDexCache();
           single_step_control_->method = m;
           *line_number_ = -1;
-          if (dex_cache != NULL) {
+          if (dex_cache != nullptr) {
             const DexFile& dex_file = *dex_cache->GetDexFile();
             *line_number_ = dex_file.GetLineNumFromPC(m, GetDexPc());
           }
@@ -3315,7 +3341,7 @@
     const DexFile::CodeItem* const code_item = m->GetCodeItem();
     DebugCallbackContext context(single_step_control, line_number, code_item);
     m->GetDexFile()->DecodeDebugInfo(code_item, m->IsStatic(), m->GetDexMethodIndex(),
-                                     DebugCallbackContext::Callback, NULL, &context);
+                                     DebugCallbackContext::Callback, nullptr, &context);
   }
 
   //
@@ -3345,8 +3371,8 @@
 void Dbg::UnconfigureStep(JDWP::ObjectId thread_id) {
   ScopedObjectAccessUnchecked soa(Thread::Current());
   MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
-  Thread* thread;
-  JDWP::JdwpError error = DecodeThread(soa, thread_id, thread);
+  JDWP::JdwpError error;
+  Thread* thread = DecodeThread(soa, thread_id, &error);
   if (error == JDWP::ERR_NONE) {
     SingleStepControl* single_step_control = thread->GetSingleStepControl();
     DCHECK(single_step_control != nullptr);
@@ -3390,13 +3416,14 @@
                                   JDWP::ObjectId* pExceptionId) {
   ThreadList* thread_list = Runtime::Current()->GetThreadList();
 
-  Thread* targetThread = NULL;
-  DebugInvokeReq* req = NULL;
+  Thread* targetThread = nullptr;
+  DebugInvokeReq* req = nullptr;
   Thread* self = Thread::Current();
   {
     ScopedObjectAccessUnchecked soa(self);
     MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
-    JDWP::JdwpError error = DecodeThread(soa, thread_id, targetThread);
+    JDWP::JdwpError error;
+    targetThread = DecodeThread(soa, thread_id, &error);
     if (error != JDWP::ERR_NONE) {
       LOG(ERROR) << "InvokeMethod request for invalid thread id " << thread_id;
       return error;
@@ -3431,25 +3458,24 @@
       return JDWP::ERR_THREAD_SUSPENDED;  // Probably not expected here.
     }
 
-    JDWP::JdwpError status;
-    mirror::Object* receiver = gRegistry->Get<mirror::Object*>(object_id);
-    if (receiver == ObjectRegistry::kInvalidObject) {
+    mirror::Object* receiver = gRegistry->Get<mirror::Object*>(object_id, &error);
+    if (error != JDWP::ERR_NONE) {
       return JDWP::ERR_INVALID_OBJECT;
     }
 
-    mirror::Object* thread = gRegistry->Get<mirror::Object*>(thread_id);
-    if (thread == ObjectRegistry::kInvalidObject) {
+    mirror::Object* thread = gRegistry->Get<mirror::Object*>(thread_id, &error);
+    if (error != JDWP::ERR_NONE) {
       return JDWP::ERR_INVALID_OBJECT;
     }
     // TODO: check that 'thread' is actually a java.lang.Thread!
 
-    mirror::Class* c = DecodeClass(class_id, status);
-    if (c == NULL) {
-      return status;
+    mirror::Class* c = DecodeClass(class_id, &error);
+    if (c == nullptr) {
+      return error;
     }
 
     mirror::ArtMethod* m = FromMethodId(method_id);
-    if (m->IsStatic() != (receiver == NULL)) {
+    if (m->IsStatic() != (receiver == nullptr)) {
       return JDWP::ERR_INVALID_METHODID;
     }
     if (m->IsStatic()) {
@@ -3483,11 +3509,11 @@
         if (shorty[i + 1] == 'L') {
           // Did we really get an argument of an appropriate reference type?
           mirror::Class* parameter_type = mh.GetClassFromTypeIdx(types->GetTypeItem(i).type_idx_);
-          mirror::Object* argument = gRegistry->Get<mirror::Object*>(arg_values[i]);
-          if (argument == ObjectRegistry::kInvalidObject) {
+          mirror::Object* argument = gRegistry->Get<mirror::Object*>(arg_values[i], &error);
+          if (error != JDWP::ERR_NONE) {
             return JDWP::ERR_INVALID_OBJECT;
           }
-          if (argument != NULL && !argument->InstanceOf(parameter_type)) {
+          if (argument != nullptr && !argument->InstanceOf(parameter_type)) {
             return JDWP::ERR_ILLEGAL_ARGUMENT;
           }
 
@@ -3598,7 +3624,7 @@
 
   // Translate the method through the vtable, unless the debugger wants to suppress it.
   Handle<mirror::ArtMethod> m(hs.NewHandle(pReq->method));
-  if ((pReq->options & JDWP::INVOKE_NONVIRTUAL) == 0 && pReq->receiver != NULL) {
+  if ((pReq->options & JDWP::INVOKE_NONVIRTUAL) == 0 && pReq->receiver != nullptr) {
     mirror::ArtMethod* actual_method = pReq->klass->FindVirtualMethodForVirtualOrInterface(m.Get());
     if (actual_method != m.Get()) {
       VLOG(jdwp) << "ExecuteMethod translated " << PrettyMethod(m.Get()) << " to " << PrettyMethod(actual_method);
@@ -3615,7 +3641,7 @@
   pReq->result_value = InvokeWithJValues(soa, pReq->receiver, soa.EncodeMethod(m.Get()),
                                          reinterpret_cast<jvalue*>(pReq->arg_values));
 
-  mirror::Throwable* exception = soa.Self()->GetException(NULL);
+  mirror::Throwable* exception = soa.Self()->GetException(nullptr);
   soa.Self()->ClearException();
   pReq->exception = gRegistry->Add(exception);
   pReq->result_tag = BasicTagFromDescriptor(m.Get()->GetShorty());
@@ -3643,7 +3669,7 @@
     gRegistry->Add(pReq->result_value.GetL());
   }
 
-  if (old_exception.Get() != NULL) {
+  if (old_exception.Get() != nullptr) {
     ThrowLocation gc_safe_throw_location(old_throw_this_object.Get(), old_throw_method.Get(),
                                          old_throw_dex_pc);
     soa.Self()->SetException(gc_safe_throw_location, old_exception.Get());
@@ -3662,23 +3688,24 @@
  * OLD-TODO: we currently assume that the request and reply include a single
  * chunk.  If this becomes inconvenient we will need to adapt.
  */
-bool Dbg::DdmHandlePacket(JDWP::Request& request, uint8_t** pReplyBuf, int* pReplyLen) {
+bool Dbg::DdmHandlePacket(JDWP::Request* request, uint8_t** pReplyBuf, int* pReplyLen) {
   Thread* self = Thread::Current();
   JNIEnv* env = self->GetJniEnv();
 
-  uint32_t type = request.ReadUnsigned32("type");
-  uint32_t length = request.ReadUnsigned32("length");
+  uint32_t type = request->ReadUnsigned32("type");
+  uint32_t length = request->ReadUnsigned32("length");
 
   // Create a byte[] corresponding to 'request'.
-  size_t request_length = request.size();
+  size_t request_length = request->size();
   ScopedLocalRef<jbyteArray> dataArray(env, env->NewByteArray(request_length));
-  if (dataArray.get() == NULL) {
+  if (dataArray.get() == nullptr) {
     LOG(WARNING) << "byte[] allocation failed: " << request_length;
     env->ExceptionClear();
     return false;
   }
-  env->SetByteArrayRegion(dataArray.get(), 0, request_length, reinterpret_cast<const jbyte*>(request.data()));
-  request.Skip(request_length);
+  env->SetByteArrayRegion(dataArray.get(), 0, request_length,
+                          reinterpret_cast<const jbyte*>(request->data()));
+  request->Skip(request_length);
 
   // Run through and find all chunks.  [Currently just find the first.]
   ScopedByteArrayRO contents(env, dataArray.get());
@@ -3698,7 +3725,7 @@
     return false;
   }
 
-  if (chunk.get() == NULL) {
+  if (chunk.get() == nullptr) {
     return false;
   }
 
@@ -3720,13 +3747,13 @@
   type = env->GetIntField(chunk.get(), WellKnownClasses::org_apache_harmony_dalvik_ddmc_Chunk_type);
 
   VLOG(jdwp) << StringPrintf("DDM reply: type=0x%08x data=%p offset=%d length=%d", type, replyData.get(), offset, length);
-  if (length == 0 || replyData.get() == NULL) {
+  if (length == 0 || replyData.get() == nullptr) {
     return false;
   }
 
   const int kChunkHdrLen = 8;
   uint8_t* reply = new uint8_t[length + kChunkHdrLen];
-  if (reply == NULL) {
+  if (reply == nullptr) {
     LOG(WARNING) << "malloc failed: " << (length + kChunkHdrLen);
     return false;
   }
@@ -3791,8 +3818,8 @@
     ScopedObjectAccessUnchecked soa(Thread::Current());
     StackHandleScope<1> hs(soa.Self());
     Handle<mirror::String> name(hs.NewHandle(t->GetThreadName(soa)));
-    size_t char_count = (name.Get() != NULL) ? name->GetLength() : 0;
-    const jchar* chars = (name.Get() != NULL) ? name->GetCharArray()->GetData() : NULL;
+    size_t char_count = (name.Get() != nullptr) ? name->GetLength() : 0;
+    const jchar* chars = (name.Get() != nullptr) ? name->GetCharArray()->GetData() : nullptr;
 
     std::vector<uint8_t> bytes;
     JDWP::Append4BE(bytes, t->GetThreadId());
@@ -3844,7 +3871,7 @@
 }
 
 void Dbg::DdmSendChunk(uint32_t type, size_t byte_count, const uint8_t* buf) {
-  CHECK(buf != NULL);
+  CHECK(buf != nullptr);
   iovec vec[1];
   vec[0].iov_base = reinterpret_cast<void*>(const_cast<uint8_t*>(buf));
   vec[0].iov_len = byte_count;
@@ -3856,7 +3883,7 @@
 }
 
 void Dbg::DdmSendChunkV(uint32_t type, const iovec* iov, int iov_count) {
-  if (gJdwpState == NULL) {
+  if (gJdwpState == nullptr) {
     VLOG(jdwp) << "Debugger thread not active, ignoring DDM send: " << type;
   } else {
     gJdwpState->DdmSendChunkV(type, iov, iov_count);
@@ -4013,7 +4040,7 @@
   }
 
   void Flush() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    if (pieceLenField_ == NULL) {
+    if (pieceLenField_ == nullptr) {
       // Flush immediately post Reset (maybe back-to-back Flush). Ignore.
       CHECK(needHeader_);
       return;
@@ -4041,7 +4068,7 @@
     ResetStartOfNextChunk();
     totalAllocationUnits_ = 0;
     needHeader_ = true;
-    pieceLenField_ = NULL;
+    pieceLenField_ = nullptr;
   }
 
   void HeapChunkCallback(void* start, void* /*end*/, size_t used_bytes)
@@ -4050,9 +4077,9 @@
     // Note: heap call backs cannot manipulate the heap upon which they are crawling, care is taken
     // in the following code not to allocate memory, by ensuring buf_ is of the correct size
     if (used_bytes == 0) {
-        if (start == NULL) {
+        if (start == nullptr) {
             // Reset for start of new heap.
-            startOfNextMemoryChunk_ = NULL;
+            startOfNextMemoryChunk_ = nullptr;
             Flush();
         }
         // Only process in use memory so that free region information
@@ -4067,7 +4094,7 @@
 
     // TODO: I'm not sure using start of next chunk works well with multiple spaces. We shouldn't
     // count gaps inbetween spaces as free memory.
-    if (startOfNextMemoryChunk_ != NULL) {
+    if (startOfNextMemoryChunk_ != nullptr) {
         // Transmit any pending free memory. Native free memory of
         // over kMaxFreeLen could be because of the use of mmaps, so
         // don't report. If not free memory then start a new segment.
@@ -4083,7 +4110,7 @@
             }
         }
         if (flush) {
-            startOfNextMemoryChunk_ = NULL;
+            startOfNextMemoryChunk_ = nullptr;
             Flush();
         }
     }
@@ -4129,7 +4156,7 @@
 
   uint8_t ExamineObject(mirror::Object* o, bool is_native_heap)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::heap_bitmap_lock_) {
-    if (o == NULL) {
+    if (o == nullptr) {
       return HPSG_STATE(SOLIDITY_FREE, 0);
     }
 
@@ -4146,7 +4173,7 @@
     }
 
     mirror::Class* c = o->GetClass();
-    if (c == NULL) {
+    if (c == nullptr) {
       // The object was probably just created but hasn't been initialized yet.
       return HPSG_STATE(SOLIDITY_HARD, KIND_OBJECT);
     }
@@ -4295,14 +4322,14 @@
   if (enabled) {
     {
       MutexLock mu(Thread::Current(), *alloc_tracker_lock_);
-      if (recent_allocation_records_ == NULL) {
+      if (recent_allocation_records_ == nullptr) {
         alloc_record_max_ = GetAllocTrackerMax();
         LOG(INFO) << "Enabling alloc tracker (" << alloc_record_max_ << " entries of "
             << kMaxAllocRecordStackDepth << " frames, taking "
             << PrettySize(sizeof(AllocRecord) * alloc_record_max_) << ")";
         alloc_record_head_ = alloc_record_count_ = 0;
         recent_allocation_records_ = new AllocRecord[alloc_record_max_];
-        CHECK(recent_allocation_records_ != NULL);
+        CHECK(recent_allocation_records_ != nullptr);
       }
     }
     Runtime::Current()->GetInstrumentation()->InstrumentQuickAllocEntryPoints();
@@ -4312,7 +4339,7 @@
       MutexLock mu(Thread::Current(), *alloc_tracker_lock_);
       LOG(INFO) << "Disabling alloc tracker";
       delete[] recent_allocation_records_;
-      recent_allocation_records_ = NULL;
+      recent_allocation_records_ = nullptr;
       type_cache_.Clear();
     }
   }
@@ -4321,7 +4348,7 @@
 struct AllocRecordStackVisitor : public StackVisitor {
   AllocRecordStackVisitor(Thread* thread, AllocRecord* record)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-      : StackVisitor(thread, NULL), record(record), depth(0) {}
+      : StackVisitor(thread, nullptr), record(record), depth(0) {}
 
   // TODO: Enable annotalysis. We know lock is held in constructor, but abstraction confuses
   // annotalysis.
@@ -4352,10 +4379,10 @@
 
 void Dbg::RecordAllocation(mirror::Class* type, size_t byte_count) {
   Thread* self = Thread::Current();
-  CHECK(self != NULL);
+  CHECK(self != nullptr);
 
   MutexLock mu(self, *alloc_tracker_lock_);
-  if (recent_allocation_records_ == NULL) {
+  if (recent_allocation_records_ == nullptr) {
     return;
   }
 
@@ -4395,7 +4422,7 @@
 void Dbg::DumpRecentAllocations() {
   ScopedObjectAccess soa(Thread::Current());
   MutexLock mu(soa.Self(), *alloc_tracker_lock_);
-  if (recent_allocation_records_ == NULL) {
+  if (recent_allocation_records_ == nullptr) {
     LOG(INFO) << "Not recording tracked allocations";
     return;
   }
@@ -4415,7 +4442,7 @@
     for (size_t stack_frame = 0; stack_frame < kMaxAllocRecordStackDepth; ++stack_frame) {
       AllocRecordStackTraceElement* stack_element = record->StackElement(stack_frame);
       mirror::ArtMethod* m = stack_element->Method();
-      if (m == NULL) {
+      if (m == nullptr) {
         break;
       }
       LOG(INFO) << "    " << PrettyMethod(m) << " line " << stack_element->LineNumber();
@@ -4543,7 +4570,7 @@
       class_names.Add(record->Type()->GetDescriptor(&temp));
       for (size_t i = 0; i < kMaxAllocRecordStackDepth; i++) {
         mirror::ArtMethod* m = record->StackElement(i)->Method();
-        if (m != NULL) {
+        if (m != nullptr) {
           class_names.Add(m->GetDeclaringClassDescriptor());
           method_names.Add(m->GetName());
           filenames.Add(GetMethodSourceFile(m));
@@ -4626,7 +4653,7 @@
   }
   JNIEnv* env = self->GetJniEnv();
   jbyteArray result = env->NewByteArray(bytes.size());
-  if (result != NULL) {
+  if (result != nullptr) {
     env->SetByteArrayRegion(result, 0, bytes.size(), reinterpret_cast<const jbyte*>(&bytes[0]));
   }
   return result;
diff --git a/runtime/debugger.h b/runtime/debugger.h
index 1d3668c..52ae7a9 100644
--- a/runtime/debugger.h
+++ b/runtime/debugger.h
@@ -248,9 +248,9 @@
    */
   static std::string GetClassName(JDWP::RefTypeId id)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  static JDWP::JdwpError GetClassObject(JDWP::RefTypeId id, JDWP::ObjectId& class_object_id)
+  static JDWP::JdwpError GetClassObject(JDWP::RefTypeId id, JDWP::ObjectId* class_object_id)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  static JDWP::JdwpError GetSuperclass(JDWP::RefTypeId id, JDWP::RefTypeId& superclass_id)
+  static JDWP::JdwpError GetSuperclass(JDWP::RefTypeId id, JDWP::RefTypeId* superclass_id)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static JDWP::JdwpError GetClassLoader(JDWP::RefTypeId id, JDWP::ExpandBuf* pReply)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -258,38 +258,38 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static JDWP::JdwpError GetReflectedType(JDWP::RefTypeId class_id, JDWP::ExpandBuf* pReply)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  static void GetClassList(std::vector<JDWP::RefTypeId>& classes)
+  static void GetClassList(std::vector<JDWP::RefTypeId>* classes)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static JDWP::JdwpError GetClassInfo(JDWP::RefTypeId class_id, JDWP::JdwpTypeTag* pTypeTag,
                                       uint32_t* pStatus, std::string* pDescriptor)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  static void FindLoadedClassBySignature(const char* descriptor, std::vector<JDWP::RefTypeId>& ids)
+  static void FindLoadedClassBySignature(const char* descriptor, std::vector<JDWP::RefTypeId>* ids)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static JDWP::JdwpError GetReferenceType(JDWP::ObjectId object_id, JDWP::ExpandBuf* pReply)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static JDWP::JdwpError GetSignature(JDWP::RefTypeId ref_type_id, std::string* signature)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  static JDWP::JdwpError GetSourceFile(JDWP::RefTypeId ref_type_id, std::string& source_file)
+  static JDWP::JdwpError GetSourceFile(JDWP::RefTypeId ref_type_id, std::string* source_file)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  static JDWP::JdwpError GetObjectTag(JDWP::ObjectId object_id, uint8_t& tag)
+  static JDWP::JdwpError GetObjectTag(JDWP::ObjectId object_id, uint8_t* tag)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static size_t GetTagWidth(JDWP::JdwpTag tag);
 
-  static JDWP::JdwpError GetArrayLength(JDWP::ObjectId array_id, int& length)
+  static JDWP::JdwpError GetArrayLength(JDWP::ObjectId array_id, int32_t* length)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static JDWP::JdwpError OutputArray(JDWP::ObjectId array_id, int offset, int count,
                                      JDWP::ExpandBuf* pReply)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static JDWP::JdwpError SetArrayElements(JDWP::ObjectId array_id, int offset, int count,
-                                          JDWP::Request& request)
+                                          JDWP::Request* request)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   static JDWP::ObjectId CreateString(const std::string& str)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  static JDWP::JdwpError CreateObject(JDWP::RefTypeId class_id, JDWP::ObjectId& new_object)
+  static JDWP::JdwpError CreateObject(JDWP::RefTypeId class_id, JDWP::ObjectId* new_object)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static JDWP::JdwpError CreateArrayObject(JDWP::RefTypeId array_class_id, uint32_t length,
-                                           JDWP::ObjectId& new_array)
+                                           JDWP::ObjectId* new_array)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   static bool MatchType(JDWP::RefTypeId instance_class_id, JDWP::RefTypeId class_id)
@@ -301,12 +301,12 @@
   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)
+                                          std::vector<JDWP::ObjectId>* monitors,
+                                          std::vector<uint32_t>* stack_depths)
       LOCKS_EXCLUDED(Locks::thread_list_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static JDWP::JdwpError GetContendedMonitor(JDWP::ObjectId thread_id,
-                                             JDWP::ObjectId& contended_monitor)
+                                             JDWP::ObjectId* contended_monitor)
       LOCKS_EXCLUDED(Locks::thread_list_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -314,19 +314,19 @@
   // Heap.
   //
   static JDWP::JdwpError GetInstanceCounts(const std::vector<JDWP::RefTypeId>& class_ids,
-                                           std::vector<uint64_t>& counts)
+                                           std::vector<uint64_t>* counts)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static JDWP::JdwpError GetInstances(JDWP::RefTypeId class_id, int32_t max_count,
-                                      std::vector<JDWP::ObjectId>& instances)
+                                      std::vector<JDWP::ObjectId>* instances)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static JDWP::JdwpError GetReferringObjects(JDWP::ObjectId object_id, int32_t max_count,
-                                             std::vector<JDWP::ObjectId>& referring_objects)
+                                             std::vector<JDWP::ObjectId>* referring_objects)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static JDWP::JdwpError DisableCollection(JDWP::ObjectId object_id)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static JDWP::JdwpError EnableCollection(JDWP::ObjectId object_id)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  static JDWP::JdwpError IsCollected(JDWP::ObjectId object_id, bool& is_collected)
+  static JDWP::JdwpError IsCollected(JDWP::ObjectId object_id, bool* is_collected)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static void DisposeObject(JDWP::ObjectId object_id, uint32_t reference_count)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -358,7 +358,7 @@
                                JDWP::ExpandBuf* pReply)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static JDWP::JdwpError GetBytecodes(JDWP::RefTypeId class_id, JDWP::MethodId method_id,
-                                      std::vector<uint8_t>& bytecodes)
+                                      std::vector<uint8_t>* bytecodes)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   static std::string GetFieldName(JDWP::FieldId field_id)
@@ -387,7 +387,7 @@
   /*
    * Thread, ThreadGroup, Frame
    */
-  static JDWP::JdwpError GetThreadName(JDWP::ObjectId thread_id, std::string& name)
+  static JDWP::JdwpError GetThreadName(JDWP::ObjectId thread_id, std::string* name)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       LOCKS_EXCLUDED(Locks::thread_list_lock_);
   static JDWP::JdwpError GetThreadGroup(JDWP::ObjectId thread_id, JDWP::ExpandBuf* pReply)
@@ -412,12 +412,13 @@
 
   // Fills 'thread_ids' with the threads in the given thread group. If thread_group_id == 0,
   // returns all threads.
-  static void GetThreads(JDWP::ObjectId thread_group_id, std::vector<JDWP::ObjectId>& thread_ids)
+  static void GetThreads(JDWP::ObjectId thread_group_id, std::vector<JDWP::ObjectId>* thread_ids)
       LOCKS_EXCLUDED(Locks::thread_list_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  static void GetChildThreadGroups(JDWP::ObjectId thread_group_id, std::vector<JDWP::ObjectId>& child_thread_group_ids);
+  static void GetChildThreadGroups(JDWP::ObjectId thread_group_id,
+                                   std::vector<JDWP::ObjectId>* child_thread_group_ids);
 
-  static JDWP::JdwpError GetThreadFrameCount(JDWP::ObjectId thread_id, size_t& result)
+  static JDWP::JdwpError GetThreadFrameCount(JDWP::ObjectId thread_id, size_t* result)
       LOCKS_EXCLUDED(Locks::thread_list_lock_);
   static JDWP::JdwpError GetThreadFrames(JDWP::ObjectId thread_id, size_t start_frame,
                                          size_t frame_count, JDWP::ExpandBuf* buf)
@@ -542,7 +543,7 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static void DdmSetThreadNotification(bool enable)
       LOCKS_EXCLUDED(Locks::thread_list_lock_);
-  static bool DdmHandlePacket(JDWP::Request& request, uint8_t** pReplyBuf, int* pReplyLen);
+  static bool DdmHandlePacket(JDWP::Request* request, uint8_t** pReplyBuf, int* pReplyLen);
   static void DdmConnected() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static void DdmDisconnected() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static void DdmSendChunk(uint32_t type, const std::vector<uint8_t>& bytes)
@@ -595,8 +596,8 @@
   static void DdmSendHeapSegments(bool native)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  static TypeCache& GetTypeCache() {
-    return type_cache_;
+  static TypeCache* GetTypeCache() {
+    return &type_cache_;
   }
 
  private:
diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc
index cf89850..e1c532e 100644
--- a/runtime/entrypoints/entrypoint_utils.cc
+++ b/runtime/entrypoints/entrypoint_utils.cc
@@ -220,21 +220,18 @@
 }
 
 void CheckReferenceResult(mirror::Object* o, Thread* self) {
-  if (o == NULL) {
+  if (o == nullptr) {
     return;
   }
-  mirror::ArtMethod* m = self->GetCurrentMethod(NULL);
-  if (o == kInvalidIndirectRefObject) {
-    Runtime::Current()->GetJavaVM()->JniAbortF(NULL, "invalid reference returned from %s",
-                                               PrettyMethod(m).c_str());
-  }
+  mirror::ArtMethod* m = self->GetCurrentMethod(nullptr);
   // Make sure that the result is an instance of the type this method was expected to return.
   StackHandleScope<1> hs(self);
   Handle<mirror::ArtMethod> h_m(hs.NewHandle(m));
   mirror::Class* return_type = MethodHelper(h_m).GetReturnType();
 
   if (!o->InstanceOf(return_type)) {
-    Runtime::Current()->GetJavaVM()->JniAbortF(NULL, "attempt to return an instance of %s from %s",
+    Runtime::Current()->GetJavaVM()->JniAbortF(nullptr,
+                                               "attempt to return an instance of %s from %s",
                                                PrettyTypeOf(o).c_str(),
                                                PrettyMethod(h_m.Get()).c_str());
   }
diff --git a/runtime/indirect_reference_table-inl.h b/runtime/indirect_reference_table-inl.h
index 00f7b06..9bf3ea2 100644
--- a/runtime/indirect_reference_table-inl.h
+++ b/runtime/indirect_reference_table-inl.h
@@ -19,6 +19,7 @@
 
 #include "indirect_reference_table.h"
 
+#include "runtime-inl.h"
 #include "verify_object-inl.h"
 
 namespace art {
@@ -26,6 +27,15 @@
 class Object;
 }  // namespace mirror
 
+inline void IrtIterator::SkipNullsAndTombstones() {
+  // We skip NULLs and tombstones. Clients don't want to see implementation details.
+  while (i_ < capacity_ &&
+         (table_[i_].IsNull() ||
+          Runtime::Current()->IsClearedJniWeakGlobal(table_[i_].Read<kWithoutReadBarrier>()))) {
+    ++i_;
+  }
+}
+
 // Verifies that the indirect table lookup is valid.
 // Returns "false" if something looks bad.
 inline bool IndirectReferenceTable::GetChecked(IndirectRef iref) const {
@@ -73,15 +83,11 @@
 template<ReadBarrierOption kReadBarrierOption>
 inline mirror::Object* IndirectReferenceTable::Get(IndirectRef iref) const {
   if (!GetChecked(iref)) {
-    return kInvalidIndirectRefObject;
+    return nullptr;
   }
   uint32_t idx = ExtractIndex(iref);
-  mirror::Object* obj = table_[idx].Read<kWithoutReadBarrier>();
-  if (LIKELY(obj != kClearedJniWeakGlobal)) {
-    // The read barrier or VerifyObject won't handle kClearedJniWeakGlobal.
-    obj = table_[idx].Read<kReadBarrierOption>();
-    VerifyObject(obj);
-  }
+  mirror::Object* obj = table_[idx].Read<kReadBarrierOption>();
+  VerifyObject(obj);
   return obj;
 }
 
diff --git a/runtime/indirect_reference_table.cc b/runtime/indirect_reference_table.cc
index 1ba2291..49bffa4 100644
--- a/runtime/indirect_reference_table.cc
+++ b/runtime/indirect_reference_table.cc
@@ -276,10 +276,6 @@
     mirror::Object* obj = table_[i].Read<kWithoutReadBarrier>();
     if (UNLIKELY(obj == nullptr)) {
       // Remove NULLs.
-    } else if (UNLIKELY(obj == kClearedJniWeakGlobal)) {
-      // ReferenceTable::Dump() will handle kClearedJniWeakGlobal
-      // while the read barrier won't.
-      entries.push_back(GcRoot<mirror::Object>(obj));
     } else {
       obj = table_[i].Read();
       entries.push_back(GcRoot<mirror::Object>(obj));
diff --git a/runtime/indirect_reference_table.h b/runtime/indirect_reference_table.h
index d25bc42..562ba1e 100644
--- a/runtime/indirect_reference_table.h
+++ b/runtime/indirect_reference_table.h
@@ -105,10 +105,6 @@
  */
 typedef void* IndirectRef;
 
-// Magic failure values; must not pass Heap::ValidateObject() or Heap::IsHeapAddress().
-static mirror::Object* const kInvalidIndirectRefObject = reinterpret_cast<mirror::Object*>(0xdead4321);
-static mirror::Object* const kClearedJniWeakGlobal = reinterpret_cast<mirror::Object*>(0xdead1234);
-
 /*
  * Indirect reference kind, used as the two low bits of IndirectRef.
  *
@@ -229,18 +225,11 @@
   }
 
  private:
-  void SkipNullsAndTombstones() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    // We skip NULLs and tombstones. Clients don't want to see implementation details.
-    while (i_ < capacity_ &&
-           (table_[i_].IsNull() ||
-            table_[i_].Read<kWithoutReadBarrier>() == kClearedJniWeakGlobal)) {
-      ++i_;
-    }
-  }
+  void SkipNullsAndTombstones() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   GcRoot<mirror::Object>* const table_;
   size_t i_;
-  size_t capacity_;
+  const size_t capacity_;
 };
 
 bool inline operator==(const IrtIterator& lhs, const IrtIterator& rhs) {
diff --git a/runtime/indirect_reference_table_test.cc b/runtime/indirect_reference_table_test.cc
index a33a981..99ee597 100644
--- a/runtime/indirect_reference_table_test.cc
+++ b/runtime/indirect_reference_table_test.cc
@@ -49,15 +49,15 @@
   IndirectReferenceTable irt(kTableInitial, kTableMax, kGlobal);
 
   mirror::Class* c = class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;");
-  ASSERT_TRUE(c != NULL);
+  ASSERT_TRUE(c != nullptr);
   mirror::Object* obj0 = c->AllocObject(soa.Self());
-  ASSERT_TRUE(obj0 != NULL);
+  ASSERT_TRUE(obj0 != nullptr);
   mirror::Object* obj1 = c->AllocObject(soa.Self());
-  ASSERT_TRUE(obj1 != NULL);
+  ASSERT_TRUE(obj1 != nullptr);
   mirror::Object* obj2 = c->AllocObject(soa.Self());
-  ASSERT_TRUE(obj2 != NULL);
+  ASSERT_TRUE(obj2 != nullptr);
   mirror::Object* obj3 = c->AllocObject(soa.Self());
-  ASSERT_TRUE(obj3 != NULL);
+  ASSERT_TRUE(obj3 != nullptr);
 
   const uint32_t cookie = IRT_FIRST_SEGMENT;
 
@@ -68,13 +68,13 @@
 
   // Add three, check, remove in the order in which they were added.
   iref0 = irt.Add(cookie, obj0);
-  EXPECT_TRUE(iref0 != NULL);
+  EXPECT_TRUE(iref0 != nullptr);
   CheckDump(&irt, 1, 1);
   IndirectRef iref1 = irt.Add(cookie, obj1);
-  EXPECT_TRUE(iref1 != NULL);
+  EXPECT_TRUE(iref1 != nullptr);
   CheckDump(&irt, 2, 2);
   IndirectRef iref2 = irt.Add(cookie, obj2);
-  EXPECT_TRUE(iref2 != NULL);
+  EXPECT_TRUE(iref2 != nullptr);
   CheckDump(&irt, 3, 3);
 
   EXPECT_EQ(obj0, irt.Get(iref0));
@@ -92,15 +92,15 @@
   EXPECT_EQ(0U, irt.Capacity());
 
   // Get invalid entry (off the end of the list).
-  EXPECT_EQ(kInvalidIndirectRefObject, irt.Get(iref0));
+  EXPECT_TRUE(irt.Get(iref0) == nullptr);
 
   // Add three, remove in the opposite order.
   iref0 = irt.Add(cookie, obj0);
-  EXPECT_TRUE(iref0 != NULL);
+  EXPECT_TRUE(iref0 != nullptr);
   iref1 = irt.Add(cookie, obj1);
-  EXPECT_TRUE(iref1 != NULL);
+  EXPECT_TRUE(iref1 != nullptr);
   iref2 = irt.Add(cookie, obj2);
-  EXPECT_TRUE(iref2 != NULL);
+  EXPECT_TRUE(iref2 != nullptr);
   CheckDump(&irt, 3, 3);
 
   ASSERT_TRUE(irt.Remove(cookie, iref2));
@@ -116,11 +116,11 @@
   // Add three, remove middle / middle / bottom / top.  (Second attempt
   // to remove middle should fail.)
   iref0 = irt.Add(cookie, obj0);
-  EXPECT_TRUE(iref0 != NULL);
+  EXPECT_TRUE(iref0 != nullptr);
   iref1 = irt.Add(cookie, obj1);
-  EXPECT_TRUE(iref1 != NULL);
+  EXPECT_TRUE(iref1 != nullptr);
   iref2 = irt.Add(cookie, obj2);
-  EXPECT_TRUE(iref2 != NULL);
+  EXPECT_TRUE(iref2 != nullptr);
   CheckDump(&irt, 3, 3);
 
   ASSERT_EQ(3U, irt.Capacity());
@@ -131,7 +131,7 @@
   CheckDump(&irt, 2, 2);
 
   // Get invalid entry (from hole).
-  EXPECT_EQ(kInvalidIndirectRefObject, irt.Get(iref1));
+  EXPECT_TRUE(irt.Get(iref1) == nullptr);
 
   ASSERT_TRUE(irt.Remove(cookie, iref2));
   CheckDump(&irt, 1, 1);
@@ -145,20 +145,20 @@
   // is still 4 (i.e. holes are getting filled).  Remove #1 and #3, verify
   // that we delete one and don't hole-compact the other.
   iref0 = irt.Add(cookie, obj0);
-  EXPECT_TRUE(iref0 != NULL);
+  EXPECT_TRUE(iref0 != nullptr);
   iref1 = irt.Add(cookie, obj1);
-  EXPECT_TRUE(iref1 != NULL);
+  EXPECT_TRUE(iref1 != nullptr);
   iref2 = irt.Add(cookie, obj2);
-  EXPECT_TRUE(iref2 != NULL);
+  EXPECT_TRUE(iref2 != nullptr);
   IndirectRef iref3 = irt.Add(cookie, obj3);
-  EXPECT_TRUE(iref3 != NULL);
+  EXPECT_TRUE(iref3 != nullptr);
   CheckDump(&irt, 4, 4);
 
   ASSERT_TRUE(irt.Remove(cookie, iref1));
   CheckDump(&irt, 3, 3);
 
   iref1 = irt.Add(cookie, obj1);
-  EXPECT_TRUE(iref1 != NULL);
+  EXPECT_TRUE(iref1 != nullptr);
 
   ASSERT_EQ(4U, irt.Capacity()) << "hole not filled";
   CheckDump(&irt, 4, 4);
@@ -181,12 +181,12 @@
   // iref.  They have the same slot number but are for different objects.
   // With the extended checks in place, this should fail.
   iref0 = irt.Add(cookie, obj0);
-  EXPECT_TRUE(iref0 != NULL);
+  EXPECT_TRUE(iref0 != nullptr);
   CheckDump(&irt, 1, 1);
   ASSERT_TRUE(irt.Remove(cookie, iref0));
   CheckDump(&irt, 0, 0);
   iref1 = irt.Add(cookie, obj1);
-  EXPECT_TRUE(iref1 != NULL);
+  EXPECT_TRUE(iref1 != nullptr);
   CheckDump(&irt, 1, 1);
   ASSERT_FALSE(irt.Remove(cookie, iref0)) << "mismatched del succeeded";
   CheckDump(&irt, 1, 1);
@@ -197,12 +197,12 @@
   // Same as above, but with the same object.  A more rigorous checker
   // (e.g. with slot serialization) will catch this.
   iref0 = irt.Add(cookie, obj0);
-  EXPECT_TRUE(iref0 != NULL);
+  EXPECT_TRUE(iref0 != nullptr);
   CheckDump(&irt, 1, 1);
   ASSERT_TRUE(irt.Remove(cookie, iref0));
   CheckDump(&irt, 0, 0);
   iref1 = irt.Add(cookie, obj0);
-  EXPECT_TRUE(iref1 != NULL);
+  EXPECT_TRUE(iref1 != nullptr);
   CheckDump(&irt, 1, 1);
   if (iref0 != iref1) {
     // Try 0, should not work.
@@ -212,15 +212,15 @@
   ASSERT_EQ(0U, irt.Capacity()) << "temporal del not empty";
   CheckDump(&irt, 0, 0);
 
-  // NULL isn't a valid iref.
-  ASSERT_EQ(kInvalidIndirectRefObject, irt.Get(NULL));
+  // nullptr isn't a valid iref.
+  ASSERT_TRUE(irt.Get(nullptr) == nullptr);
 
   // Stale lookup.
   iref0 = irt.Add(cookie, obj0);
-  EXPECT_TRUE(iref0 != NULL);
+  EXPECT_TRUE(iref0 != nullptr);
   CheckDump(&irt, 1, 1);
   ASSERT_TRUE(irt.Remove(cookie, iref0));
-  EXPECT_EQ(kInvalidIndirectRefObject, irt.Get(iref0)) << "stale lookup succeeded";
+  EXPECT_TRUE(irt.Get(iref0) == nullptr) << "stale lookup succeeded";
   CheckDump(&irt, 0, 0);
 
   // Test table resizing.
@@ -228,12 +228,12 @@
   IndirectRef manyRefs[kTableInitial];
   for (size_t i = 0; i < kTableInitial; i++) {
     manyRefs[i] = irt.Add(cookie, obj0);
-    ASSERT_TRUE(manyRefs[i] != NULL) << "Failed adding " << i;
+    ASSERT_TRUE(manyRefs[i] != nullptr) << "Failed adding " << i;
     CheckDump(&irt, i + 1, 1);
   }
   // ...this one causes overflow.
   iref0 = irt.Add(cookie, obj0);
-  ASSERT_TRUE(iref0 != NULL);
+  ASSERT_TRUE(iref0 != nullptr);
   ASSERT_EQ(kTableInitial + 1, irt.Capacity());
   CheckDump(&irt, kTableInitial + 1, 1);
 
diff --git a/runtime/java_vm_ext.cc b/runtime/java_vm_ext.cc
index dd3b7cf..424addb 100644
--- a/runtime/java_vm_ext.cc
+++ b/runtime/java_vm_ext.cc
@@ -28,6 +28,7 @@
 #include "nativebridge/native_bridge.h"
 #include "java_vm_ext.h"
 #include "parsed_options.h"
+#include "runtime-inl.h"
 #include "ScopedLocalRef.h"
 #include "scoped_thread_state_change.h"
 #include "thread-inl.h"
@@ -761,7 +762,7 @@
     mirror::Object* obj = *entry;
     mirror::Object* new_obj = callback(obj, arg);
     if (new_obj == nullptr) {
-      new_obj = kClearedJniWeakGlobal;
+      new_obj = Runtime::Current()->GetClearedJniWeakGlobal();
     }
     *entry = new_obj;
   }
diff --git a/runtime/jdwp/jdwp.h b/runtime/jdwp/jdwp.h
index 8fd07cc..b5b6298 100644
--- a/runtime/jdwp/jdwp.h
+++ b/runtime/jdwp/jdwp.h
@@ -285,7 +285,7 @@
 
  private:
   explicit JdwpState(const JdwpOptions* options);
-  size_t ProcessRequest(Request& request, ExpandBuf* pReply);
+  size_t ProcessRequest(Request* request, ExpandBuf* pReply);
   bool InvokeInProgress();
   bool IsConnected();
   void SuspendByPolicy(JdwpSuspendPolicy suspend_policy, JDWP::ObjectId thread_self_id)
diff --git a/runtime/jdwp/jdwp_event.cc b/runtime/jdwp/jdwp_event.cc
index 36fbed4..fc39cc4 100644
--- a/runtime/jdwp/jdwp_event.cc
+++ b/runtime/jdwp/jdwp_event.cc
@@ -781,7 +781,7 @@
                << StringPrintf(" (requestId=%#" PRIx32 ")", pEvent->requestId);
   }
   std::string thread_name;
-  JdwpError error = Dbg::GetThreadName(basket.threadId, thread_name);
+  JdwpError error = Dbg::GetThreadName(basket.threadId, &thread_name);
   if (error != JDWP::ERR_NONE) {
     thread_name = "<unknown>";
   }
@@ -924,7 +924,7 @@
 
   // Get instance type tag.
   uint8_t tag;
-  error = Dbg::GetObjectTag(thisPtr, tag);
+  error = Dbg::GetObjectTag(thisPtr, &tag);
   if (error != ERR_NONE) {
     return false;
   }
diff --git a/runtime/jdwp/jdwp_handler.cc b/runtime/jdwp/jdwp_handler.cc
index 330d235..35095f9 100644
--- a/runtime/jdwp/jdwp_handler.cc
+++ b/runtime/jdwp/jdwp_handler.cc
@@ -65,7 +65,7 @@
 static JdwpError WriteTaggedObject(ExpandBuf* reply, ObjectId object_id)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   uint8_t tag;
-  JdwpError rc = Dbg::GetObjectTag(object_id, tag);
+  JdwpError rc = Dbg::GetObjectTag(object_id, &tag);
   if (rc == ERR_NONE) {
     expandBufAdd1(reply, tag);
     expandBufAddObjectId(reply, object_id);
@@ -91,13 +91,13 @@
  * If "is_constructor" is set, this returns "object_id" rather than the
  * expected-to-be-void return value of the called function.
  */
-static JdwpError FinishInvoke(JdwpState*, Request& request, ExpandBuf* pReply,
+static JdwpError FinishInvoke(JdwpState*, Request* request, ExpandBuf* pReply,
                               ObjectId thread_id, ObjectId object_id,
                               RefTypeId class_id, MethodId method_id, bool is_constructor)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   CHECK(!is_constructor || object_id != 0);
 
-  int32_t arg_count = request.ReadSigned32("argument count");
+  int32_t arg_count = request->ReadSigned32("argument count");
 
   VLOG(jdwp) << StringPrintf("    --> thread_id=%#" PRIx64 " object_id=%#" PRIx64,
                              thread_id, object_id);
@@ -109,14 +109,14 @@
   std::unique_ptr<JdwpTag[]> argTypes(arg_count > 0 ? new JdwpTag[arg_count] : NULL);
   std::unique_ptr<uint64_t[]> argValues(arg_count > 0 ? new uint64_t[arg_count] : NULL);
   for (int32_t i = 0; i < arg_count; ++i) {
-    argTypes[i] = request.ReadTag();
+    argTypes[i] = request->ReadTag();
     size_t width = Dbg::GetTagWidth(argTypes[i]);
-    argValues[i] = request.ReadValue(width);
+    argValues[i] = request->ReadValue(width);
     VLOG(jdwp) << "          " << argTypes[i] << StringPrintf("(%zd): %#" PRIx64, width,
                                                               argValues[i]);
   }
 
-  uint32_t options = request.ReadUnsigned32("InvokeOptions bit flags");
+  uint32_t options = request->ReadUnsigned32("InvokeOptions bit flags");
   VLOG(jdwp) << StringPrintf("        options=0x%04x%s%s", options,
                              (options & INVOKE_SINGLE_THREADED) ? " (SINGLE_THREADED)" : "",
                              (options & INVOKE_NONVIRTUAL) ? " (NONVIRTUAL)" : "");
@@ -161,7 +161,7 @@
   return err;
 }
 
-static JdwpError VM_Version(JdwpState*, Request&, ExpandBuf* pReply)
+static JdwpError VM_Version(JdwpState*, Request*, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   // Text information on runtime version.
   std::string version(StringPrintf("Android Runtime %s", Runtime::Current()->GetVersion()));
@@ -185,12 +185,12 @@
  * referenceTypeID.  We need to send back more than one if the class has
  * been loaded by multiple class loaders.
  */
-static JdwpError VM_ClassesBySignature(JdwpState*, Request& request, ExpandBuf* pReply)
+static JdwpError VM_ClassesBySignature(JdwpState*, Request* request, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  std::string classDescriptor(request.ReadUtf8String());
+  std::string classDescriptor(request->ReadUtf8String());
 
   std::vector<RefTypeId> ids;
-  Dbg::FindLoadedClassBySignature(classDescriptor.c_str(), ids);
+  Dbg::FindLoadedClassBySignature(classDescriptor.c_str(), &ids);
 
   expandBufAdd4BE(pReply, ids.size());
 
@@ -217,10 +217,10 @@
  * We exclude ourselves from the list, because we don't allow ourselves
  * to be suspended, and that violates some JDWP expectations.
  */
-static JdwpError VM_AllThreads(JdwpState*, Request&, ExpandBuf* pReply)
+static JdwpError VM_AllThreads(JdwpState*, Request*, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   std::vector<ObjectId> thread_ids;
-  Dbg::GetThreads(0, thread_ids);
+  Dbg::GetThreads(0, &thread_ids);
 
   expandBufAdd4BE(pReply, thread_ids.size());
   for (uint32_t i = 0; i < thread_ids.size(); ++i) {
@@ -233,7 +233,7 @@
 /*
  * List all thread groups that do not have a parent.
  */
-static JdwpError VM_TopLevelThreadGroups(JdwpState*, Request&, ExpandBuf* pReply)
+static JdwpError VM_TopLevelThreadGroups(JdwpState*, Request*, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   /*
    * TODO: maintain a list of parentless thread groups in the VM.
@@ -254,7 +254,7 @@
  *
  * All IDs are 8 bytes.
  */
-static JdwpError VM_IDSizes(JdwpState*, Request&, ExpandBuf* pReply)
+static JdwpError VM_IDSizes(JdwpState*, Request*, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   expandBufAdd4BE(pReply, sizeof(FieldId));
   expandBufAdd4BE(pReply, sizeof(MethodId));
@@ -264,7 +264,7 @@
   return ERR_NONE;
 }
 
-static JdwpError VM_Dispose(JdwpState*, Request&, ExpandBuf*)
+static JdwpError VM_Dispose(JdwpState*, Request*, ExpandBuf*)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   Dbg::Disposed();
   return ERR_NONE;
@@ -276,7 +276,7 @@
  *
  * This needs to increment the "suspend count" on all threads.
  */
-static JdwpError VM_Suspend(JdwpState*, Request&, ExpandBuf*)
+static JdwpError VM_Suspend(JdwpState*, Request*, ExpandBuf*)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   Thread* self = Thread::Current();
   self->TransitionFromRunnableToSuspended(kWaitingForDebuggerSuspension);
@@ -288,16 +288,16 @@
 /*
  * Resume execution.  Decrements the "suspend count" of all threads.
  */
-static JdwpError VM_Resume(JdwpState*, Request&, ExpandBuf*)
+static JdwpError VM_Resume(JdwpState*, Request*, ExpandBuf*)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   Dbg::ProcessDelayedFullUndeoptimizations();
   Dbg::ResumeVM();
   return ERR_NONE;
 }
 
-static JdwpError VM_Exit(JdwpState* state, Request& request, ExpandBuf*)
+static JdwpError VM_Exit(JdwpState* state, Request* request, ExpandBuf*)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  uint32_t exit_status = request.ReadUnsigned32("exit_status");
+  uint32_t exit_status = request->ReadUnsigned32("exit_status");
   state->ExitAfterReplying(exit_status);
   return ERR_NONE;
 }
@@ -308,9 +308,9 @@
  * (Ctrl-Shift-I in Eclipse on an array of objects causes it to create the
  * string "java.util.Arrays".)
  */
-static JdwpError VM_CreateString(JdwpState*, Request& request, ExpandBuf* pReply)
+static JdwpError VM_CreateString(JdwpState*, Request* request, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  std::string str(request.ReadUtf8String());
+  std::string str(request->ReadUtf8String());
   ObjectId stringId = Dbg::CreateString(str);
   if (stringId == 0) {
     return ERR_OUT_OF_MEMORY;
@@ -319,7 +319,7 @@
   return ERR_NONE;
 }
 
-static JdwpError VM_ClassPaths(JdwpState*, Request&, ExpandBuf* pReply)
+static JdwpError VM_ClassPaths(JdwpState*, Request*, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   expandBufAddUtf8String(pReply, "/");
 
@@ -340,18 +340,18 @@
   return ERR_NONE;
 }
 
-static JdwpError VM_DisposeObjects(JdwpState*, Request& request, ExpandBuf*)
+static JdwpError VM_DisposeObjects(JdwpState*, Request* request, ExpandBuf*)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  size_t object_count = request.ReadUnsigned32("object_count");
+  size_t object_count = request->ReadUnsigned32("object_count");
   for (size_t i = 0; i < object_count; ++i) {
-    ObjectId object_id = request.ReadObjectId();
-    uint32_t reference_count = request.ReadUnsigned32("reference_count");
+    ObjectId object_id = request->ReadObjectId();
+    uint32_t reference_count = request->ReadUnsigned32("reference_count");
     Dbg::DisposeObject(object_id, reference_count);
   }
   return ERR_NONE;
 }
 
-static JdwpError VM_Capabilities(JdwpState*, Request&, ExpandBuf* reply)
+static JdwpError VM_Capabilities(JdwpState*, Request*, ExpandBuf* reply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   expandBufAdd1(reply, true);    // canWatchFieldModification
   expandBufAdd1(reply, true);    // canWatchFieldAccess
@@ -363,7 +363,7 @@
   return ERR_NONE;
 }
 
-static JdwpError VM_CapabilitiesNew(JdwpState*, Request& request, ExpandBuf* reply)
+static JdwpError VM_CapabilitiesNew(JdwpState*, Request* request, ExpandBuf* reply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   // The first few capabilities are the same as those reported by the older call.
   VM_Capabilities(NULL, request, reply);
@@ -393,7 +393,7 @@
 static JdwpError VM_AllClassesImpl(ExpandBuf* pReply, bool descriptor_and_status, bool generic)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   std::vector<JDWP::RefTypeId> classes;
-  Dbg::GetClassList(classes);
+  Dbg::GetClassList(&classes);
 
   expandBufAdd4BE(pReply, classes.size());
 
@@ -421,29 +421,29 @@
   return ERR_NONE;
 }
 
-static JdwpError VM_AllClasses(JdwpState*, Request&, ExpandBuf* pReply)
+static JdwpError VM_AllClasses(JdwpState*, Request*, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   return VM_AllClassesImpl(pReply, true, false);
 }
 
-static JdwpError VM_AllClassesWithGeneric(JdwpState*, Request&, ExpandBuf* pReply)
+static JdwpError VM_AllClassesWithGeneric(JdwpState*, Request*, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   return VM_AllClassesImpl(pReply, true, true);
 }
 
-static JdwpError VM_InstanceCounts(JdwpState*, Request& request, ExpandBuf* pReply)
+static JdwpError VM_InstanceCounts(JdwpState*, Request* request, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  int32_t class_count = request.ReadSigned32("class count");
+  int32_t class_count = request->ReadSigned32("class count");
   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(request.ReadRefTypeId());
+    class_ids.push_back(request->ReadRefTypeId());
   }
 
   std::vector<uint64_t> counts;
-  JdwpError rc = Dbg::GetInstanceCounts(class_ids, counts);
+  JdwpError rc = Dbg::GetInstanceCounts(class_ids, &counts);
   if (rc != ERR_NONE) {
     return rc;
   }
@@ -455,22 +455,22 @@
   return ERR_NONE;
 }
 
-static JdwpError RT_Modifiers(JdwpState*, Request& request, ExpandBuf* pReply)
+static JdwpError RT_Modifiers(JdwpState*, Request* request, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  RefTypeId refTypeId = request.ReadRefTypeId();
+  RefTypeId refTypeId = request->ReadRefTypeId();
   return Dbg::GetModifiers(refTypeId, pReply);
 }
 
 /*
  * Get values from static fields in a reference type.
  */
-static JdwpError RT_GetValues(JdwpState*, Request& request, ExpandBuf* pReply)
+static JdwpError RT_GetValues(JdwpState*, Request* request, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  RefTypeId refTypeId = request.ReadRefTypeId();
-  int32_t field_count = request.ReadSigned32("field count");
+  RefTypeId refTypeId = request->ReadRefTypeId();
+  int32_t field_count = request->ReadSigned32("field count");
   expandBufAdd4BE(pReply, field_count);
   for (int32_t i = 0; i < field_count; ++i) {
-    FieldId fieldId = request.ReadFieldId();
+    FieldId fieldId = request->ReadFieldId();
     JdwpError status = Dbg::GetStaticFieldValue(refTypeId, fieldId, pReply);
     if (status != ERR_NONE) {
       return status;
@@ -482,11 +482,11 @@
 /*
  * Get the name of the source file in which a reference type was declared.
  */
-static JdwpError RT_SourceFile(JdwpState*, Request& request, ExpandBuf* pReply)
+static JdwpError RT_SourceFile(JdwpState*, Request* request, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  RefTypeId refTypeId = request.ReadRefTypeId();
+  RefTypeId refTypeId = request->ReadRefTypeId();
   std::string source_file;
-  JdwpError status = Dbg::GetSourceFile(refTypeId, source_file);
+  JdwpError status = Dbg::GetSourceFile(refTypeId, &source_file);
   if (status != ERR_NONE) {
     return status;
   }
@@ -497,9 +497,9 @@
 /*
  * Return the current status of the reference type.
  */
-static JdwpError RT_Status(JdwpState*, Request& request, ExpandBuf* pReply)
+static JdwpError RT_Status(JdwpState*, Request* request, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  RefTypeId refTypeId = request.ReadRefTypeId();
+  RefTypeId refTypeId = request->ReadRefTypeId();
   JDWP::JdwpTypeTag type_tag;
   uint32_t class_status;
   JDWP::JdwpError status = Dbg::GetClassInfo(refTypeId, &type_tag, &class_status, NULL);
@@ -513,20 +513,20 @@
 /*
  * Return interfaces implemented directly by this class.
  */
-static JdwpError RT_Interfaces(JdwpState*, Request& request, ExpandBuf* pReply)
+static JdwpError RT_Interfaces(JdwpState*, Request* request, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  RefTypeId refTypeId = request.ReadRefTypeId();
+  RefTypeId refTypeId = request->ReadRefTypeId();
   return Dbg::OutputDeclaredInterfaces(refTypeId, pReply);
 }
 
 /*
  * Return the class object corresponding to this type.
  */
-static JdwpError RT_ClassObject(JdwpState*, Request& request, ExpandBuf* pReply)
+static JdwpError RT_ClassObject(JdwpState*, Request* request, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  RefTypeId refTypeId = request.ReadRefTypeId();
+  RefTypeId refTypeId = request->ReadRefTypeId();
   ObjectId class_object_id;
-  JdwpError status = Dbg::GetClassObject(refTypeId, class_object_id);
+  JdwpError status = Dbg::GetClassObject(refTypeId, &class_object_id);
   if (status != ERR_NONE) {
     return status;
   }
@@ -540,15 +540,15 @@
  *
  * JDB seems interested, but DEX files don't currently support this.
  */
-static JdwpError RT_SourceDebugExtension(JdwpState*, Request&, ExpandBuf*)
+static JdwpError RT_SourceDebugExtension(JdwpState*, Request*, ExpandBuf*)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   /* referenceTypeId in, string out */
   return ERR_ABSENT_INFORMATION;
 }
 
-static JdwpError RT_Signature(JdwpState*, Request& request, ExpandBuf* pReply, bool with_generic)
+static JdwpError RT_Signature(JdwpState*, Request* request, ExpandBuf* pReply, bool with_generic)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  RefTypeId refTypeId = request.ReadRefTypeId();
+  RefTypeId refTypeId = request->ReadRefTypeId();
 
   std::string signature;
   JdwpError status = Dbg::GetSignature(refTypeId, &signature);
@@ -562,12 +562,12 @@
   return ERR_NONE;
 }
 
-static JdwpError RT_Signature(JdwpState* state, Request& request, ExpandBuf* pReply)
+static JdwpError RT_Signature(JdwpState* state, Request* request, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   return RT_Signature(state, request, pReply, false);
 }
 
-static JdwpError RT_SignatureWithGeneric(JdwpState* state, Request& request, ExpandBuf* pReply)
+static JdwpError RT_SignatureWithGeneric(JdwpState* state, Request* request, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   return RT_Signature(state, request, pReply, true);
 }
@@ -576,9 +576,9 @@
  * Return the instance of java.lang.ClassLoader that loaded the specified
  * reference type, or null if it was loaded by the system loader.
  */
-static JdwpError RT_ClassLoader(JdwpState*, Request& request, ExpandBuf* pReply)
+static JdwpError RT_ClassLoader(JdwpState*, Request* request, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  RefTypeId refTypeId = request.ReadRefTypeId();
+  RefTypeId refTypeId = request->ReadRefTypeId();
   return Dbg::GetClassLoader(refTypeId, pReply);
 }
 
@@ -586,16 +586,16 @@
  * Given a referenceTypeId, return a block of stuff that describes the
  * fields declared by a class.
  */
-static JdwpError RT_FieldsWithGeneric(JdwpState*, Request& request, ExpandBuf* pReply)
+static JdwpError RT_FieldsWithGeneric(JdwpState*, Request* request, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  RefTypeId refTypeId = request.ReadRefTypeId();
+  RefTypeId refTypeId = request->ReadRefTypeId();
   return Dbg::OutputDeclaredFields(refTypeId, true, pReply);
 }
 
 // Obsolete equivalent of FieldsWithGeneric, without the generic type information.
-static JdwpError RT_Fields(JdwpState*, Request& request, ExpandBuf* pReply)
+static JdwpError RT_Fields(JdwpState*, Request* request, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  RefTypeId refTypeId = request.ReadRefTypeId();
+  RefTypeId refTypeId = request->ReadRefTypeId();
   return Dbg::OutputDeclaredFields(refTypeId, false, pReply);
 }
 
@@ -603,29 +603,29 @@
  * Given a referenceTypeID, return a block of goodies describing the
  * methods declared by a class.
  */
-static JdwpError RT_MethodsWithGeneric(JdwpState*, Request& request, ExpandBuf* pReply)
+static JdwpError RT_MethodsWithGeneric(JdwpState*, Request* request, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  RefTypeId refTypeId = request.ReadRefTypeId();
+  RefTypeId refTypeId = request->ReadRefTypeId();
   return Dbg::OutputDeclaredMethods(refTypeId, true, pReply);
 }
 
 // Obsolete equivalent of MethodsWithGeneric, without the generic type information.
-static JdwpError RT_Methods(JdwpState*, Request& request, ExpandBuf* pReply)
+static JdwpError RT_Methods(JdwpState*, Request* request, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  RefTypeId refTypeId = request.ReadRefTypeId();
+  RefTypeId refTypeId = request->ReadRefTypeId();
   return Dbg::OutputDeclaredMethods(refTypeId, false, pReply);
 }
 
-static JdwpError RT_Instances(JdwpState*, Request& request, ExpandBuf* reply)
+static JdwpError RT_Instances(JdwpState*, Request* request, ExpandBuf* reply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  RefTypeId class_id = request.ReadRefTypeId();
-  int32_t max_count = request.ReadSigned32("max count");
+  RefTypeId class_id = request->ReadRefTypeId();
+  int32_t max_count = request->ReadSigned32("max count");
   if (max_count < 0) {
     return ERR_ILLEGAL_ARGUMENT;
   }
 
   std::vector<ObjectId> instances;
-  JdwpError rc = Dbg::GetInstances(class_id, max_count, instances);
+  JdwpError rc = Dbg::GetInstances(class_id, max_count, &instances);
   if (rc != ERR_NONE) {
     return rc;
   }
@@ -636,11 +636,11 @@
 /*
  * Return the immediate superclass of a class.
  */
-static JdwpError CT_Superclass(JdwpState*, Request& request, ExpandBuf* pReply)
+static JdwpError CT_Superclass(JdwpState*, Request* request, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  RefTypeId class_id = request.ReadRefTypeId();
+  RefTypeId class_id = request->ReadRefTypeId();
   RefTypeId superClassId;
-  JdwpError status = Dbg::GetSuperclass(class_id, superClassId);
+  JdwpError status = Dbg::GetSuperclass(class_id, &superClassId);
   if (status != ERR_NONE) {
     return status;
   }
@@ -651,18 +651,18 @@
 /*
  * Set static class values.
  */
-static JdwpError CT_SetValues(JdwpState* , Request& request, ExpandBuf*)
+static JdwpError CT_SetValues(JdwpState* , Request* request, ExpandBuf*)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  RefTypeId class_id = request.ReadRefTypeId();
-  int32_t values_count = request.ReadSigned32("values count");
+  RefTypeId class_id = request->ReadRefTypeId();
+  int32_t values_count = request->ReadSigned32("values count");
 
   UNUSED(class_id);
 
   for (int32_t i = 0; i < values_count; ++i) {
-    FieldId fieldId = request.ReadFieldId();
+    FieldId fieldId = request->ReadFieldId();
     JDWP::JdwpTag fieldTag = Dbg::GetStaticFieldBasicTag(fieldId);
     size_t width = Dbg::GetTagWidth(fieldTag);
-    uint64_t value = request.ReadValue(width);
+    uint64_t value = request->ReadValue(width);
 
     VLOG(jdwp) << "    --> field=" << fieldId << " tag=" << fieldTag << " --> " << value;
     JdwpError status = Dbg::SetStaticFieldValue(fieldId, value, width);
@@ -680,11 +680,11 @@
  * Example: Eclipse sometimes uses java/lang/Class.forName(String s) on
  * values in the "variables" display.
  */
-static JdwpError CT_InvokeMethod(JdwpState* state, Request& request, ExpandBuf* pReply)
+static JdwpError CT_InvokeMethod(JdwpState* state, Request* request, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  RefTypeId class_id = request.ReadRefTypeId();
-  ObjectId thread_id = request.ReadThreadId();
-  MethodId method_id = request.ReadMethodId();
+  RefTypeId class_id = request->ReadRefTypeId();
+  ObjectId thread_id = request->ReadThreadId();
+  MethodId method_id = request->ReadMethodId();
 
   return FinishInvoke(state, request, pReply, thread_id, 0, class_id, method_id, false);
 }
@@ -696,14 +696,14 @@
  * Example: in IntelliJ, create a watch on "new String(myByteArray)" to
  * see the contents of a byte[] as a string.
  */
-static JdwpError CT_NewInstance(JdwpState* state, Request& request, ExpandBuf* pReply)
+static JdwpError CT_NewInstance(JdwpState* state, Request* request, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  RefTypeId class_id = request.ReadRefTypeId();
-  ObjectId thread_id = request.ReadThreadId();
-  MethodId method_id = request.ReadMethodId();
+  RefTypeId class_id = request->ReadRefTypeId();
+  ObjectId thread_id = request->ReadThreadId();
+  MethodId method_id = request->ReadMethodId();
 
   ObjectId object_id;
-  JdwpError status = Dbg::CreateObject(class_id, object_id);
+  JdwpError status = Dbg::CreateObject(class_id, &object_id);
   if (status != ERR_NONE) {
     return status;
   }
@@ -716,13 +716,13 @@
 /*
  * Create a new array object of the requested type and length.
  */
-static JdwpError AT_newInstance(JdwpState*, Request& request, ExpandBuf* pReply)
+static JdwpError AT_newInstance(JdwpState*, Request* request, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  RefTypeId arrayTypeId = request.ReadRefTypeId();
-  int32_t length = request.ReadSigned32("length");
+  RefTypeId arrayTypeId = request->ReadRefTypeId();
+  int32_t length = request->ReadSigned32("length");
 
   ObjectId object_id;
-  JdwpError status = Dbg::CreateArrayObject(arrayTypeId, length, object_id);
+  JdwpError status = Dbg::CreateArrayObject(arrayTypeId, length, &object_id);
   if (status != ERR_NONE) {
     return status;
   }
@@ -737,21 +737,21 @@
 /*
  * Return line number information for the method, if present.
  */
-static JdwpError M_LineTable(JdwpState*, Request& request, ExpandBuf* pReply)
+static JdwpError M_LineTable(JdwpState*, Request* request, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  RefTypeId refTypeId = request.ReadRefTypeId();
-  MethodId method_id = request.ReadMethodId();
+  RefTypeId refTypeId = request->ReadRefTypeId();
+  MethodId method_id = request->ReadMethodId();
 
   Dbg::OutputLineTable(refTypeId, method_id, pReply);
 
   return ERR_NONE;
 }
 
-static JdwpError M_VariableTable(JdwpState*, Request& request, ExpandBuf* pReply,
+static JdwpError M_VariableTable(JdwpState*, Request* request, ExpandBuf* pReply,
                                  bool generic)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  RefTypeId class_id = request.ReadRefTypeId();
-  MethodId method_id = request.ReadMethodId();
+  RefTypeId class_id = request->ReadRefTypeId();
+  MethodId method_id = request->ReadMethodId();
 
   // We could return ERR_ABSENT_INFORMATION here if the DEX file was built without local variable
   // information. That will cause Eclipse to make a best-effort attempt at displaying local
@@ -761,23 +761,23 @@
   return ERR_NONE;
 }
 
-static JdwpError M_VariableTable(JdwpState* state, Request& request, ExpandBuf* pReply)
+static JdwpError M_VariableTable(JdwpState* state, Request* request, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   return M_VariableTable(state, request, pReply, false);
 }
 
-static JdwpError M_VariableTableWithGeneric(JdwpState* state, Request& request, ExpandBuf* pReply)
+static JdwpError M_VariableTableWithGeneric(JdwpState* state, Request* request, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   return M_VariableTable(state, request, pReply, true);
 }
 
-static JdwpError M_Bytecodes(JdwpState*, Request& request, ExpandBuf* reply)
+static JdwpError M_Bytecodes(JdwpState*, Request* request, ExpandBuf* reply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  RefTypeId class_id = request.ReadRefTypeId();
-  MethodId method_id = request.ReadMethodId();
+  RefTypeId class_id = request->ReadRefTypeId();
+  MethodId method_id = request->ReadMethodId();
 
   std::vector<uint8_t> bytecodes;
-  JdwpError rc = Dbg::GetBytecodes(class_id, method_id, bytecodes);
+  JdwpError rc = Dbg::GetBytecodes(class_id, method_id, &bytecodes);
   if (rc != ERR_NONE) {
     return rc;
   }
@@ -797,23 +797,23 @@
  * This can get called on different things, e.g. thread_id gets
  * passed in here.
  */
-static JdwpError OR_ReferenceType(JdwpState*, Request& request, ExpandBuf* pReply)
+static JdwpError OR_ReferenceType(JdwpState*, Request* request, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ObjectId object_id = request.ReadObjectId();
+  ObjectId object_id = request->ReadObjectId();
   return Dbg::GetReferenceType(object_id, pReply);
 }
 
 /*
  * Get values from the fields of an object.
  */
-static JdwpError OR_GetValues(JdwpState*, Request& request, ExpandBuf* pReply)
+static JdwpError OR_GetValues(JdwpState*, Request* request, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ObjectId object_id = request.ReadObjectId();
-  int32_t field_count = request.ReadSigned32("field count");
+  ObjectId object_id = request->ReadObjectId();
+  int32_t field_count = request->ReadSigned32("field count");
 
   expandBufAdd4BE(pReply, field_count);
   for (int32_t i = 0; i < field_count; ++i) {
-    FieldId fieldId = request.ReadFieldId();
+    FieldId fieldId = request->ReadFieldId();
     JdwpError status = Dbg::GetFieldValue(object_id, fieldId, pReply);
     if (status != ERR_NONE) {
       return status;
@@ -826,17 +826,17 @@
 /*
  * Set values in the fields of an object.
  */
-static JdwpError OR_SetValues(JdwpState*, Request& request, ExpandBuf*)
+static JdwpError OR_SetValues(JdwpState*, Request* request, ExpandBuf*)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ObjectId object_id = request.ReadObjectId();
-  int32_t field_count = request.ReadSigned32("field count");
+  ObjectId object_id = request->ReadObjectId();
+  int32_t field_count = request->ReadSigned32("field count");
 
   for (int32_t i = 0; i < field_count; ++i) {
-    FieldId fieldId = request.ReadFieldId();
+    FieldId fieldId = request->ReadFieldId();
 
     JDWP::JdwpTag fieldTag = Dbg::GetFieldBasicTag(fieldId);
     size_t width = Dbg::GetTagWidth(fieldTag);
-    uint64_t value = request.ReadValue(width);
+    uint64_t value = request->ReadValue(width);
 
     VLOG(jdwp) << "    --> fieldId=" << fieldId << " tag=" << fieldTag << "(" << width << ") value=" << value;
     JdwpError status = Dbg::SetFieldValue(object_id, fieldId, value, width);
@@ -848,9 +848,9 @@
   return ERR_NONE;
 }
 
-static JdwpError OR_MonitorInfo(JdwpState*, Request& request, ExpandBuf* reply)
+static JdwpError OR_MonitorInfo(JdwpState*, Request* request, ExpandBuf* reply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ObjectId object_id = request.ReadObjectId();
+  ObjectId object_id = request->ReadObjectId();
   return Dbg::GetMonitorInfo(object_id, reply);
 }
 
@@ -865,47 +865,47 @@
  * object), it will try to invoke the object's toString() function.  This
  * feature becomes crucial when examining ArrayLists with Eclipse.
  */
-static JdwpError OR_InvokeMethod(JdwpState* state, Request& request, ExpandBuf* pReply)
+static JdwpError OR_InvokeMethod(JdwpState* state, Request* request, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ObjectId object_id = request.ReadObjectId();
-  ObjectId thread_id = request.ReadThreadId();
-  RefTypeId class_id = request.ReadRefTypeId();
-  MethodId method_id = request.ReadMethodId();
+  ObjectId object_id = request->ReadObjectId();
+  ObjectId thread_id = request->ReadThreadId();
+  RefTypeId class_id = request->ReadRefTypeId();
+  MethodId method_id = request->ReadMethodId();
 
   return FinishInvoke(state, request, pReply, thread_id, object_id, class_id, method_id, false);
 }
 
-static JdwpError OR_DisableCollection(JdwpState*, Request& request, ExpandBuf*)
+static JdwpError OR_DisableCollection(JdwpState*, Request* request, ExpandBuf*)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ObjectId object_id = request.ReadObjectId();
+  ObjectId object_id = request->ReadObjectId();
   return Dbg::DisableCollection(object_id);
 }
 
-static JdwpError OR_EnableCollection(JdwpState*, Request& request, ExpandBuf*)
+static JdwpError OR_EnableCollection(JdwpState*, Request* request, ExpandBuf*)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ObjectId object_id = request.ReadObjectId();
+  ObjectId object_id = request->ReadObjectId();
   return Dbg::EnableCollection(object_id);
 }
 
-static JdwpError OR_IsCollected(JdwpState*, Request& request, ExpandBuf* pReply)
+static JdwpError OR_IsCollected(JdwpState*, Request* request, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ObjectId object_id = request.ReadObjectId();
+  ObjectId object_id = request->ReadObjectId();
   bool is_collected;
-  JdwpError rc = Dbg::IsCollected(object_id, is_collected);
+  JdwpError rc = Dbg::IsCollected(object_id, &is_collected);
   expandBufAdd1(pReply, is_collected ? 1 : 0);
   return rc;
 }
 
-static JdwpError OR_ReferringObjects(JdwpState*, Request& request, ExpandBuf* reply)
+static JdwpError OR_ReferringObjects(JdwpState*, Request* request, ExpandBuf* reply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ObjectId object_id = request.ReadObjectId();
-  int32_t max_count = request.ReadSigned32("max count");
+  ObjectId object_id = request->ReadObjectId();
+  int32_t max_count = request->ReadSigned32("max count");
   if (max_count < 0) {
     return ERR_ILLEGAL_ARGUMENT;
   }
 
   std::vector<ObjectId> referring_objects;
-  JdwpError rc = Dbg::GetReferringObjects(object_id, max_count, referring_objects);
+  JdwpError rc = Dbg::GetReferringObjects(object_id, max_count, &referring_objects);
   if (rc != ERR_NONE) {
     return rc;
   }
@@ -916,9 +916,9 @@
 /*
  * Return the string value in a string object.
  */
-static JdwpError SR_Value(JdwpState*, Request& request, ExpandBuf* pReply)
+static JdwpError SR_Value(JdwpState*, Request* request, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ObjectId stringObject = request.ReadObjectId();
+  ObjectId stringObject = request->ReadObjectId();
   std::string str(Dbg::StringToUtf8(stringObject));
 
   VLOG(jdwp) << StringPrintf("    --> %s", PrintableString(str.c_str()).c_str());
@@ -931,12 +931,12 @@
 /*
  * Return a thread's name.
  */
-static JdwpError TR_Name(JdwpState*, Request& request, ExpandBuf* pReply)
+static JdwpError TR_Name(JdwpState*, Request* request, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ObjectId thread_id = request.ReadThreadId();
+  ObjectId thread_id = request->ReadThreadId();
 
   std::string name;
-  JdwpError error = Dbg::GetThreadName(thread_id, name);
+  JdwpError error = Dbg::GetThreadName(thread_id, &name);
   if (error != ERR_NONE) {
     return error;
   }
@@ -952,9 +952,9 @@
  * It's supposed to remain suspended even if interpreted code wants to
  * resume it; only the JDI is allowed to resume it.
  */
-static JdwpError TR_Suspend(JdwpState*, Request& request, ExpandBuf*)
+static JdwpError TR_Suspend(JdwpState*, Request* request, ExpandBuf*)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ObjectId thread_id = request.ReadThreadId();
+  ObjectId thread_id = request->ReadThreadId();
 
   if (thread_id == Dbg::GetThreadSelfId()) {
     LOG(INFO) << "  Warning: ignoring request to suspend self";
@@ -971,9 +971,9 @@
 /*
  * Resume the specified thread.
  */
-static JdwpError TR_Resume(JdwpState*, Request& request, ExpandBuf*)
+static JdwpError TR_Resume(JdwpState*, Request* request, ExpandBuf*)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ObjectId thread_id = request.ReadThreadId();
+  ObjectId thread_id = request->ReadThreadId();
 
   if (thread_id == Dbg::GetThreadSelfId()) {
     LOG(INFO) << "  Warning: ignoring request to resume self";
@@ -989,9 +989,9 @@
 /*
  * Return status of specified thread.
  */
-static JdwpError TR_Status(JdwpState*, Request& request, ExpandBuf* pReply)
+static JdwpError TR_Status(JdwpState*, Request* request, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ObjectId thread_id = request.ReadThreadId();
+  ObjectId thread_id = request->ReadThreadId();
 
   JDWP::JdwpThreadStatus threadStatus;
   JDWP::JdwpSuspendStatus suspendStatus;
@@ -1011,9 +1011,9 @@
 /*
  * Return the thread group that the specified thread is a member of.
  */
-static JdwpError TR_ThreadGroup(JdwpState*, Request& request, ExpandBuf* pReply)
+static JdwpError TR_ThreadGroup(JdwpState*, Request* request, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ObjectId thread_id = request.ReadThreadId();
+  ObjectId thread_id = request->ReadThreadId();
   return Dbg::GetThreadGroup(thread_id, pReply);
 }
 
@@ -1023,14 +1023,14 @@
  * If the thread isn't suspended, the error code isn't defined, but should
  * be THREAD_NOT_SUSPENDED.
  */
-static JdwpError TR_Frames(JdwpState*, Request& request, ExpandBuf* pReply)
+static JdwpError TR_Frames(JdwpState*, Request* request, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ObjectId thread_id = request.ReadThreadId();
-  uint32_t start_frame = request.ReadUnsigned32("start frame");
-  uint32_t length = request.ReadUnsigned32("length");
+  ObjectId thread_id = request->ReadThreadId();
+  uint32_t start_frame = request->ReadUnsigned32("start frame");
+  uint32_t length = request->ReadUnsigned32("length");
 
   size_t actual_frame_count;
-  JdwpError error = Dbg::GetThreadFrameCount(thread_id, actual_frame_count);
+  JdwpError error = Dbg::GetThreadFrameCount(thread_id, &actual_frame_count);
   if (error != ERR_NONE) {
     return error;
   }
@@ -1055,12 +1055,12 @@
 /*
  * Returns the #of frames on the specified thread, which must be suspended.
  */
-static JdwpError TR_FrameCount(JdwpState*, Request& request, ExpandBuf* pReply)
+static JdwpError TR_FrameCount(JdwpState*, Request* request, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ObjectId thread_id = request.ReadThreadId();
+  ObjectId thread_id = request->ReadThreadId();
 
   size_t frame_count;
-  JdwpError rc = Dbg::GetThreadFrameCount(thread_id, frame_count);
+  JdwpError rc = Dbg::GetThreadFrameCount(thread_id, &frame_count);
   if (rc != ERR_NONE) {
     return rc;
   }
@@ -1069,13 +1069,13 @@
   return ERR_NONE;
 }
 
-static JdwpError TR_OwnedMonitors(Request& request, ExpandBuf* reply, bool with_stack_depths)
+static JdwpError TR_OwnedMonitors(Request* request, ExpandBuf* reply, bool with_stack_depths)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ObjectId thread_id = request.ReadThreadId();
+  ObjectId thread_id = request->ReadThreadId();
 
   std::vector<ObjectId> monitors;
   std::vector<uint32_t> stack_depths;
-  JdwpError rc = Dbg::GetOwnedMonitors(thread_id, monitors, stack_depths);
+  JdwpError rc = Dbg::GetOwnedMonitors(thread_id, &monitors, &stack_depths);
   if (rc != ERR_NONE) {
     return rc;
   }
@@ -1093,31 +1093,31 @@
   return ERR_NONE;
 }
 
-static JdwpError TR_OwnedMonitors(JdwpState*, Request& request, ExpandBuf* reply)
+static JdwpError TR_OwnedMonitors(JdwpState*, Request* request, ExpandBuf* reply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   return TR_OwnedMonitors(request, reply, false);
 }
 
-static JdwpError TR_OwnedMonitorsStackDepthInfo(JdwpState*, Request& request, ExpandBuf* reply)
+static JdwpError TR_OwnedMonitorsStackDepthInfo(JdwpState*, Request* request, ExpandBuf* reply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   return TR_OwnedMonitors(request, reply, true);
 }
 
-static JdwpError TR_CurrentContendedMonitor(JdwpState*, Request& request, ExpandBuf* reply)
+static JdwpError TR_CurrentContendedMonitor(JdwpState*, Request* request, ExpandBuf* reply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ObjectId thread_id = request.ReadThreadId();
+  ObjectId thread_id = request->ReadThreadId();
 
   ObjectId contended_monitor;
-  JdwpError rc = Dbg::GetContendedMonitor(thread_id, contended_monitor);
+  JdwpError rc = Dbg::GetContendedMonitor(thread_id, &contended_monitor);
   if (rc != ERR_NONE) {
     return rc;
   }
   return WriteTaggedObject(reply, contended_monitor);
 }
 
-static JdwpError TR_Interrupt(JdwpState*, Request& request, ExpandBuf* reply)
+static JdwpError TR_Interrupt(JdwpState*, Request* request, ExpandBuf* reply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ObjectId thread_id = request.ReadThreadId();
+  ObjectId thread_id = request->ReadThreadId();
   return Dbg::Interrupt(thread_id);
 }
 
@@ -1127,9 +1127,9 @@
  * (The thread *might* still be running -- it might not have examined
  * its suspend count recently.)
  */
-static JdwpError TR_DebugSuspendCount(JdwpState*, Request& request, ExpandBuf* pReply)
+static JdwpError TR_DebugSuspendCount(JdwpState*, Request* request, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ObjectId thread_id = request.ReadThreadId();
+  ObjectId thread_id = request->ReadThreadId();
   return Dbg::GetThreadDebugSuspendCount(thread_id, pReply);
 }
 
@@ -1138,9 +1138,9 @@
  *
  * The Eclipse debugger recognizes "main" and "system" as special.
  */
-static JdwpError TGR_Name(JdwpState*, Request& request, ExpandBuf* pReply)
+static JdwpError TGR_Name(JdwpState*, Request* request, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ObjectId thread_group_id = request.ReadThreadGroupId();
+  ObjectId thread_group_id = request->ReadThreadGroupId();
 
   expandBufAddUtf8String(pReply, Dbg::GetThreadGroupName(thread_group_id));
 
@@ -1151,9 +1151,9 @@
  * Returns the thread group -- if any -- that contains the specified
  * thread group.
  */
-static JdwpError TGR_Parent(JdwpState*, Request& request, ExpandBuf* pReply)
+static JdwpError TGR_Parent(JdwpState*, Request* request, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ObjectId thread_group_id = request.ReadThreadGroupId();
+  ObjectId thread_group_id = request->ReadThreadGroupId();
 
   ObjectId parentGroup = Dbg::GetThreadGroupParent(thread_group_id);
   expandBufAddObjectId(pReply, parentGroup);
@@ -1165,19 +1165,19 @@
  * Return the active threads and thread groups that are part of the
  * specified thread group.
  */
-static JdwpError TGR_Children(JdwpState*, Request& request, ExpandBuf* pReply)
+static JdwpError TGR_Children(JdwpState*, Request* request, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ObjectId thread_group_id = request.ReadThreadGroupId();
+  ObjectId thread_group_id = request->ReadThreadGroupId();
 
   std::vector<ObjectId> thread_ids;
-  Dbg::GetThreads(thread_group_id, thread_ids);
+  Dbg::GetThreads(thread_group_id, &thread_ids);
   expandBufAdd4BE(pReply, thread_ids.size());
   for (uint32_t i = 0; i < thread_ids.size(); ++i) {
     expandBufAddObjectId(pReply, thread_ids[i]);
   }
 
   std::vector<ObjectId> child_thread_groups_ids;
-  Dbg::GetChildThreadGroups(thread_group_id, child_thread_groups_ids);
+  Dbg::GetChildThreadGroups(thread_group_id, &child_thread_groups_ids);
   expandBufAdd4BE(pReply, child_thread_groups_ids.size());
   for (uint32_t i = 0; i < child_thread_groups_ids.size(); ++i) {
     expandBufAddObjectId(pReply, child_thread_groups_ids[i]);
@@ -1189,12 +1189,12 @@
 /*
  * Return the #of components in the array.
  */
-static JdwpError AR_Length(JdwpState*, Request& request, ExpandBuf* pReply)
+static JdwpError AR_Length(JdwpState*, Request* request, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ObjectId array_id = request.ReadArrayId();
+  ObjectId array_id = request->ReadArrayId();
 
-  int length;
-  JdwpError status = Dbg::GetArrayLength(array_id, length);
+  int32_t length;
+  JdwpError status = Dbg::GetArrayLength(array_id, &length);
   if (status != ERR_NONE) {
     return status;
   }
@@ -1208,28 +1208,28 @@
 /*
  * Return the values from an array.
  */
-static JdwpError AR_GetValues(JdwpState*, Request& request, ExpandBuf* pReply)
+static JdwpError AR_GetValues(JdwpState*, Request* request, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ObjectId array_id = request.ReadArrayId();
-  uint32_t offset = request.ReadUnsigned32("offset");
-  uint32_t length = request.ReadUnsigned32("length");
+  ObjectId array_id = request->ReadArrayId();
+  uint32_t offset = request->ReadUnsigned32("offset");
+  uint32_t length = request->ReadUnsigned32("length");
   return Dbg::OutputArray(array_id, offset, length, pReply);
 }
 
 /*
  * Set values in an array.
  */
-static JdwpError AR_SetValues(JdwpState*, Request& request, ExpandBuf*)
+static JdwpError AR_SetValues(JdwpState*, Request* request, ExpandBuf*)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ObjectId array_id = request.ReadArrayId();
-  uint32_t offset = request.ReadUnsigned32("offset");
-  uint32_t count = request.ReadUnsigned32("count");
+  ObjectId array_id = request->ReadArrayId();
+  uint32_t offset = request->ReadUnsigned32("offset");
+  uint32_t count = request->ReadUnsigned32("count");
   return Dbg::SetArrayElements(array_id, offset, count, request);
 }
 
-static JdwpError CLR_VisibleClasses(JdwpState*, Request& request, ExpandBuf* pReply)
+static JdwpError CLR_VisibleClasses(JdwpState*, Request* request, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  request.ReadObjectId();  // classLoaderObject
+  request->ReadObjectId();  // classLoaderObject
   // TODO: we should only return classes which have the given class loader as a defining or
   // initiating loader. The former would be easy; the latter is hard, because we don't have
   // any such notion.
@@ -1241,11 +1241,11 @@
  *
  * Reply with a requestID.
  */
-static JdwpError ER_Set(JdwpState* state, Request& request, ExpandBuf* pReply)
+static JdwpError ER_Set(JdwpState* state, Request* request, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  JdwpEventKind event_kind = request.ReadEnum1<JdwpEventKind>("event kind");
-  JdwpSuspendPolicy suspend_policy = request.ReadEnum1<JdwpSuspendPolicy>("suspend policy");
-  int32_t modifier_count = request.ReadSigned32("modifier count");
+  JdwpEventKind event_kind = request->ReadEnum1<JdwpEventKind>("event kind");
+  JdwpSuspendPolicy suspend_policy = request->ReadEnum1<JdwpSuspendPolicy>("suspend policy");
+  int32_t modifier_count = request->ReadSigned32("modifier count");
 
   CHECK_LT(modifier_count, 256);    /* reasonableness check */
 
@@ -1260,12 +1260,12 @@
    */
   for (int32_t i = 0; i < modifier_count; ++i) {
     JdwpEventMod& mod = pEvent->mods[i];
-    mod.modKind = request.ReadModKind();
+    mod.modKind = request->ReadModKind();
     switch (mod.modKind) {
     case MK_COUNT:
       {
         // Report once, when "--count" reaches 0.
-        uint32_t count = request.ReadUnsigned32("count");
+        uint32_t count = request->ReadUnsigned32("count");
         if (count == 0) {
           return ERR_INVALID_COUNT;
         }
@@ -1275,21 +1275,21 @@
     case MK_CONDITIONAL:
       {
         // Conditional on expression.
-        uint32_t exprId = request.ReadUnsigned32("expr id");
+        uint32_t exprId = request->ReadUnsigned32("expr id");
         mod.conditional.exprId = exprId;
       }
       break;
     case MK_THREAD_ONLY:
       {
         // Only report events in specified thread.
-        ObjectId thread_id = request.ReadThreadId();
+        ObjectId thread_id = request->ReadThreadId();
         mod.threadOnly.threadId = thread_id;
       }
       break;
     case MK_CLASS_ONLY:
       {
         // For ClassPrepare, MethodEntry.
-        RefTypeId class_id = request.ReadRefTypeId();
+        RefTypeId class_id = request->ReadRefTypeId();
         mod.classOnly.refTypeId = class_id;
       }
       break;
@@ -1297,7 +1297,7 @@
       {
         // Restrict events to matching classes.
         // pattern is "java.foo.*", we want "java/foo/*".
-        std::string pattern(request.ReadUtf8String());
+        std::string pattern(request->ReadUtf8String());
         std::replace(pattern.begin(), pattern.end(), '.', '/');
         mod.classMatch.classPattern = strdup(pattern.c_str());
       }
@@ -1306,7 +1306,7 @@
       {
         // Restrict events to non-matching classes.
         // pattern is "java.foo.*", we want "java/foo/*".
-        std::string pattern(request.ReadUtf8String());
+        std::string pattern(request->ReadUtf8String());
         std::replace(pattern.begin(), pattern.end(), '.', '/');
         mod.classExclude.classPattern = strdup(pattern.c_str());
       }
@@ -1314,23 +1314,23 @@
     case MK_LOCATION_ONLY:
       {
         // Restrict certain events based on location.
-        JdwpLocation location = request.ReadLocation();
+        JdwpLocation location = request->ReadLocation();
         mod.locationOnly.loc = location;
       }
       break;
     case MK_EXCEPTION_ONLY:
       {
         // Modifies EK_EXCEPTION events,
-        mod.exceptionOnly.refTypeId = request.ReadRefTypeId();  // null => all exceptions.
-        mod.exceptionOnly.caught = request.ReadEnum1<uint8_t>("caught");
-        mod.exceptionOnly.uncaught = request.ReadEnum1<uint8_t>("uncaught");
+        mod.exceptionOnly.refTypeId = request->ReadRefTypeId();  // null => all exceptions.
+        mod.exceptionOnly.caught = request->ReadEnum1<uint8_t>("caught");
+        mod.exceptionOnly.uncaught = request->ReadEnum1<uint8_t>("uncaught");
       }
       break;
     case MK_FIELD_ONLY:
       {
         // For field access/modification events.
-        RefTypeId declaring = request.ReadRefTypeId();
-        FieldId fieldId = request.ReadFieldId();
+        RefTypeId declaring = request->ReadRefTypeId();
+        FieldId fieldId = request->ReadFieldId();
         mod.fieldOnly.refTypeId = declaring;
         mod.fieldOnly.fieldId = fieldId;
       }
@@ -1338,9 +1338,9 @@
     case MK_STEP:
       {
         // For use with EK_SINGLE_STEP.
-        ObjectId thread_id = request.ReadThreadId();
-        uint32_t size = request.ReadUnsigned32("step size");
-        uint32_t depth = request.ReadUnsigned32("step depth");
+        ObjectId thread_id = request->ReadThreadId();
+        uint32_t size = request->ReadUnsigned32("step size");
+        uint32_t depth = request->ReadUnsigned32("step depth");
         VLOG(jdwp) << StringPrintf("    Step: thread=%#" PRIx64, thread_id)
                      << " size=" << JdwpStepSize(size) << " depth=" << JdwpStepDepth(depth);
 
@@ -1352,7 +1352,7 @@
     case MK_INSTANCE_ONLY:
       {
         // Report events related to a specific object.
-        ObjectId instance = request.ReadObjectId();
+        ObjectId instance = request->ReadObjectId();
         mod.instanceOnly.objectId = instance;
       }
       break;
@@ -1382,10 +1382,10 @@
   return err;
 }
 
-static JdwpError ER_Clear(JdwpState* state, Request& request, ExpandBuf*)
+static JdwpError ER_Clear(JdwpState* state, Request* request, ExpandBuf*)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  request.ReadEnum1<JdwpEventKind>("event kind");
-  uint32_t requestId = request.ReadUnsigned32("request id");
+  request->ReadEnum1<JdwpEventKind>("event kind");
+  uint32_t requestId = request->ReadUnsigned32("request id");
 
   // Failure to find an event with a matching ID is a no-op
   // and does not return an error.
@@ -1396,16 +1396,16 @@
 /*
  * Return the values of arguments and local variables.
  */
-static JdwpError SF_GetValues(JdwpState*, Request& request, ExpandBuf* pReply)
+static JdwpError SF_GetValues(JdwpState*, Request* request, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ObjectId thread_id = request.ReadThreadId();
-  FrameId frame_id = request.ReadFrameId();
-  int32_t slot_count = request.ReadSigned32("slot count");
+  ObjectId thread_id = request->ReadThreadId();
+  FrameId frame_id = request->ReadFrameId();
+  int32_t slot_count = request->ReadSigned32("slot count");
 
   expandBufAdd4BE(pReply, slot_count);     /* "int values" */
   for (int32_t i = 0; i < slot_count; ++i) {
-    uint32_t slot = request.ReadUnsigned32("slot");
-    JDWP::JdwpTag reqSigByte = request.ReadTag();
+    uint32_t slot = request->ReadUnsigned32("slot");
+    JDWP::JdwpTag reqSigByte = request->ReadTag();
 
     VLOG(jdwp) << "    --> slot " << slot << " " << reqSigByte;
 
@@ -1423,17 +1423,17 @@
 /*
  * Set the values of arguments and local variables.
  */
-static JdwpError SF_SetValues(JdwpState*, Request& request, ExpandBuf*)
+static JdwpError SF_SetValues(JdwpState*, Request* request, ExpandBuf*)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ObjectId thread_id = request.ReadThreadId();
-  FrameId frame_id = request.ReadFrameId();
-  int32_t slot_count = request.ReadSigned32("slot count");
+  ObjectId thread_id = request->ReadThreadId();
+  FrameId frame_id = request->ReadFrameId();
+  int32_t slot_count = request->ReadSigned32("slot count");
 
   for (int32_t i = 0; i < slot_count; ++i) {
-    uint32_t slot = request.ReadUnsigned32("slot");
-    JDWP::JdwpTag sigByte = request.ReadTag();
+    uint32_t slot = request->ReadUnsigned32("slot");
+    JDWP::JdwpTag sigByte = request->ReadTag();
     size_t width = Dbg::GetTagWidth(sigByte);
-    uint64_t value = request.ReadValue(width);
+    uint64_t value = request->ReadValue(width);
 
     VLOG(jdwp) << "    --> slot " << slot << " " << sigByte << " " << value;
     JdwpError error = Dbg::SetLocalValue(thread_id, frame_id, slot, sigByte, value, width);
@@ -1445,10 +1445,10 @@
   return ERR_NONE;
 }
 
-static JdwpError SF_ThisObject(JdwpState*, Request& request, ExpandBuf* reply)
+static JdwpError SF_ThisObject(JdwpState*, Request* request, ExpandBuf* reply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ObjectId thread_id = request.ReadThreadId();
-  FrameId frame_id = request.ReadFrameId();
+  ObjectId thread_id = request->ReadThreadId();
+  FrameId frame_id = request->ReadFrameId();
 
   ObjectId object_id;
   JdwpError rc = Dbg::GetThisObject(thread_id, frame_id, &object_id);
@@ -1466,16 +1466,16 @@
  * reused, whereas ClassIds can be recycled like any other object.  (Either
  * that, or I have no idea what this is for.)
  */
-static JdwpError COR_ReflectedType(JdwpState*, Request& request, ExpandBuf* pReply)
+static JdwpError COR_ReflectedType(JdwpState*, Request* request, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  RefTypeId class_object_id = request.ReadRefTypeId();
+  RefTypeId class_object_id = request->ReadRefTypeId();
   return Dbg::GetReflectedType(class_object_id, pReply);
 }
 
 /*
  * Handle a DDM packet with a single chunk in it.
  */
-static JdwpError DDM_Chunk(JdwpState* state, Request& request, ExpandBuf* pReply)
+static JdwpError DDM_Chunk(JdwpState* state, Request* request, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   state->NotifyDdmsActive();
   uint8_t* replyBuf = NULL;
@@ -1496,7 +1496,7 @@
 /*
  * Handler map decl.
  */
-typedef JdwpError (*JdwpRequestHandler)(JdwpState* state, Request& request, ExpandBuf* reply);
+typedef JdwpError (*JdwpRequestHandler)(JdwpState* state, Request* request, ExpandBuf* reply);
 
 struct JdwpHandlerMap {
   uint8_t cmdSet;
@@ -1639,20 +1639,20 @@
   { 199,  1,  DDM_Chunk,        "DDM.Chunk" },
 };
 
-static const char* GetCommandName(Request& request) {
+static const char* GetCommandName(Request* request) {
   for (size_t i = 0; i < arraysize(gHandlers); ++i) {
-    if (gHandlers[i].cmdSet == request.GetCommandSet() && gHandlers[i].cmd == request.GetCommand()) {
+    if (gHandlers[i].cmdSet == request->GetCommandSet() && gHandlers[i].cmd == request->GetCommand()) {
       return gHandlers[i].name;
     }
   }
   return "?UNKNOWN?";
 }
 
-static std::string DescribeCommand(Request& request) {
+static std::string DescribeCommand(Request* request) {
   std::string result;
   result += "REQUEST: ";
   result += GetCommandName(request);
-  result += StringPrintf(" (length=%zu id=0x%06x)", request.GetLength(), request.GetId());
+  result += StringPrintf(" (length=%zu id=0x%06x)", request->GetLength(), request->GetId());
   return result;
 }
 
@@ -1661,10 +1661,10 @@
  *
  * On entry, the JDWP thread is in VMWAIT.
  */
-size_t JdwpState::ProcessRequest(Request& request, ExpandBuf* pReply) {
+size_t JdwpState::ProcessRequest(Request* request, ExpandBuf* pReply) {
   JdwpError result = ERR_NONE;
 
-  if (request.GetCommandSet() != kJDWPDdmCmdSet) {
+  if (request->GetCommandSet() != kJDWPDdmCmdSet) {
     /*
      * Activity from a debugger, not merely ddms.  Mark us as having an
      * active debugger session, and zero out the last-activity timestamp
@@ -1684,7 +1684,7 @@
    * thread to finish, and then clear the block.  Depending on the thread
    * suspend policy, this may allow events in other threads to fire,
    * but those events have no bearing on what the debugger has sent us
-   * in the current request.
+   * in the current request->
    *
    * Note that we MUST clear the event token before waking the event
    * thread up, or risk waiting for the thread to suspend after we've
@@ -1693,7 +1693,7 @@
   SetWaitForEventThread(0);
 
   /*
-   * We do not want events to be sent while we process a request. Indicate the JDWP thread starts
+   * We do not want events to be sent while we process a request-> Indicate the JDWP thread starts
    * to process a request so other threads wait for it to finish before sending an event.
    */
   StartProcessingRequest();
@@ -1709,18 +1709,18 @@
 
   size_t i;
   for (i = 0; i < arraysize(gHandlers); ++i) {
-    if (gHandlers[i].cmdSet == request.GetCommandSet() && gHandlers[i].cmd == request.GetCommand() && gHandlers[i].func != NULL) {
+    if (gHandlers[i].cmdSet == request->GetCommandSet() && gHandlers[i].cmd == request->GetCommand() && gHandlers[i].func != NULL) {
       VLOG(jdwp) << DescribeCommand(request);
       result = (*gHandlers[i].func)(this, request, pReply);
       if (result == ERR_NONE) {
-        request.CheckConsumed();
+        request->CheckConsumed();
       }
       break;
     }
   }
   if (i == arraysize(gHandlers)) {
     LOG(ERROR) << "Command not implemented: " << DescribeCommand(request);
-    LOG(ERROR) << HexDump(request.data(), request.size(), false, "");
+    LOG(ERROR) << HexDump(request->data(), request->size(), false, "");
     result = ERR_NOT_IMPLEMENTED;
   }
 
@@ -1732,11 +1732,11 @@
   uint8_t* replyBuf = expandBufGetBuffer(pReply);
   size_t replyLength = (result == ERR_NONE) ? expandBufGetLength(pReply) : kJDWPHeaderLen;
   Set4BE(replyBuf + 0, replyLength);
-  Set4BE(replyBuf + 4, request.GetId());
+  Set4BE(replyBuf + 4, request->GetId());
   Set1(replyBuf + 8, kJDWPFlagReply);
   Set2BE(replyBuf + 9, result);
 
-  CHECK_GT(expandBufGetLength(pReply), 0U) << GetCommandName(request) << " " << request.GetId();
+  CHECK_GT(expandBufGetLength(pReply), 0U) << GetCommandName(request) << " " << request->GetId();
 
   size_t respLen = expandBufGetLength(pReply) - kJDWPHeaderLen;
   VLOG(jdwp) << "REPLY: " << GetCommandName(request) << " " << result << " (length=" << respLen << ")";
@@ -1750,7 +1750,7 @@
    * Update last-activity timestamp.  We really only need this during
    * the initial setup.  Only update if this is a non-DDMS packet.
    */
-  if (request.GetCommandSet() != kJDWPDdmCmdSet) {
+  if (request->GetCommandSet() != kJDWPDdmCmdSet) {
     last_activity_time_ms_.StoreSequentiallyConsistent(MilliTime());
   }
 
diff --git a/runtime/jdwp/jdwp_main.cc b/runtime/jdwp/jdwp_main.cc
index a4f427c..c500ef5 100644
--- a/runtime/jdwp/jdwp_main.cc
+++ b/runtime/jdwp/jdwp_main.cc
@@ -373,7 +373,7 @@
   JDWP::Request request(netStateBase->input_buffer_, netStateBase->input_count_);
 
   ExpandBuf* pReply = expandBufAlloc();
-  size_t replyLength = ProcessRequest(request, pReply);
+  size_t replyLength = ProcessRequest(&request, pReply);
   ssize_t cc = netStateBase->WritePacket(pReply, replyLength);
 
   /*
diff --git a/runtime/jdwp/object_registry.cc b/runtime/jdwp/object_registry.cc
index ad18d8a..35aaf0a 100644
--- a/runtime/jdwp/object_registry.cc
+++ b/runtime/jdwp/object_registry.cc
@@ -21,8 +21,6 @@
 
 namespace art {
 
-mirror::Object* const ObjectRegistry::kInvalidObject = reinterpret_cast<mirror::Object*>(1);
-
 std::ostream& operator<<(std::ostream& os, const ObjectRegistryEntry& rhs) {
   os << "ObjectRegistryEntry[" << rhs.jni_reference_type
      << ",reference=" << rhs.jni_reference
@@ -129,14 +127,16 @@
   id_to_entry_.clear();
 }
 
-mirror::Object* ObjectRegistry::InternalGet(JDWP::ObjectId id) {
+mirror::Object* ObjectRegistry::InternalGet(JDWP::ObjectId id, JDWP::JdwpError* error) {
   Thread* self = Thread::Current();
   MutexLock mu(self, lock_);
   auto it = id_to_entry_.find(id);
   if (it == id_to_entry_.end()) {
-    return kInvalidObject;
+    *error = JDWP::ERR_INVALID_OBJECT;
+    return nullptr;
   }
   ObjectRegistryEntry& entry = *it->second;
+  *error = JDWP::ERR_NONE;
   return self->DecodeJObject(entry.jni_reference);
 }
 
diff --git a/runtime/jdwp/object_registry.h b/runtime/jdwp/object_registry.h
index f0314a3..0e46d5c 100644
--- a/runtime/jdwp/object_registry.h
+++ b/runtime/jdwp/object_registry.h
@@ -22,6 +22,7 @@
 
 #include <map>
 
+#include "base/casts.h"
 #include "jdwp/jdwp.h"
 #include "safe_map.h"
 
@@ -64,11 +65,13 @@
       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_) {
+  template<typename T> T Get(JDWP::ObjectId id, JDWP::JdwpError* error)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     if (id == 0) {
-      return NULL;
+      *error = JDWP::ERR_NONE;
+      return nullptr;
     }
-    return reinterpret_cast<T>(InternalGet(id));
+    return down_cast<T>(InternalGet(id, error));
   }
 
   bool Contains(mirror::Object* o) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -85,9 +88,6 @@
   void DisposeObject(JDWP::ObjectId id, uint32_t reference_count)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  // Returned by Get when passed an invalid object id.
-  static mirror::Object* const kInvalidObject;
-
   // This is needed to get the jobject instead of the Object*.
   // Avoid using this and use standard Get when possible.
   jobject GetJObject(JDWP::ObjectId id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -95,7 +95,8 @@
  private:
   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_);
+  mirror::Object* InternalGet(JDWP::ObjectId id, JDWP::JdwpError* error)
+      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)
diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc
index 9196556..3e9ae09 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -2261,25 +2261,15 @@
     IndirectRef ref = reinterpret_cast<IndirectRef>(java_object);
     IndirectRefKind kind = GetIndirectRefKind(ref);
     switch (kind) {
-    case kLocal: {
-      ScopedObjectAccess soa(env);
-      // The local refs don't need a read barrier.
-      if (static_cast<JNIEnvExt*>(env)->locals.Get<kWithoutReadBarrier>(ref) !=
-          kInvalidIndirectRefObject) {
-        return JNILocalRefType;
-      }
-      return JNIInvalidRefType;
-    }
+    case kLocal:
+      return JNILocalRefType;
     case kGlobal:
       return JNIGlobalRefType;
     case kWeakGlobal:
       return JNIWeakGlobalRefType;
     case kHandleScopeOrInvalid:
-      // Is it in a stack IRT?
-      if (static_cast<JNIEnvExt*>(env)->self->HandleScopeContains(java_object)) {
-        return JNILocalRefType;
-      }
-      return JNIInvalidRefType;
+      // Assume value is in a handle scope.
+      return JNILocalRefType;
     }
     LOG(FATAL) << "IndirectRefKind[" << kind << "]";
     return JNIInvalidRefType;
diff --git a/runtime/jni_internal_test.cc b/runtime/jni_internal_test.cc
index b236ede..20d031c 100644
--- a/runtime/jni_internal_test.cc
+++ b/runtime/jni_internal_test.cc
@@ -1269,13 +1269,14 @@
   jweak weak_global = env_->NewWeakGlobalRef(local);
   EXPECT_EQ(JNIWeakGlobalRefType, env_->GetObjectRefType(weak_global));
 
+  CheckJniAbortCatcher jni_abort_catcher;
   jobject invalid = reinterpret_cast<jobject>(this);
   EXPECT_EQ(JNIInvalidRefType, env_->GetObjectRefType(invalid));
+  jni_abort_catcher.Check("use of invalid jobject");
 
   // TODO: invoke a native method and test that its arguments are considered local references.
 
   // Null as object should fail.
-  CheckJniAbortCatcher jni_abort_catcher;
   EXPECT_EQ(JNIInvalidRefType, env_->GetObjectRefType(nullptr));
   jni_abort_catcher.Check("java_object == null");
 }
@@ -1687,7 +1688,7 @@
     CheckJniAbortCatcher check_jni_abort_catcher;
     EXPECT_FALSE(vm_->SetCheckJniEnabled(true));
     env_->DeleteLocalRef(s);
-    std::string expected(StringPrintf("jobject is an invalid local reference: %p", s));
+    std::string expected(StringPrintf("use of deleted local reference %p", s));
     check_jni_abort_catcher.Check(expected.c_str());
     EXPECT_TRUE(vm_->SetCheckJniEnabled(old_check_jni));
   }
@@ -1723,7 +1724,6 @@
   jobject outer;
   jobject inner1, inner2;
   ScopedObjectAccess soa(env_);
-  mirror::Object* inner2_direct_pointer;
   {
     ASSERT_EQ(JNI_OK, env_->PushLocalFrame(4));
     outer = env_->NewLocalRef(original);
@@ -1732,24 +1732,35 @@
       ASSERT_EQ(JNI_OK, env_->PushLocalFrame(4));
       inner1 = env_->NewLocalRef(outer);
       inner2 = env_->NewStringUTF("survivor");
-      inner2_direct_pointer = soa.Decode<mirror::Object*>(inner2);
-      env_->PopLocalFrame(inner2);
+      EXPECT_NE(env_->PopLocalFrame(inner2), nullptr);
     }
 
     EXPECT_EQ(JNILocalRefType, env_->GetObjectRefType(original));
     EXPECT_EQ(JNILocalRefType, env_->GetObjectRefType(outer));
-    EXPECT_EQ(JNIInvalidRefType, env_->GetObjectRefType(inner1));
+    {
+      CheckJniAbortCatcher check_jni_abort_catcher;
+      EXPECT_EQ(JNIInvalidRefType, env_->GetObjectRefType(inner1));
+      check_jni_abort_catcher.Check("use of deleted local reference");
+    }
 
     // Our local reference for the survivor is invalid because the survivor
     // gets a new local reference...
-    EXPECT_EQ(JNIInvalidRefType, env_->GetObjectRefType(inner2));
+    {
+      CheckJniAbortCatcher check_jni_abort_catcher;
+      EXPECT_EQ(JNIInvalidRefType, env_->GetObjectRefType(inner2));
+      check_jni_abort_catcher.Check("use of deleted local reference");
+    }
 
-    env_->PopLocalFrame(nullptr);
+    EXPECT_EQ(env_->PopLocalFrame(nullptr), nullptr);
   }
   EXPECT_EQ(JNILocalRefType, env_->GetObjectRefType(original));
+  CheckJniAbortCatcher check_jni_abort_catcher;
   EXPECT_EQ(JNIInvalidRefType, env_->GetObjectRefType(outer));
+  check_jni_abort_catcher.Check("use of deleted local reference");
   EXPECT_EQ(JNIInvalidRefType, env_->GetObjectRefType(inner1));
+  check_jni_abort_catcher.Check("use of deleted local reference");
   EXPECT_EQ(JNIInvalidRefType, env_->GetObjectRefType(inner2));
+  check_jni_abort_catcher.Check("use of deleted local reference");
 }
 
 TEST_F(JniInternalTest, NewGlobalRef_nullptr) {
@@ -1788,7 +1799,7 @@
     CheckJniAbortCatcher check_jni_abort_catcher;
     EXPECT_FALSE(vm_->SetCheckJniEnabled(true));
     env_->DeleteGlobalRef(o);
-    std::string expected(StringPrintf("jobject is an invalid global reference: %p", o));
+    std::string expected(StringPrintf("use of deleted global reference %p", o));
     check_jni_abort_catcher.Check(expected.c_str());
     EXPECT_TRUE(vm_->SetCheckJniEnabled(old_check_jni));
   }
@@ -1838,7 +1849,7 @@
     CheckJniAbortCatcher check_jni_abort_catcher;
     EXPECT_FALSE(vm_->SetCheckJniEnabled(true));
     env_->DeleteWeakGlobalRef(o);
-    std::string expected(StringPrintf("jobject is an invalid weak global reference: %p", o));
+    std::string expected(StringPrintf("use of deleted weak global reference %p", o));
     check_jni_abort_catcher.Check(expected.c_str());
     EXPECT_TRUE(vm_->SetCheckJniEnabled(old_check_jni));
   }
diff --git a/runtime/reference_table.cc b/runtime/reference_table.cc
index 70aba9b..01c5070 100644
--- a/runtime/reference_table.cc
+++ b/runtime/reference_table.cc
@@ -24,6 +24,7 @@
 #include "mirror/class-inl.h"
 #include "mirror/object-inl.h"
 #include "mirror/string-inl.h"
+#include "runtime-inl.h"
 #include "thread.h"
 #include "utils.h"
 
@@ -62,7 +63,9 @@
 // If "obj" is an array, return the number of elements in the array.
 // Otherwise, return zero.
 static size_t GetElementCount(mirror::Object* obj) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  if (obj == NULL || obj == kClearedJniWeakGlobal || !obj->IsArrayInstance()) {
+  // We assume the special cleared value isn't an array in the if statement below.
+  DCHECK(!Runtime::Current()->GetClearedJniWeakGlobal()->IsArrayInstance());
+  if (obj == nullptr || !obj->IsArrayInstance()) {
     return 0;
   }
   return obj->AsArray()->GetLength();
@@ -81,9 +84,10 @@
     } else if (obj2 == NULL) {
       return false;
     }
-    if (obj1 == kClearedJniWeakGlobal) {
+    Runtime* runtime = Runtime::Current();
+    if (runtime->IsClearedJniWeakGlobal(obj1)) {
       return true;
-    } else if (obj2 == kClearedJniWeakGlobal) {
+    } else if (runtime->IsClearedJniWeakGlobal(obj2)) {
       return false;
     }
 
@@ -116,7 +120,7 @@
     os << "    NULL reference (count=" << equiv << ")\n";
     return;
   }
-  if (obj == kClearedJniWeakGlobal) {
+  if (Runtime::Current()->IsClearedJniWeakGlobal(obj)) {
     os << "    cleared jweak (count=" << equiv << ")\n";
     return;
   }
@@ -167,7 +171,7 @@
     if (ref == NULL) {
       continue;
     }
-    if (ref == kClearedJniWeakGlobal) {
+    if (Runtime::Current()->IsClearedJniWeakGlobal(ref)) {
       os << StringPrintf("    %5d: cleared jweak\n", idx);
       continue;
     }
@@ -209,7 +213,8 @@
     sorted_entries.pop_back();
   }
   while (!sorted_entries.empty() &&
-         sorted_entries.back().Read<kWithoutReadBarrier>() == kClearedJniWeakGlobal) {
+         Runtime::Current()->IsClearedJniWeakGlobal(
+             sorted_entries.back().Read<kWithoutReadBarrier>())) {
     sorted_entries.pop_back();
   }
   if (sorted_entries.empty()) {
diff --git a/runtime/runtime-inl.h b/runtime/runtime-inl.h
index ac9026b..8b632b2 100644
--- a/runtime/runtime-inl.h
+++ b/runtime/runtime-inl.h
@@ -23,6 +23,18 @@
 
 namespace art {
 
+inline bool Runtime::IsClearedJniWeakGlobal(mirror::Object* obj) {
+  return obj == GetClearedJniWeakGlobal();
+}
+
+inline mirror::Object* Runtime::GetClearedJniWeakGlobal() {
+  mirror::Object* obj = sentinel_.Read();
+  if (obj == nullptr) {
+    LOG(ERROR) << "Failed to return cleared JNI weak global sentinel";
+  }
+  return obj;
+}
+
 inline QuickMethodFrameInfo Runtime::GetRuntimeMethodFrameInfo(mirror::ArtMethod* method) {
   DCHECK(method != nullptr);
   // Cannot be imt-conflict-method or resolution-method.
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 1a682fb..65ae5b7 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -796,6 +796,10 @@
     class_linker_->InitWithoutImage(*options->boot_class_path_);
   }
   CHECK(class_linker_ != nullptr);
+
+  // Initialize the special sentinel_ value early.
+  sentinel_ = GcRoot<mirror::Object>(class_linker_->AllocObject(self));
+
   verifier::MethodVerifier::Init();
 
   method_trace_ = options->method_trace_;
@@ -1084,6 +1088,10 @@
 
 void Runtime::VisitNonThreadRoots(RootCallback* callback, void* arg) {
   java_vm_->VisitRoots(callback, arg);
+  if (!sentinel_.IsNull()) {
+    sentinel_.VisitRoot(callback, arg, 0, kRootVMInternal);
+    DCHECK(!sentinel_.IsNull());
+  }
   if (!pre_allocated_OutOfMemoryError_.IsNull()) {
     pre_allocated_OutOfMemoryError_.VisitRoot(callback, arg, 0, kRootVMInternal);
     DCHECK(!pre_allocated_OutOfMemoryError_.IsNull());
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 03952c4..caed664 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -244,6 +244,12 @@
     return monitor_pool_;
   }
 
+  // Is the given object the special object used to mark a cleared JNI weak global?
+  bool IsClearedJniWeakGlobal(mirror::Object* obj) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  // Get the special object used to mark a cleared JNI weak global.
+  mirror::Object* GetClearedJniWeakGlobal() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   mirror::Throwable* GetPreAllocatedOutOfMemoryError() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   mirror::Throwable* GetPreAllocatedNoClassDefFoundError()
@@ -517,6 +523,10 @@
   GcRoot<mirror::ArtMethod> imt_conflict_method_;
   GcRoot<mirror::ObjectArray<mirror::ArtMethod>> default_imt_;
 
+  // Special sentinel object used to invalid conditions in JNI (cleared weak references) and
+  // JDWP (invalid references).
+  GcRoot<mirror::Object> sentinel_;
+
   InstructionSet instruction_set_;
   QuickMethodFrameInfo callee_save_method_frame_infos_[kLastCalleeSaveType];
 
diff --git a/runtime/thread.cc b/runtime/thread.cc
index e0d67d6..e323473 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -911,7 +911,6 @@
   std::ostream& os;
   const Thread* thread;
   const bool can_allocate;
-  mirror::ArtMethod* method;
   mirror::ArtMethod* last_method;
   int last_line_number;
   int repetition_count;
@@ -1238,7 +1237,7 @@
 
 size_t Thread::NumHandleReferences() {
   size_t count = 0;
-  for (HandleScope* cur = tlsPtr_.top_handle_scope; cur; cur = cur->GetLink()) {
+  for (HandleScope* cur = tlsPtr_.top_handle_scope; cur != nullptr; cur = cur->GetLink()) {
     count += cur->NumberOfReferences();
   }
   return count;
@@ -1247,7 +1246,7 @@
 bool Thread::HandleScopeContains(jobject obj) const {
   StackReference<mirror::Object>* hs_entry =
       reinterpret_cast<StackReference<mirror::Object>*>(obj);
-  for (HandleScope* cur = tlsPtr_.top_handle_scope; cur; cur = cur->GetLink()) {
+  for (HandleScope* cur = tlsPtr_.top_handle_scope; cur!= nullptr; cur = cur->GetLink()) {
     if (cur->Contains(hs_entry)) {
       return true;
     }
@@ -1280,6 +1279,7 @@
   IndirectRef ref = reinterpret_cast<IndirectRef>(obj);
   IndirectRefKind kind = GetIndirectRefKind(ref);
   mirror::Object* result;
+  bool expect_null = false;
   // The "kinds" below are sorted by the frequency we expect to encounter them.
   if (kind == kLocal) {
     IndirectReferenceTable& locals = tlsPtr_.jni_env->locals;
@@ -1293,20 +1293,23 @@
       result = reinterpret_cast<StackReference<mirror::Object>*>(obj)->AsMirrorPtr();
       VerifyObject(result);
     } else {
-      result = kInvalidIndirectRefObject;
+      tlsPtr_.jni_env->vm->JniAbortF(nullptr, "use of invalid jobject %p", obj);
+      expect_null = true;
+      result = nullptr;
     }
   } else if (kind == kGlobal) {
     result = tlsPtr_.jni_env->vm->DecodeGlobal(const_cast<Thread*>(this), ref);
   } else {
     DCHECK_EQ(kind, kWeakGlobal);
     result = tlsPtr_.jni_env->vm->DecodeWeakGlobal(const_cast<Thread*>(this), ref);
-    if (result == kClearedJniWeakGlobal) {
+    if (Runtime::Current()->IsClearedJniWeakGlobal(result)) {
       // This is a special case where it's okay to return nullptr.
-      return nullptr;
+      expect_null = true;
+      result = nullptr;
     }
   }
 
-  if (UNLIKELY(result == nullptr)) {
+  if (UNLIKELY(!expect_null && result == nullptr)) {
     tlsPtr_.jni_env->vm->JniAbortF(nullptr, "use of deleted %s %p",
                                    ToStr<IndirectRefKind>(kind).c_str(), obj);
   }