Move ArtField to ObjPtr

Added EXPECT_OBJ_PTR_EQ and variants to gtests.

Fixed moving GC bugs in:
ClassLinker::CreatePathClassLoader
ClassLinkerTest: StaticFields

ObjPtr Decode call sites: 186 -> 181.

Some tests fail due to ResolvedFieldAccessTest, will fix in follow
up CL.

Bug: 31113334

Test: test-art-host CC baker

Change-Id: I8b266ad00f3c20c8cbe7cfdf280d175083df0b88
diff --git a/compiler/driver/compiler_driver-inl.h b/compiler/driver/compiler_driver-inl.h
index 2d0dd3c..b4730cc 100644
--- a/compiler/driver/compiler_driver-inl.h
+++ b/compiler/driver/compiler_driver-inl.h
@@ -103,7 +103,7 @@
 inline void CompilerDriver::GetResolvedFieldDexFileLocation(
     ArtField* resolved_field, const DexFile** declaring_dex_file,
     uint16_t* declaring_class_idx, uint16_t* declaring_field_idx) {
-  mirror::Class* declaring_class = resolved_field->GetDeclaringClass();
+  ObjPtr<mirror::Class> declaring_class = resolved_field->GetDeclaringClass();
   *declaring_dex_file = declaring_class->GetDexCache()->GetDexFile();
   *declaring_class_idx = declaring_class->GetDexTypeIndex();
   *declaring_field_idx = resolved_field->GetDexFieldIndex();
@@ -121,10 +121,12 @@
     mirror::DexCache* dex_cache, mirror::Class* referrer_class,
     ArtField* resolved_field, uint16_t field_idx) {
   DCHECK(!resolved_field->IsStatic());
-  mirror::Class* fields_class = resolved_field->GetDeclaringClass();
+  ObjPtr<mirror::Class> fields_class = resolved_field->GetDeclaringClass();
   bool fast_get = referrer_class != nullptr &&
-      referrer_class->CanAccessResolvedField(fields_class, resolved_field,
-                                             dex_cache, field_idx);
+      referrer_class->CanAccessResolvedField(fields_class.Decode(),
+                                             resolved_field,
+                                             dex_cache,
+                                             field_idx);
   bool fast_put = fast_get && (!resolved_field->IsFinal() || fields_class == referrer_class);
   return std::make_pair(fast_get, fast_put);
 }
@@ -167,13 +169,13 @@
     uint32_t* storage_index) {
   DCHECK(resolved_member->IsStatic());
   if (LIKELY(referrer_class != nullptr)) {
-    mirror::Class* members_class = resolved_member->GetDeclaringClass();
+    ObjPtr<mirror::Class> members_class = resolved_member->GetDeclaringClass();
     if (members_class == referrer_class) {
       *storage_index = members_class->GetDexTypeIndex();
       return std::make_pair(true, true);
     }
     if (CanAccessResolvedMember<ArtMember>(
-            referrer_class, members_class, resolved_member, dex_cache, member_idx)) {
+        referrer_class, members_class.Decode(), resolved_member, dex_cache, member_idx)) {
       // We have the resolved member, we must make it into a index for the referrer
       // in its static storage (which may fail if it doesn't have a slot for it)
       // TODO: for images we can elide the static storage base null check
@@ -220,7 +222,7 @@
 inline bool CompilerDriver::IsStaticFieldInReferrerClass(mirror::Class* referrer_class,
                                                          ArtField* resolved_field) {
   DCHECK(resolved_field->IsStatic());
-  mirror::Class* fields_class = resolved_field->GetDeclaringClass();
+  ObjPtr<mirror::Class> fields_class = resolved_field->GetDeclaringClass();
   return referrer_class == fields_class;
 }
 
@@ -250,8 +252,8 @@
 inline bool CompilerDriver::IsStaticFieldsClassInitialized(mirror::Class* referrer_class,
                                                            ArtField* resolved_field) {
   DCHECK(resolved_field->IsStatic());
-  mirror::Class* fields_class = resolved_field->GetDeclaringClass();
-  return CanReferrerAssumeClassIsInitialized(referrer_class, fields_class);
+  ObjPtr<mirror::Class> fields_class = resolved_field->GetDeclaringClass();
+  return CanReferrerAssumeClassIsInitialized(referrer_class, fields_class.Decode());
 }
 
 inline ArtMethod* CompilerDriver::ResolveMethod(
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index 41bda60..210943c 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -908,7 +908,7 @@
     ArtField** resolved_fields = dex_cache->GetResolvedFields();
     for (size_t i = 0; i < dex_cache->NumResolvedFields(); i++) {
       ArtField* field = mirror::DexCache::GetElementPtrSize(resolved_fields, i, target_ptr_size_);
-      if (field != nullptr && !KeepClass(field->GetDeclaringClass())) {
+      if (field != nullptr && !KeepClass(field->GetDeclaringClass().Decode())) {
         dex_cache->SetResolvedField(i, nullptr, target_ptr_size_);
       }
     }
@@ -1742,7 +1742,7 @@
       case kNativeObjectRelocationTypeArtField: {
         memcpy(dest, pair.first, sizeof(ArtField));
         reinterpret_cast<ArtField*>(dest)->SetDeclaringClass(
-            GetImageAddress(reinterpret_cast<ArtField*>(pair.first)->GetDeclaringClass()));
+            GetImageAddress(reinterpret_cast<ArtField*>(pair.first)->GetDeclaringClass().Decode()));
         break;
       }
       case kNativeObjectRelocationTypeRuntimeMethod:
diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc
index 5a47df1..15cebfe 100644
--- a/compiler/optimizing/reference_type_propagation.cc
+++ b/compiler/optimizing/reference_type_propagation.cc
@@ -84,7 +84,7 @@
   void VisitNewArray(HNewArray* instr) OVERRIDE;
   void VisitParameterValue(HParameterValue* instr) OVERRIDE;
   void UpdateFieldAccessTypeInfo(HInstruction* instr, const FieldInfo& info);
-  void SetClassAsTypeInfo(HInstruction* instr, mirror::Class* klass, bool is_exact)
+  void SetClassAsTypeInfo(HInstruction* instr, ObjPtr<mirror::Class> klass, bool is_exact)
       REQUIRES_SHARED(Locks::mutator_lock_);
   void VisitInstanceFieldGet(HInstanceFieldGet* instr) OVERRIDE;
   void VisitStaticFieldGet(HStaticFieldGet* instr) OVERRIDE;
@@ -427,7 +427,7 @@
 }
 
 void ReferenceTypePropagation::RTPVisitor::SetClassAsTypeInfo(HInstruction* instr,
-                                                              mirror::Class* klass,
+                                                              ObjPtr<mirror::Class> klass,
                                                               bool is_exact) {
   if (instr->IsInvokeStaticOrDirect() && instr->AsInvokeStaticOrDirect()->IsStringInit()) {
     // Calls to String.<init> are replaced with a StringFactory.
@@ -454,7 +454,7 @@
     }
     instr->SetReferenceTypeInfo(
         ReferenceTypeInfo::Create(handle_cache_->GetStringClassHandle(), /* is_exact */ true));
-  } else if (IsAdmissible(klass)) {
+  } else if (IsAdmissible(klass.Decode())) {
     ReferenceTypeInfo::TypeHandle handle = handle_cache_->NewHandle(klass);
     is_exact = is_exact || handle->CannotBeAssignedFromOtherTypes();
     instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(handle, is_exact));
@@ -512,7 +512,7 @@
   }
 
   ScopedObjectAccess soa(Thread::Current());
-  mirror::Class* klass = nullptr;
+  ObjPtr<mirror::Class> klass;
 
   // The field index is unknown only during tests.
   if (info.GetFieldIndex() != kUnknownFieldIndex) {
diff --git a/compiler/optimizing/reference_type_propagation.h b/compiler/optimizing/reference_type_propagation.h
index 1fa6624..61428b2 100644
--- a/compiler/optimizing/reference_type_propagation.h
+++ b/compiler/optimizing/reference_type_propagation.h
@@ -21,6 +21,7 @@
 #include "driver/dex_compilation_unit.h"
 #include "handle_scope-inl.h"
 #include "nodes.h"
+#include "obj_ptr.h"
 #include "optimization.h"
 #include "optimizing_compiler_stats.h"
 
@@ -62,6 +63,11 @@
       return handles_->NewHandle(object);
     }
 
+    template <typename T>
+    MutableHandle<T> NewHandle(ObjPtr<T> object) REQUIRES_SHARED(Locks::mutator_lock_) {
+      return handles_->NewHandle(object);
+    }
+
     ReferenceTypeInfo::TypeHandle GetObjectClassHandle();
     ReferenceTypeInfo::TypeHandle GetClassClassHandle();
     ReferenceTypeInfo::TypeHandle GetStringClassHandle();
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index be5224b..4d0dc56 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -1687,7 +1687,9 @@
     ImageDumper* const image_dumper_;
   };
 
-  static void PrettyObjectValue(std::ostream& os, mirror::Class* type, mirror::Object* value)
+  static void PrettyObjectValue(std::ostream& os,
+                                ObjPtr<mirror::Class> type,
+                                ObjPtr<mirror::Object> value)
       REQUIRES_SHARED(Locks::mutator_lock_) {
     CHECK(type != nullptr);
     if (value == nullptr) {
@@ -1700,11 +1702,11 @@
       mirror::Class* klass = value->AsClass();
       os << StringPrintf("%p   Class: %s\n", klass, PrettyDescriptor(klass).c_str());
     } else {
-      os << StringPrintf("%p   %s\n", value, PrettyDescriptor(type).c_str());
+      os << StringPrintf("%p   %s\n", value.Decode(), PrettyDescriptor(type).c_str());
     }
   }
 
-  static void PrintField(std::ostream& os, ArtField* field, mirror::Object* obj)
+  static void PrintField(std::ostream& os, ArtField* field, ObjPtr<mirror::Object> obj)
       REQUIRES_SHARED(Locks::mutator_lock_) {
     os << StringPrintf("%s: ", field->GetName());
     switch (field->GetTypeAsPrimitiveType()) {
@@ -1736,16 +1738,17 @@
       case Primitive::kPrimNot: {
         // Get the value, don't compute the type unless it is non-null as we don't want
         // to cause class loading.
-        mirror::Object* value = field->GetObj(obj);
+        ObjPtr<mirror::Object> value = field->GetObj(obj);
         if (value == nullptr) {
           os << StringPrintf("null   %s\n", PrettyDescriptor(field->GetTypeDescriptor()).c_str());
         } else {
           // Grab the field type without causing resolution.
-          mirror::Class* field_type = field->GetType<false>();
+          ObjPtr<mirror::Class> field_type = field->GetType<false>();
           if (field_type != nullptr) {
             PrettyObjectValue(os, field_type, value);
           } else {
-            os << StringPrintf("%p   %s\n", value,
+            os << StringPrintf("%p   %s\n",
+                               value.Decode(),
                                PrettyDescriptor(field->GetTypeDescriptor()).c_str());
           }
         }
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc
index d58f38c..b259f64 100644
--- a/patchoat/patchoat.cc
+++ b/patchoat/patchoat.cc
@@ -504,7 +504,8 @@
 
   void Visit(ArtField* field) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
     ArtField* const dest = patch_oat_->RelocatedCopyOf(field);
-    dest->SetDeclaringClass(patch_oat_->RelocatedAddressOfPointer(field->GetDeclaringClass()));
+    dest->SetDeclaringClass(
+        patch_oat_->RelocatedAddressOfPointer(field->GetDeclaringClass().Decode()));
   }
 
  private:
diff --git a/runtime/arch/stub_test.cc b/runtime/arch/stub_test.cc
index 5e39f42..432ba36 100644
--- a/runtime/arch/stub_test.cc
+++ b/runtime/arch/stub_test.cc
@@ -1688,7 +1688,7 @@
 
   EXPECT_EQ(res, reinterpret_cast<size_t>(val)) << "Value " << val;
 
-  EXPECT_EQ(val, f->GetObj(trg));
+  EXPECT_OBJ_PTR_EQ(val, f->GetObj(trg));
 }
 #endif
 
diff --git a/runtime/art_field-inl.h b/runtime/art_field-inl.h
index ca96169..a52c714 100644
--- a/runtime/art_field-inl.h
+++ b/runtime/art_field-inl.h
@@ -34,15 +34,15 @@
 namespace art {
 
 template<ReadBarrierOption kReadBarrierOption>
-inline mirror::Class* ArtField::GetDeclaringClass() {
+inline ObjPtr<mirror::Class> ArtField::GetDeclaringClass() {
   GcRootSource gc_root_source(this);
-  mirror::Class* result = declaring_class_.Read<kReadBarrierOption>(&gc_root_source);
+  ObjPtr<mirror::Class> result = declaring_class_.Read<kReadBarrierOption>(&gc_root_source);
   DCHECK(result != nullptr);
   DCHECK(result->IsLoaded() || result->IsErroneous()) << result->GetStatus();
   return result;
 }
 
-inline void ArtField::SetDeclaringClass(mirror::Class* new_declaring_class) {
+inline void ArtField::SetDeclaringClass(ObjPtr<mirror::Class> new_declaring_class) {
   declaring_class_ = GcRoot<mirror::Class>(new_declaring_class);
 }
 
@@ -61,7 +61,7 @@
   return MemberOffset(offset_);
 }
 
-inline uint32_t ArtField::Get32(mirror::Object* object) {
+inline uint32_t ArtField::Get32(ObjPtr<mirror::Object> object) {
   DCHECK(object != nullptr) << PrettyField(this);
   DCHECK(!IsStatic() || (object == GetDeclaringClass()) || !Runtime::Current()->IsStarted());
   if (UNLIKELY(IsVolatile())) {
@@ -71,7 +71,7 @@
 }
 
 template<bool kTransactionActive>
-inline void ArtField::Set32(mirror::Object* object, uint32_t new_value) {
+inline void ArtField::Set32(ObjPtr<mirror::Object> object, uint32_t new_value) {
   DCHECK(object != nullptr) << PrettyField(this);
   DCHECK(!IsStatic() || (object == GetDeclaringClass()) || !Runtime::Current()->IsStarted());
   if (UNLIKELY(IsVolatile())) {
@@ -81,7 +81,7 @@
   }
 }
 
-inline uint64_t ArtField::Get64(mirror::Object* object) {
+inline uint64_t ArtField::Get64(ObjPtr<mirror::Object> object) {
   DCHECK(object != nullptr) << PrettyField(this);
   DCHECK(!IsStatic() || (object == GetDeclaringClass()) || !Runtime::Current()->IsStarted());
   if (UNLIKELY(IsVolatile())) {
@@ -91,7 +91,7 @@
 }
 
 template<bool kTransactionActive>
-inline void ArtField::Set64(mirror::Object* object, uint64_t new_value) {
+inline void ArtField::Set64(ObjPtr<mirror::Object> object, uint64_t new_value) {
   DCHECK(object != nullptr) << PrettyField(this);
   DCHECK(!IsStatic() || (object == GetDeclaringClass()) || !Runtime::Current()->IsStarted());
   if (UNLIKELY(IsVolatile())) {
@@ -101,23 +101,24 @@
   }
 }
 
-inline mirror::Object* ArtField::GetObj(mirror::Object* object) {
+template<class MirrorType>
+inline ObjPtr<MirrorType> ArtField::GetObj(ObjPtr<mirror::Object> object) {
   DCHECK(object != nullptr) << PrettyField(this);
   DCHECK(!IsStatic() || (object == GetDeclaringClass()) || !Runtime::Current()->IsStarted());
   if (UNLIKELY(IsVolatile())) {
-    return object->GetFieldObjectVolatile<mirror::Object>(GetOffset());
+    return object->GetFieldObjectVolatile<MirrorType>(GetOffset());
   }
-  return object->GetFieldObject<mirror::Object>(GetOffset());
+  return object->GetFieldObject<MirrorType>(GetOffset());
 }
 
 template<bool kTransactionActive>
-inline void ArtField::SetObj(mirror::Object* object, mirror::Object* new_value) {
+inline void ArtField::SetObj(ObjPtr<mirror::Object> object, ObjPtr<mirror::Object> new_value) {
   DCHECK(object != nullptr) << PrettyField(this);
   DCHECK(!IsStatic() || (object == GetDeclaringClass()) || !Runtime::Current()->IsStarted());
   if (UNLIKELY(IsVolatile())) {
-    object->SetFieldObjectVolatile<kTransactionActive>(GetOffset(), new_value);
+    object->SetFieldObjectVolatile<kTransactionActive>(GetOffset(), new_value.Decode());
   } else {
-    object->SetFieldObject<kTransactionActive>(GetOffset(), new_value);
+    object->SetFieldObject<kTransactionActive>(GetOffset(), new_value.Decode());
   }
 }
 
@@ -140,46 +141,46 @@
     (object)->SetField ## type<kTransactionActive>(GetOffset(), value); \
   }
 
-inline uint8_t ArtField::GetBoolean(mirror::Object* object) {
+inline uint8_t ArtField::GetBoolean(ObjPtr<mirror::Object> object) {
   FIELD_GET(object, Boolean);
 }
 
 template<bool kTransactionActive>
-inline void ArtField::SetBoolean(mirror::Object* object, uint8_t z) {
+inline void ArtField::SetBoolean(ObjPtr<mirror::Object> object, uint8_t z) {
   FIELD_SET(object, Boolean, z);
 }
 
-inline int8_t ArtField::GetByte(mirror::Object* object) {
+inline int8_t ArtField::GetByte(ObjPtr<mirror::Object> object) {
   FIELD_GET(object, Byte);
 }
 
 template<bool kTransactionActive>
-inline void ArtField::SetByte(mirror::Object* object, int8_t b) {
+inline void ArtField::SetByte(ObjPtr<mirror::Object> object, int8_t b) {
   FIELD_SET(object, Byte, b);
 }
 
-inline uint16_t ArtField::GetChar(mirror::Object* object) {
+inline uint16_t ArtField::GetChar(ObjPtr<mirror::Object> object) {
   FIELD_GET(object, Char);
 }
 
 template<bool kTransactionActive>
-inline void ArtField::SetChar(mirror::Object* object, uint16_t c) {
+inline void ArtField::SetChar(ObjPtr<mirror::Object> object, uint16_t c) {
   FIELD_SET(object, Char, c);
 }
 
-inline int16_t ArtField::GetShort(mirror::Object* object) {
+inline int16_t ArtField::GetShort(ObjPtr<mirror::Object> object) {
   FIELD_GET(object, Short);
 }
 
 template<bool kTransactionActive>
-inline void ArtField::SetShort(mirror::Object* object, int16_t s) {
+inline void ArtField::SetShort(ObjPtr<mirror::Object> object, int16_t s) {
   FIELD_SET(object, Short, s);
 }
 
 #undef FIELD_GET
 #undef FIELD_SET
 
-inline int32_t ArtField::GetInt(mirror::Object* object) {
+inline int32_t ArtField::GetInt(ObjPtr<mirror::Object> object) {
   if (kIsDebugBuild) {
     Primitive::Type type = GetTypeAsPrimitiveType();
     CHECK(type == Primitive::kPrimInt || type == Primitive::kPrimFloat) << PrettyField(this);
@@ -188,7 +189,7 @@
 }
 
 template<bool kTransactionActive>
-inline void ArtField::SetInt(mirror::Object* object, int32_t i) {
+inline void ArtField::SetInt(ObjPtr<mirror::Object> object, int32_t i) {
   if (kIsDebugBuild) {
     Primitive::Type type = GetTypeAsPrimitiveType();
     CHECK(type == Primitive::kPrimInt || type == Primitive::kPrimFloat) << PrettyField(this);
@@ -196,7 +197,7 @@
   Set32<kTransactionActive>(object, i);
 }
 
-inline int64_t ArtField::GetLong(mirror::Object* object) {
+inline int64_t ArtField::GetLong(ObjPtr<mirror::Object> object) {
   if (kIsDebugBuild) {
     Primitive::Type type = GetTypeAsPrimitiveType();
     CHECK(type == Primitive::kPrimLong || type == Primitive::kPrimDouble) << PrettyField(this);
@@ -205,7 +206,7 @@
 }
 
 template<bool kTransactionActive>
-inline void ArtField::SetLong(mirror::Object* object, int64_t j) {
+inline void ArtField::SetLong(ObjPtr<mirror::Object> object, int64_t j) {
   if (kIsDebugBuild) {
     Primitive::Type type = GetTypeAsPrimitiveType();
     CHECK(type == Primitive::kPrimLong || type == Primitive::kPrimDouble) << PrettyField(this);
@@ -213,7 +214,7 @@
   Set64<kTransactionActive>(object, j);
 }
 
-inline float ArtField::GetFloat(mirror::Object* object) {
+inline float ArtField::GetFloat(ObjPtr<mirror::Object> object) {
   DCHECK_EQ(Primitive::kPrimFloat, GetTypeAsPrimitiveType()) << PrettyField(this);
   JValue bits;
   bits.SetI(Get32(object));
@@ -221,14 +222,14 @@
 }
 
 template<bool kTransactionActive>
-inline void ArtField::SetFloat(mirror::Object* object, float f) {
+inline void ArtField::SetFloat(ObjPtr<mirror::Object> object, float f) {
   DCHECK_EQ(Primitive::kPrimFloat, GetTypeAsPrimitiveType()) << PrettyField(this);
   JValue bits;
   bits.SetF(f);
   Set32<kTransactionActive>(object, bits.GetI());
 }
 
-inline double ArtField::GetDouble(mirror::Object* object) {
+inline double ArtField::GetDouble(ObjPtr<mirror::Object> object) {
   DCHECK_EQ(Primitive::kPrimDouble, GetTypeAsPrimitiveType()) << PrettyField(this);
   JValue bits;
   bits.SetJ(Get64(object));
@@ -236,20 +237,20 @@
 }
 
 template<bool kTransactionActive>
-inline void ArtField::SetDouble(mirror::Object* object, double d) {
+inline void ArtField::SetDouble(ObjPtr<mirror::Object> object, double d) {
   DCHECK_EQ(Primitive::kPrimDouble, GetTypeAsPrimitiveType()) << PrettyField(this);
   JValue bits;
   bits.SetD(d);
   Set64<kTransactionActive>(object, bits.GetJ());
 }
 
-inline mirror::Object* ArtField::GetObject(mirror::Object* object) {
+inline ObjPtr<mirror::Object> ArtField::GetObject(ObjPtr<mirror::Object> object) {
   DCHECK_EQ(Primitive::kPrimNot, GetTypeAsPrimitiveType()) << PrettyField(this);
   return GetObj(object);
 }
 
 template<bool kTransactionActive>
-inline void ArtField::SetObject(mirror::Object* object, mirror::Object* l) {
+inline void ArtField::SetObject(ObjPtr<mirror::Object> object, ObjPtr<mirror::Object> l) {
   DCHECK_EQ(Primitive::kPrimNot, GetTypeAsPrimitiveType()) << PrettyField(this);
   SetObj<kTransactionActive>(object, l);
 }
@@ -288,16 +289,16 @@
 }
 
 template <bool kResolve>
-inline mirror::Class* ArtField::GetType() {
+inline ObjPtr<mirror::Class> ArtField::GetType() {
   const uint32_t field_index = GetDexFieldIndex();
-  auto* declaring_class = GetDeclaringClass();
+  ObjPtr<mirror::Class> declaring_class = GetDeclaringClass();
   if (UNLIKELY(declaring_class->IsProxyClass())) {
     return ProxyFindSystemClass(GetTypeDescriptor());
   }
   auto* dex_cache = declaring_class->GetDexCache();
   const DexFile* const dex_file = dex_cache->GetDexFile();
   const DexFile::FieldId& field_id = dex_file->GetFieldId(field_index);
-  mirror::Class* type = dex_cache->GetResolvedType(field_id.type_idx_);
+  ObjPtr<mirror::Class> type = dex_cache->GetResolvedType(field_id.type_idx_);
   if (kResolve && UNLIKELY(type == nullptr)) {
     type = ResolveGetType(field_id.type_idx_);
     CHECK(type != nullptr || Thread::Current()->IsExceptionPending());
@@ -309,7 +310,7 @@
   return Primitive::ComponentSize(GetTypeAsPrimitiveType());
 }
 
-inline mirror::DexCache* ArtField::GetDexCache() REQUIRES_SHARED(Locks::mutator_lock_) {
+inline ObjPtr<mirror::DexCache> ArtField::GetDexCache() REQUIRES_SHARED(Locks::mutator_lock_) {
   return GetDeclaringClass()->GetDexCache();
 }
 
@@ -317,13 +318,13 @@
   return GetDexCache()->GetDexFile();
 }
 
-inline mirror::String* ArtField::GetStringName(Thread* self, bool resolve) {
+inline ObjPtr<mirror::String> ArtField::GetStringName(Thread* self, bool resolve) {
   auto dex_field_index = GetDexFieldIndex();
   CHECK_NE(dex_field_index, DexFile::kDexNoIndex);
-  auto* dex_cache = GetDexCache();
+  ObjPtr<mirror::DexCache> dex_cache = GetDexCache();
   const auto* dex_file = dex_cache->GetDexFile();
   const auto& field_id = dex_file->GetFieldId(dex_field_index);
-  auto* name = dex_cache->GetResolvedString(field_id.name_idx_);
+  ObjPtr<mirror::String> name = dex_cache->GetResolvedString(field_id.name_idx_);
   if (resolve && name == nullptr) {
     name = ResolveGetStringName(self, *dex_file, field_id.name_idx_, dex_cache);
   }
@@ -337,8 +338,8 @@
 
 template <typename Visitor>
 inline void ArtField::UpdateObjects(const Visitor& visitor) {
-  mirror::Class* old_class = DeclaringClassRoot().Read<kWithoutReadBarrier>();
-  mirror::Class* new_class = visitor(old_class);
+  ObjPtr<mirror::Class> old_class = DeclaringClassRoot().Read<kWithoutReadBarrier>();
+  ObjPtr<mirror::Class> new_class = visitor(old_class.Decode());
   if (old_class != new_class) {
     SetDeclaringClass(new_class);
   }
@@ -369,7 +370,7 @@
 }
 
 template <bool kExactOffset>
-inline ArtField* ArtField::FindInstanceFieldWithOffset(mirror::Class* klass,
+inline ArtField* ArtField::FindInstanceFieldWithOffset(ObjPtr<mirror::Class> klass,
                                                        uint32_t field_offset) {
   DCHECK(klass != nullptr);
   ArtField* field = FindFieldWithOffset<kExactOffset>(klass->GetIFields(), field_offset);
@@ -382,7 +383,8 @@
 }
 
 template <bool kExactOffset>
-inline ArtField* ArtField::FindStaticFieldWithOffset(mirror::Class* klass, uint32_t field_offset) {
+inline ArtField* ArtField::FindStaticFieldWithOffset(ObjPtr<mirror::Class> klass,
+                                                     uint32_t field_offset) {
   DCHECK(klass != nullptr);
   return FindFieldWithOffset<kExactOffset>(klass->GetSFields(), field_offset);
 }
diff --git a/runtime/art_field.cc b/runtime/art_field.cc
index 3b4db0b..78c62d6 100644
--- a/runtime/art_field.cc
+++ b/runtime/art_field.cc
@@ -30,10 +30,6 @@
 
 namespace art {
 
-ArtField::ArtField() : access_flags_(0), field_dex_idx_(0), offset_(0) {
-  declaring_class_ = GcRoot<mirror::Class>(nullptr);
-}
-
 void ArtField::SetOffset(MemberOffset num_bytes) {
   DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
   if (kIsDebugBuild && Runtime::Current()->IsAotCompiler() &&
@@ -47,20 +43,23 @@
   offset_ = num_bytes.Uint32Value();
 }
 
-mirror::Class* ArtField::ProxyFindSystemClass(const char* descriptor) {
+ObjPtr<mirror::Class> ArtField::ProxyFindSystemClass(const char* descriptor) {
   DCHECK(GetDeclaringClass()->IsProxyClass());
   return Runtime::Current()->GetClassLinker()->FindSystemClass(Thread::Current(), descriptor);
 }
 
-mirror::Class* ArtField::ResolveGetType(uint32_t type_idx) {
+ObjPtr<mirror::Class> ArtField::ResolveGetType(uint32_t type_idx) {
   return Runtime::Current()->GetClassLinker()->ResolveType(type_idx, this);
 }
 
-mirror::String* ArtField::ResolveGetStringName(Thread* self, const DexFile& dex_file,
-                                               uint32_t string_idx, mirror::DexCache* dex_cache) {
+ObjPtr<mirror::String> ArtField::ResolveGetStringName(Thread* self,
+                                                      const DexFile& dex_file,
+                                                      uint32_t string_idx,
+                                                      ObjPtr<mirror::DexCache> dex_cache) {
   StackHandleScope<1> hs(self);
-  return Runtime::Current()->GetClassLinker()->ResolveString(
-      dex_file, string_idx, hs.NewHandle(dex_cache));
+  return Runtime::Current()->GetClassLinker()->ResolveString(dex_file,
+                                                             string_idx,
+                                                             hs.NewHandle(dex_cache));
 }
 
 }  // namespace art
diff --git a/runtime/art_field.h b/runtime/art_field.h
index 16e6c75..8ba383c 100644
--- a/runtime/art_field.h
+++ b/runtime/art_field.h
@@ -21,6 +21,7 @@
 
 #include "gc_root.h"
 #include "modifiers.h"
+#include "obj_ptr.h"
 #include "offsets.h"
 #include "primitive.h"
 #include "read_barrier_option.h"
@@ -39,12 +40,10 @@
 
 class ArtField FINAL {
  public:
-  ArtField();
-
   template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
-  mirror::Class* GetDeclaringClass() REQUIRES_SHARED(Locks::mutator_lock_);
+  ObjPtr<mirror::Class> GetDeclaringClass() REQUIRES_SHARED(Locks::mutator_lock_);
 
-  void SetDeclaringClass(mirror::Class *new_declaring_class)
+  void SetDeclaringClass(ObjPtr<mirror::Class> new_declaring_class)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   uint32_t GetAccessFlags() REQUIRES_SHARED(Locks::mutator_lock_);
@@ -87,68 +86,72 @@
   void SetOffset(MemberOffset num_bytes) REQUIRES_SHARED(Locks::mutator_lock_);
 
   // field access, null object for static fields
-  uint8_t GetBoolean(mirror::Object* object) REQUIRES_SHARED(Locks::mutator_lock_);
+  uint8_t GetBoolean(ObjPtr<mirror::Object> object) REQUIRES_SHARED(Locks::mutator_lock_);
 
   template<bool kTransactionActive>
-  void SetBoolean(mirror::Object* object, uint8_t z) REQUIRES_SHARED(Locks::mutator_lock_);
+  void SetBoolean(ObjPtr<mirror::Object> object, uint8_t z) REQUIRES_SHARED(Locks::mutator_lock_);
 
-  int8_t GetByte(mirror::Object* object) REQUIRES_SHARED(Locks::mutator_lock_);
+  int8_t GetByte(ObjPtr<mirror::Object> object) REQUIRES_SHARED(Locks::mutator_lock_);
 
   template<bool kTransactionActive>
-  void SetByte(mirror::Object* object, int8_t b) REQUIRES_SHARED(Locks::mutator_lock_);
+  void SetByte(ObjPtr<mirror::Object> object, int8_t b) REQUIRES_SHARED(Locks::mutator_lock_);
 
-  uint16_t GetChar(mirror::Object* object) REQUIRES_SHARED(Locks::mutator_lock_);
+  uint16_t GetChar(ObjPtr<mirror::Object> object) REQUIRES_SHARED(Locks::mutator_lock_);
 
   template<bool kTransactionActive>
-  void SetChar(mirror::Object* object, uint16_t c) REQUIRES_SHARED(Locks::mutator_lock_);
+  void SetChar(ObjPtr<mirror::Object> object, uint16_t c) REQUIRES_SHARED(Locks::mutator_lock_);
 
-  int16_t GetShort(mirror::Object* object) REQUIRES_SHARED(Locks::mutator_lock_);
+  int16_t GetShort(ObjPtr<mirror::Object> object) REQUIRES_SHARED(Locks::mutator_lock_);
 
   template<bool kTransactionActive>
-  void SetShort(mirror::Object* object, int16_t s) REQUIRES_SHARED(Locks::mutator_lock_);
+  void SetShort(ObjPtr<mirror::Object> object, int16_t s) REQUIRES_SHARED(Locks::mutator_lock_);
 
-  int32_t GetInt(mirror::Object* object) REQUIRES_SHARED(Locks::mutator_lock_);
+  int32_t GetInt(ObjPtr<mirror::Object> object) REQUIRES_SHARED(Locks::mutator_lock_);
 
   template<bool kTransactionActive>
-  void SetInt(mirror::Object* object, int32_t i) REQUIRES_SHARED(Locks::mutator_lock_);
+  void SetInt(ObjPtr<mirror::Object> object, int32_t i) REQUIRES_SHARED(Locks::mutator_lock_);
 
-  int64_t GetLong(mirror::Object* object) REQUIRES_SHARED(Locks::mutator_lock_);
+  int64_t GetLong(ObjPtr<mirror::Object> object) REQUIRES_SHARED(Locks::mutator_lock_);
 
   template<bool kTransactionActive>
-  void SetLong(mirror::Object* object, int64_t j) REQUIRES_SHARED(Locks::mutator_lock_);
+  void SetLong(ObjPtr<mirror::Object> object, int64_t j) REQUIRES_SHARED(Locks::mutator_lock_);
 
-  float GetFloat(mirror::Object* object) REQUIRES_SHARED(Locks::mutator_lock_);
+  float GetFloat(ObjPtr<mirror::Object> object) REQUIRES_SHARED(Locks::mutator_lock_);
 
   template<bool kTransactionActive>
-  void SetFloat(mirror::Object* object, float f) REQUIRES_SHARED(Locks::mutator_lock_);
+  void SetFloat(ObjPtr<mirror::Object> object, float f) REQUIRES_SHARED(Locks::mutator_lock_);
 
-  double GetDouble(mirror::Object* object) REQUIRES_SHARED(Locks::mutator_lock_);
+  double GetDouble(ObjPtr<mirror::Object> object) REQUIRES_SHARED(Locks::mutator_lock_);
 
   template<bool kTransactionActive>
-  void SetDouble(mirror::Object* object, double d) REQUIRES_SHARED(Locks::mutator_lock_);
+  void SetDouble(ObjPtr<mirror::Object> object, double d) REQUIRES_SHARED(Locks::mutator_lock_);
 
-  mirror::Object* GetObject(mirror::Object* object) REQUIRES_SHARED(Locks::mutator_lock_);
+  ObjPtr<mirror::Object> GetObject(ObjPtr<mirror::Object> object)
+      REQUIRES_SHARED(Locks::mutator_lock_);
 
   template<bool kTransactionActive>
-  void SetObject(mirror::Object* object, mirror::Object* l)
+  void SetObject(ObjPtr<mirror::Object> object, ObjPtr<mirror::Object> l)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   // Raw field accesses.
-  uint32_t Get32(mirror::Object* object) REQUIRES_SHARED(Locks::mutator_lock_);
+  uint32_t Get32(ObjPtr<mirror::Object> object) REQUIRES_SHARED(Locks::mutator_lock_);
 
   template<bool kTransactionActive>
-  void Set32(mirror::Object* object, uint32_t new_value)
+  void Set32(ObjPtr<mirror::Object> object, uint32_t new_value)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
-  uint64_t Get64(mirror::Object* object) REQUIRES_SHARED(Locks::mutator_lock_);
+  uint64_t Get64(ObjPtr<mirror::Object> object) REQUIRES_SHARED(Locks::mutator_lock_);
 
   template<bool kTransactionActive>
-  void Set64(mirror::Object* object, uint64_t new_value) REQUIRES_SHARED(Locks::mutator_lock_);
+  void Set64(ObjPtr<mirror::Object> object, uint64_t new_value)
+      REQUIRES_SHARED(Locks::mutator_lock_);
 
-  mirror::Object* GetObj(mirror::Object* object) REQUIRES_SHARED(Locks::mutator_lock_);
+  template<class MirrorType = mirror::Object>
+  ObjPtr<MirrorType> GetObj(ObjPtr<mirror::Object> object)
+      REQUIRES_SHARED(Locks::mutator_lock_);
 
   template<bool kTransactionActive>
-  void SetObj(mirror::Object* object, mirror::Object* new_value)
+  void SetObj(ObjPtr<mirror::Object> object, ObjPtr<mirror::Object> new_value)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   // NO_THREAD_SAFETY_ANALYSIS since we don't know what the callback requires.
@@ -163,20 +166,20 @@
   // If kExactOffset is true then we only find the matching offset, not the field containing the
   // offset.
   template <bool kExactOffset = true>
-  static ArtField* FindInstanceFieldWithOffset(mirror::Class* klass, uint32_t field_offset)
+  static ArtField* FindInstanceFieldWithOffset(ObjPtr<mirror::Class> klass, uint32_t field_offset)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   // Returns a static field with this offset in the given class or null if not found.
   // If kExactOffset is true then we only find the matching offset, not the field containing the
   // offset.
   template <bool kExactOffset = true>
-  static ArtField* FindStaticFieldWithOffset(mirror::Class* klass, uint32_t field_offset)
+  static ArtField* FindStaticFieldWithOffset(ObjPtr<mirror::Class> klass, uint32_t field_offset)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   const char* GetName() REQUIRES_SHARED(Locks::mutator_lock_);
 
   // Resolves / returns the name from the dex cache.
-  mirror::String* GetStringName(Thread* self, bool resolve)
+  ObjPtr<mirror::String> GetStringName(Thread* self, bool resolve)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   const char* GetTypeDescriptor() REQUIRES_SHARED(Locks::mutator_lock_);
@@ -186,11 +189,11 @@
   bool IsPrimitiveType() REQUIRES_SHARED(Locks::mutator_lock_);
 
   template <bool kResolve>
-  mirror::Class* GetType() REQUIRES_SHARED(Locks::mutator_lock_);
+  ObjPtr<mirror::Class> GetType() REQUIRES_SHARED(Locks::mutator_lock_);
 
   size_t FieldSize() REQUIRES_SHARED(Locks::mutator_lock_);
 
-  mirror::DexCache* GetDexCache() REQUIRES_SHARED(Locks::mutator_lock_);
+  ObjPtr<mirror::DexCache> GetDexCache() REQUIRES_SHARED(Locks::mutator_lock_);
 
   const DexFile* GetDexFile() REQUIRES_SHARED(Locks::mutator_lock_);
 
@@ -204,22 +207,24 @@
       REQUIRES_SHARED(Locks::mutator_lock_);
 
  private:
-  mirror::Class* ProxyFindSystemClass(const char* descriptor)
+  ObjPtr<mirror::Class> ProxyFindSystemClass(const char* descriptor)
       REQUIRES_SHARED(Locks::mutator_lock_);
-  mirror::Class* ResolveGetType(uint32_t type_idx) REQUIRES_SHARED(Locks::mutator_lock_);
-  mirror::String* ResolveGetStringName(Thread* self, const DexFile& dex_file, uint32_t string_idx,
-                                       mirror::DexCache* dex_cache)
+  ObjPtr<mirror::Class> ResolveGetType(uint32_t type_idx) REQUIRES_SHARED(Locks::mutator_lock_);
+  ObjPtr<mirror::String> ResolveGetStringName(Thread* self,
+                                              const DexFile& dex_file,
+                                              uint32_t string_idx,
+                                              ObjPtr<mirror::DexCache> dex_cache)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   GcRoot<mirror::Class> declaring_class_;
 
-  uint32_t access_flags_;
+  uint32_t access_flags_ = 0;
 
   // Dex cache index of field id
-  uint32_t field_dex_idx_;
+  uint32_t field_dex_idx_ = 0;
 
   // Offset of field within an instance or in the Class' static fields
-  uint32_t offset_;
+  uint32_t offset_ = 0;
 };
 
 }  // namespace art
diff --git a/runtime/check_jni.cc b/runtime/check_jni.cc
index 9f07702..c671b81 100644
--- a/runtime/check_jni.cc
+++ b/runtime/check_jni.cc
@@ -274,7 +274,7 @@
       AbortF("field operation on NULL object: %p", java_object);
       return false;
     }
-    if (!Runtime::Current()->GetHeap()->IsValidObjectAddress(o.Decode())) {
+    if (!Runtime::Current()->GetHeap()->IsValidObjectAddress(o)) {
       Runtime::Current()->GetHeap()->DumpSpaces(LOG_STREAM(ERROR));
       AbortF("field operation on invalid %s: %p",
              ToStr<IndirectRefKind>(GetIndirectRefKind(java_object)).c_str(),
@@ -334,7 +334,7 @@
     }
     if (invoke != kVirtual) {
       ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(jc);
-      if (!m->GetDeclaringClass()->IsAssignableFrom(c.Decode())) {
+      if (!m->GetDeclaringClass()->IsAssignableFrom(c)) {
         AbortF("can't call %s %s with class %s", invoke == kStatic ? "static" : "nonvirtual",
             PrettyMethod(m).c_str(), PrettyClass(c).c_str());
         return false;
@@ -388,7 +388,7 @@
       return false;
     }
     ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(java_class);
-    if (!m->GetDeclaringClass()->IsAssignableFrom(c.Decode())) {
+    if (!m->GetDeclaringClass()->IsAssignableFrom(c)) {
       AbortF("can't call static %s on class %s", PrettyMethod(m).c_str(), PrettyClass(c).c_str());
       return false;
     }
@@ -939,7 +939,7 @@
         ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(jc);
         if (c == nullptr) {
           *msg += "NULL";
-        } else if (!Runtime::Current()->GetHeap()->IsValidObjectAddress(c.Decode())) {
+        } 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);
@@ -1108,7 +1108,7 @@
     }
 
     ObjPtr<mirror::Array> a = soa.Decode<mirror::Array>(java_array);
-    if (UNLIKELY(!Runtime::Current()->GetHeap()->IsValidObjectAddress(a.Decode()))) {
+    if (UNLIKELY(!Runtime::Current()->GetHeap()->IsValidObjectAddress(a))) {
       Runtime::Current()->GetHeap()->DumpSpaces(LOG_STREAM(ERROR));
       AbortF("jarray is an invalid %s: %p (%p)",
              ToStr<IndirectRefKind>(GetIndirectRefKind(java_array)).c_str(),
diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h
index 51e5aae..378da57 100644
--- a/runtime/class_linker-inl.h
+++ b/runtime/class_linker-inl.h
@@ -63,6 +63,7 @@
 }
 
 inline mirror::String* ClassLinker::ResolveString(uint32_t string_idx, ArtMethod* referrer) {
+  Thread::PoisonObjectPointersIfDebug();
   mirror::Class* declaring_class = referrer->GetDeclaringClass();
   // MethodVerifier refuses methods with string_idx out of bounds.
   DCHECK_LT(string_idx, declaring_class->GetDexFile().NumStringIds());;
@@ -70,7 +71,6 @@
         mirror::StringDexCachePair::Lookup(declaring_class->GetDexCacheStrings(),
                                            string_idx,
                                            mirror::DexCache::kDexCacheStringCacheSize).Read();
-  Thread::PoisonObjectPointersIfDebug();
   if (UNLIKELY(string == nullptr)) {
     StackHandleScope<1> hs(Thread::Current());
     Handle<mirror::DexCache> dex_cache(hs.NewHandle(declaring_class->GetDexCache()));
@@ -84,8 +84,8 @@
 }
 
 inline mirror::Class* ClassLinker::ResolveType(uint16_t type_idx, ArtMethod* referrer) {
-  mirror::Class* resolved_type = referrer->GetDexCacheResolvedType(type_idx, image_pointer_size_);
   Thread::PoisonObjectPointersIfDebug();
+  mirror::Class* resolved_type = referrer->GetDexCacheResolvedType(type_idx, image_pointer_size_);
   if (UNLIKELY(resolved_type == nullptr)) {
     mirror::Class* declaring_class = referrer->GetDeclaringClass();
     StackHandleScope<2> hs(Thread::Current());
@@ -100,10 +100,10 @@
 }
 
 inline mirror::Class* ClassLinker::ResolveType(uint16_t type_idx, ArtField* referrer) {
-  mirror::Class* declaring_class = referrer->GetDeclaringClass();
+  Thread::PoisonObjectPointersIfDebug();
+  ObjPtr<mirror::Class> declaring_class = referrer->GetDeclaringClass();
   mirror::DexCache* dex_cache_ptr = declaring_class->GetDexCache();
   mirror::Class* resolved_type = dex_cache_ptr->GetResolvedType(type_idx);
-  Thread::PoisonObjectPointersIfDebug();
   if (UNLIKELY(resolved_type == nullptr)) {
     StackHandleScope<2> hs(Thread::Current());
     Handle<mirror::DexCache> dex_cache(hs.NewHandle(dex_cache_ptr));
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 7dea614..06a8243 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -1090,7 +1090,7 @@
 }
 
 static mirror::String* GetDexPathListElementName(ScopedObjectAccessUnchecked& soa,
-                                                 mirror::Object* element)
+                                                 ObjPtr<mirror::Object> element)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   ArtField* const dex_file_field =
       soa.DecodeField(WellKnownClasses::dalvik_system_DexPathList__Element_dexFile);
@@ -1100,11 +1100,11 @@
   DCHECK(dex_file_name_field != nullptr);
   DCHECK(element != nullptr);
   CHECK_EQ(dex_file_field->GetDeclaringClass(), element->GetClass()) << PrettyTypeOf(element);
-  mirror::Object* dex_file = dex_file_field->GetObject(element);
+  ObjPtr<mirror::Object> dex_file = dex_file_field->GetObject(element);
   if (dex_file == nullptr) {
     return nullptr;
   }
-  mirror::Object* const name_object = dex_file_name_field->GetObject(dex_file);
+  ObjPtr<mirror::Object> name_object = dex_file_name_field->GetObject(dex_file);
   if (name_object != nullptr) {
     return name_object->AsString();
   }
@@ -1131,28 +1131,28 @@
       // Unsupported class loader.
       return false;
     }
-    mirror::Object* dex_path_list = dex_path_list_field->GetObject(class_loader);
+    ObjPtr<mirror::Object> dex_path_list = dex_path_list_field->GetObject(class_loader);
     if (dex_path_list != nullptr) {
       // DexPathList has an array dexElements of Elements[] which each contain a dex file.
-      mirror::Object* dex_elements_obj = dex_elements_field->GetObject(dex_path_list);
+      ObjPtr<mirror::Object> dex_elements_obj = dex_elements_field->GetObject(dex_path_list);
       // Loop through each dalvik.system.DexPathList$Element's dalvik.system.DexFile and look
       // at the mCookie which is a DexFile vector.
       if (dex_elements_obj != nullptr) {
-        mirror::ObjectArray<mirror::Object>* dex_elements =
+        ObjPtr<mirror::ObjectArray<mirror::Object>> dex_elements =
             dex_elements_obj->AsObjectArray<mirror::Object>();
         // Reverse order since we insert the parent at the front.
         for (int32_t i = dex_elements->GetLength() - 1; i >= 0; --i) {
-          mirror::Object* const element = dex_elements->GetWithoutChecks(i);
+          ObjPtr<mirror::Object> element = dex_elements->GetWithoutChecks(i);
           if (element == nullptr) {
             *error_msg = StringPrintf("Null dex element at index %d", i);
             return false;
           }
-          mirror::String* const name = GetDexPathListElementName(soa, element);
+          ObjPtr<mirror::String> const name = GetDexPathListElementName(soa, element);
           if (name == nullptr) {
             *error_msg = StringPrintf("Null name for dex element at index %d", i);
             return false;
           }
-          out_dex_file_names->push_front(name);
+          out_dex_file_names->push_front(name.Decode());
         }
       }
     }
@@ -2395,12 +2395,12 @@
   ArtField* const cookie_field = soa.DecodeField(WellKnownClasses::dalvik_system_DexFile_cookie);
   ArtField* const dex_file_field =
       soa.DecodeField(WellKnownClasses::dalvik_system_DexPathList__Element_dexFile);
-  mirror::Object* dex_path_list =
+  ObjPtr<mirror::Object> dex_path_list =
       soa.DecodeField(WellKnownClasses::dalvik_system_PathClassLoader_pathList)->
       GetObject(class_loader.Get());
   if (dex_path_list != nullptr && dex_file_field != nullptr && cookie_field != nullptr) {
     // DexPathList has an array dexElements of Elements[] which each contain a dex file.
-    mirror::Object* dex_elements_obj =
+    ObjPtr<mirror::Object> dex_elements_obj =
         soa.DecodeField(WellKnownClasses::dalvik_system_DexPathList_dexElements)->
         GetObject(dex_path_list);
     // Loop through each dalvik.system.DexPathList$Element's dalvik.system.DexFile and look
@@ -2409,14 +2409,14 @@
       Handle<mirror::ObjectArray<mirror::Object>> dex_elements =
           hs.NewHandle(dex_elements_obj->AsObjectArray<mirror::Object>());
       for (int32_t i = 0; i < dex_elements->GetLength(); ++i) {
-        mirror::Object* element = dex_elements->GetWithoutChecks(i);
+        ObjPtr<mirror::Object> element = dex_elements->GetWithoutChecks(i);
         if (element == nullptr) {
           // Should never happen, fall back to java code to throw a NPE.
           break;
         }
-        mirror::Object* dex_file = dex_file_field->GetObject(element);
+        ObjPtr<mirror::Object> dex_file = dex_file_field->GetObject(element);
         if (dex_file != nullptr) {
-          mirror::LongArray* long_array = cookie_field->GetObject(dex_file)->AsLongArray();
+          ObjPtr<mirror::LongArray> long_array = cookie_field->GetObject(dex_file)->AsLongArray();
           if (long_array == nullptr) {
             // This should never happen so log a warning.
             LOG(WARNING) << "Null DexFile::mCookie for " << descriptor;
@@ -8256,16 +8256,18 @@
   ScopedObjectAccessUnchecked soa(self);
 
   // For now, create a libcore-level DexFile for each ART DexFile. This "explodes" multidex.
-  StackHandleScope<10> hs(self);
+  StackHandleScope<11> hs(self);
 
   ArtField* dex_elements_field =
       soa.DecodeField(WellKnownClasses::dalvik_system_DexPathList_dexElements);
 
-  mirror::Class* dex_elements_class = dex_elements_field->GetType<true>();
-  DCHECK(dex_elements_class != nullptr);
+  Handle<mirror::Class> dex_elements_class(hs.NewHandle(dex_elements_field->GetType<true>()));
+  DCHECK(dex_elements_class.Get() != nullptr);
   DCHECK(dex_elements_class->IsArrayClass());
   Handle<mirror::ObjectArray<mirror::Object>> h_dex_elements(hs.NewHandle(
-      mirror::ObjectArray<mirror::Object>::Alloc(self, dex_elements_class, dex_files.size())));
+      mirror::ObjectArray<mirror::Object>::Alloc(self,
+                                                 dex_elements_class.Get(),
+                                                 dex_files.size())));
   Handle<mirror::Class> h_dex_element_class =
       hs.NewHandle(dex_elements_class->GetComponentType());
 
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 451b752..3c12b18 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -243,10 +243,10 @@
         kRuntimePointerSize));
   }
 
-  void AssertField(mirror::Class* klass, ArtField* field)
+  void AssertField(ObjPtr<mirror::Class> klass, ArtField* field)
       REQUIRES_SHARED(Locks::mutator_lock_) {
     EXPECT_TRUE(field != nullptr);
-    EXPECT_EQ(klass, field->GetDeclaringClass());
+    EXPECT_OBJ_PTR_EQ(klass, field->GetDeclaringClass());
     EXPECT_TRUE(field->GetName() != nullptr);
     EXPECT_TRUE(field->GetType<true>() != nullptr);
   }
@@ -358,7 +358,7 @@
     MemberOffset current_ref_offset = start_ref_offset;
     for (size_t i = 0; i < klass->NumInstanceFields(); i++) {
       ArtField* field = klass->GetInstanceField(i);
-      mirror::Class* field_type = field->GetType<true>();
+      ObjPtr<mirror::Class> field_type = field->GetType<true>();
       ASSERT_TRUE(field_type != nullptr);
       if (!field->IsPrimitiveType()) {
         ASSERT_TRUE(!field_type->IsPrimitive());
@@ -1018,8 +1018,8 @@
                                                         "Ljava/lang/String;");
   EXPECT_EQ(s8->GetTypeAsPrimitiveType(), Primitive::kPrimNot);
   EXPECT_TRUE(s8->GetObject(statics.Get())->AsString()->Equals("android"));
-  s8->SetObject<false>(s8->GetDeclaringClass(),
-                       mirror::String::AllocFromModifiedUtf8(soa.Self(), "robot"));
+  mirror::String* str_value = mirror::String::AllocFromModifiedUtf8(soa.Self(), "robot");
+  s8->SetObject<false>(s8->GetDeclaringClass(), str_value);
 
   // TODO: Remove EXPECT_FALSE when GCC can handle EXPECT_EQ
   // http://code.google.com/p/googletest/issues/detail?id=322
diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc
index eda1ddd..ea07195 100644
--- a/runtime/common_runtime_test.cc
+++ b/runtime/common_runtime_test.cc
@@ -523,12 +523,12 @@
   ArtField* cookie_field = soa.DecodeField(WellKnownClasses::dalvik_system_DexFile_cookie);
   ArtField* dex_file_field =
       soa.DecodeField(WellKnownClasses::dalvik_system_DexPathList__Element_dexFile);
-  mirror::Object* dex_path_list =
+  ObjPtr<mirror::Object> dex_path_list =
       soa.DecodeField(WellKnownClasses::dalvik_system_PathClassLoader_pathList)->
       GetObject(class_loader.Get());
   if (dex_path_list != nullptr && dex_file_field!= nullptr && cookie_field != nullptr) {
     // DexPathList has an array dexElements of Elements[] which each contain a dex file.
-    mirror::Object* dex_elements_obj =
+    ObjPtr<mirror::Object> dex_elements_obj =
         soa.DecodeField(WellKnownClasses::dalvik_system_DexPathList_dexElements)->
         GetObject(dex_path_list);
     // Loop through each dalvik.system.DexPathList$Element's dalvik.system.DexFile and look
@@ -537,14 +537,14 @@
       Handle<mirror::ObjectArray<mirror::Object>> dex_elements =
           hs.NewHandle(dex_elements_obj->AsObjectArray<mirror::Object>());
       for (int32_t i = 0; i < dex_elements->GetLength(); ++i) {
-        mirror::Object* element = dex_elements->GetWithoutChecks(i);
+        ObjPtr<mirror::Object> element = dex_elements->GetWithoutChecks(i);
         if (element == nullptr) {
           // Should never happen, fall back to java code to throw a NPE.
           break;
         }
-        mirror::Object* dex_file = dex_file_field->GetObject(element);
+        ObjPtr<mirror::Object> dex_file = dex_file_field->GetObject(element);
         if (dex_file != nullptr) {
-          mirror::LongArray* long_array = cookie_field->GetObject(dex_file)->AsLongArray();
+          ObjPtr<mirror::LongArray> long_array = cookie_field->GetObject(dex_file)->AsLongArray();
           DCHECK(long_array != nullptr);
           int32_t long_array_size = long_array->GetLength();
           for (int32_t j = kDexFileIndexStart; j < long_array_size; ++j) {
diff --git a/runtime/common_runtime_test.h b/runtime/common_runtime_test.h
index a7948e4..2158d81 100644
--- a/runtime/common_runtime_test.h
+++ b/runtime/common_runtime_test.h
@@ -25,10 +25,18 @@
 #include "arch/instruction_set.h"
 #include "base/mutex.h"
 #include "globals.h"
+// TODO: Add inl file and avoid including inl.
+#include "obj_ptr-inl.h"
 #include "os.h"
 
 namespace art {
 
+// OBJ pointer helpers to avoid needing .Decode everywhere.
+#define EXPECT_OBJ_PTR_EQ(a, b) EXPECT_EQ(MakeObjPtr(a).Decode(), MakeObjPtr(b).Decode());
+#define ASSERT_OBJ_PTR_EQ(a, b) ASSERT_EQ(MakeObjPtr(a).Decode(), MakeObjPtr(b).Decode());
+#define EXPECT_OBJ_PTR_NE(a, b) EXPECT_NE(MakeObjPtr(a).Decode(), MakeObjPtr(b).Decode());
+#define ASSERT_OBJ_PTR_NE(a, b) ASSERT_NE(MakeObjPtr(a).Decode(), MakeObjPtr(b).Decode());
+
 class ClassLinker;
 class CompilerCallbacks;
 class DexFile;
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 0206cae..1bdb0fc 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -46,6 +46,7 @@
 #include "mirror/object_array-inl.h"
 #include "mirror/string-inl.h"
 #include "mirror/throwable.h"
+#include "obj_ptr-inl.h"
 #include "reflection.h"
 #include "safe_map.h"
 #include "scoped_thread_state_change-inl.h"
@@ -985,7 +986,7 @@
   gRegistry->DisposeObject(object_id, reference_count);
 }
 
-JDWP::JdwpTypeTag Dbg::GetTypeTag(mirror::Class* klass) {
+JDWP::JdwpTypeTag Dbg::GetTypeTag(ObjPtr<mirror::Class> klass) {
   DCHECK(klass != nullptr);
   if (klass->IsArrayClass()) {
     return JDWP::TT_ARRAY;
@@ -1367,12 +1368,12 @@
   return m == event_location.method;
 }
 
-bool Dbg::MatchType(mirror::Class* event_class, JDWP::RefTypeId class_id) {
+bool Dbg::MatchType(ObjPtr<mirror::Class> event_class, JDWP::RefTypeId class_id) {
   if (event_class == nullptr) {
     return false;
   }
   JDWP::JdwpError error;
-  mirror::Class* expected_class = DecodeClass(class_id, &error);
+  ObjPtr<mirror::Class> expected_class = DecodeClass(class_id, &error);
   CHECK(expected_class != nullptr);
   return expected_class->IsAssignableFrom(event_class);
 }
@@ -1742,7 +1743,7 @@
       return field_value;
 
     case Primitive::kPrimNot:
-      field_value.SetL(f->GetObject(o));
+      field_value.SetL(f->GetObject(o).Decode());
       return field_value;
 
     case Primitive::kPrimVoid:
@@ -1868,7 +1869,7 @@
         return JDWP::ERR_INVALID_OBJECT;
       }
       if (v != nullptr) {
-        mirror::Class* field_type;
+        ObjPtr<mirror::Class> field_type;
         {
           StackHandleScope<2> hs(Thread::Current());
           HandleWrapper<mirror::Object> h_v(hs.NewHandleWrapper(&v));
@@ -1994,8 +1995,7 @@
   CHECK(thread_object != nullptr) << error;
   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));
+  ObjPtr<mirror::String> s(java_lang_Thread_name_field->GetObject(thread_object));
   if (s != nullptr) {
     *name = s->ToModifiedUtf8();
   }
@@ -2021,7 +2021,7 @@
     CHECK(c != nullptr);
     ArtField* f = soa.DecodeField(WellKnownClasses::java_lang_Thread_group);
     CHECK(f != nullptr);
-    mirror::Object* group = f->GetObject(thread_object);
+    ObjPtr<mirror::Object> group = f->GetObject(thread_object);
     CHECK(group != nullptr);
     JDWP::ObjectId thread_group_id = gRegistry->Add(group);
     expandBufAddObjectId(pReply, thread_group_id);
@@ -2063,7 +2063,7 @@
   ScopedAssertNoThreadSuspension ants("Debugger: GetThreadGroupName");
   ArtField* f = soa.DecodeField(WellKnownClasses::java_lang_ThreadGroup_name);
   CHECK(f != nullptr);
-  mirror::String* s = reinterpret_cast<mirror::String*>(f->GetObject(thread_group));
+  ObjPtr<mirror::String> s = f->GetObject(thread_group)->AsString();
 
   std::string thread_group_name(s->ToModifiedUtf8());
   expandBufAddUtf8String(pReply, thread_group_name);
@@ -2077,7 +2077,7 @@
   if (error != JDWP::ERR_NONE) {
     return error;
   }
-  mirror::Object* parent;
+  ObjPtr<mirror::Object> parent;
   {
     ScopedAssertNoThreadSuspension ants("Debugger: GetThreadGroupParent");
     ArtField* f = soa.DecodeField(WellKnownClasses::java_lang_ThreadGroup_parent);
@@ -2104,12 +2104,12 @@
 
   // Get the ThreadGroup[] "groups" out of this thread group...
   ArtField* groups_field = soa.DecodeField(WellKnownClasses::java_lang_ThreadGroup_groups);
-  mirror::Object* groups_array = groups_field->GetObject(thread_group);
+  ObjPtr<mirror::Object> groups_array = groups_field->GetObject(thread_group);
 
   CHECK(groups_array != nullptr);
   CHECK(groups_array->IsObjectArray());
 
-  mirror::ObjectArray<mirror::Object>* groups_array_as_array =
+  ObjPtr<mirror::ObjectArray<mirror::Object>> groups_array_as_array =
       groups_array->AsObjectArray<mirror::Object>();
 
   // Copy the first 'size' elements out of the array into the result.
@@ -2154,7 +2154,7 @@
 JDWP::ObjectId Dbg::GetSystemThreadGroupId() {
   ScopedObjectAccessUnchecked soa(Thread::Current());
   ArtField* f = soa.DecodeField(WellKnownClasses::java_lang_ThreadGroup_systemThreadGroup);
-  mirror::Object* group = f->GetObject(f->GetDeclaringClass());
+  ObjPtr<mirror::Object> group = f->GetObject(f->GetDeclaringClass());
   return gRegistry->Add(group);
 }
 
@@ -2252,7 +2252,7 @@
   }
   ArtField* thread_group_field = soa.DecodeField(WellKnownClasses::java_lang_Thread_group);
   DCHECK(thread_group_field != nullptr);
-  mirror::Object* group = thread_group_field->GetObject(peer);
+  ObjPtr<mirror::Object> group = thread_group_field->GetObject(peer);
   return (group == desired_thread_group);
 }
 
diff --git a/runtime/debugger.h b/runtime/debugger.h
index 7398c4e..5d0315e 100644
--- a/runtime/debugger.h
+++ b/runtime/debugger.h
@@ -31,6 +31,7 @@
 #include "jdwp/jdwp.h"
 #include "jni.h"
 #include "jvalue.h"
+#include "obj_ptr.h"
 #include "thread.h"
 #include "thread_state.h"
 
@@ -317,7 +318,7 @@
                             const JDWP::EventLocation& event_location)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
-  static bool MatchType(mirror::Class* event_class, JDWP::RefTypeId class_id)
+  static bool MatchType(ObjPtr<mirror::Class> event_class, JDWP::RefTypeId class_id)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   static bool MatchField(JDWP::RefTypeId expected_type_id, JDWP::FieldId expected_field_id,
@@ -689,7 +690,7 @@
   static JDWP::JdwpTag TagFromObject(const ScopedObjectAccessUnchecked& soa, mirror::Object* o)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
-  static JDWP::JdwpTypeTag GetTypeTag(mirror::Class* klass)
+  static JDWP::JdwpTypeTag GetTypeTag(ObjPtr<mirror::Class> klass)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   static JDWP::FieldId ToFieldId(const ArtField* f)
diff --git a/runtime/dex_file_annotations.cc b/runtime/dex_file_annotations.cc
index 5763479..feb75a8 100644
--- a/runtime/dex_file_annotations.cc
+++ b/runtime/dex_file_annotations.cc
@@ -54,7 +54,7 @@
 const DexFile::AnnotationSetItem* FindAnnotationSetForField(ArtField* field)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   const DexFile* dex_file = field->GetDexFile();
-  mirror::Class* klass = field->GetDeclaringClass();
+  ObjPtr<mirror::Class> klass = field->GetDeclaringClass();
   const DexFile::AnnotationsDirectoryItem* annotations_dir =
       dex_file->GetAnnotationsDirectory(*klass->GetClassDef());
   if (annotations_dir == nullptr) {
@@ -302,7 +302,7 @@
     REQUIRES_SHARED(Locks::mutator_lock_) {
   const DexFile& dex_file = klass->GetDexFile();
   Thread* self = Thread::Current();
-  mirror::Object* element_object = nullptr;
+  ObjPtr<mirror::Object> element_object = nullptr;
   bool set_object = false;
   Primitive::Type primitive_type = Primitive::kPrimVoid;
   const uint8_t* annotation = *annotation_ptr;
@@ -577,7 +577,7 @@
   }
 
   if (set_object) {
-    annotation_value->value_.SetL(element_object);
+    annotation_value->value_.SetL(element_object.Decode());
   }
 
   return true;
diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h
index 99b8805..e37db7d 100644
--- a/runtime/entrypoints/entrypoint_utils-inl.h
+++ b/runtime/entrypoints/entrypoint_utils-inl.h
@@ -410,14 +410,15 @@
     DCHECK(self->IsExceptionPending());  // Throw exception and unwind.
     return nullptr;  // Failure.
   }
-  mirror::Class* fields_class = resolved_field->GetDeclaringClass();
+  ObjPtr<mirror::Class> fields_class = resolved_field->GetDeclaringClass();
   if (access_check) {
     if (UNLIKELY(resolved_field->IsStatic() != is_static)) {
       ThrowIncompatibleClassChangeErrorField(resolved_field, is_static, referrer);
       return nullptr;
     }
     mirror::Class* referring_class = referrer->GetDeclaringClass();
-    if (UNLIKELY(!referring_class->CheckResolvedFieldAccess(fields_class, resolved_field,
+    if (UNLIKELY(!referring_class->CheckResolvedFieldAccess(fields_class,
+                                                            resolved_field,
                                                             field_idx))) {
       DCHECK(self->IsExceptionPending());  // Throw exception and unwind.
       return nullptr;  // Failure.
@@ -696,7 +697,7 @@
     // Incompatible class change.
     return nullptr;
   }
-  mirror::Class* fields_class = resolved_field->GetDeclaringClass();
+  ObjPtr<mirror::Class> fields_class = resolved_field->GetDeclaringClass();
   if (is_static) {
     // Check class is initialized else fail so that we can contend to initialize the class with
     // other threads that may be racing to do this.
diff --git a/runtime/entrypoints/quick/quick_field_entrypoints.cc b/runtime/entrypoints/quick/quick_field_entrypoints.cc
index 5b65029..70eb1de 100644
--- a/runtime/entrypoints/quick/quick_field_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_field_entrypoints.cc
@@ -151,14 +151,14 @@
                                   StaticObjectRead,
                                   sizeof(mirror::HeapReference<mirror::Object>));
   if (LIKELY(field != nullptr)) {
-    return field->GetObj(field->GetDeclaringClass());
+    return field->GetObj(field->GetDeclaringClass()).Decode();
   }
   field = FindFieldFromCode<StaticObjectRead, true>(field_idx,
                                                     referrer,
                                                     self,
                                                     sizeof(mirror::HeapReference<mirror::Object>));
   if (LIKELY(field != nullptr)) {
-    return field->GetObj(field->GetDeclaringClass());
+    return field->GetObj(field->GetDeclaringClass()).Decode();
   }
   return nullptr;  // Will throw exception by checking with Thread::Current.
 }
@@ -299,7 +299,7 @@
                                   InstanceObjectRead,
                                   sizeof(mirror::HeapReference<mirror::Object>));
   if (LIKELY(field != nullptr && obj != nullptr)) {
-    return field->GetObj(obj);
+    return field->GetObj(obj).Decode();
   }
   field = FindInstanceField<InstanceObjectRead, true>(field_idx,
                                                       referrer,
@@ -307,7 +307,7 @@
                                                       sizeof(mirror::HeapReference<mirror::Object>),
                                                       &obj);
   if (LIKELY(field != nullptr)) {
-    return field->GetObj(obj);
+    return field->GetObj(obj).Decode();
   }
   return nullptr;  // Will throw exception by checking with Thread::Current.
 }
diff --git a/runtime/gc_root-inl.h b/runtime/gc_root-inl.h
index ae8a38f..11ccd33 100644
--- a/runtime/gc_root-inl.h
+++ b/runtime/gc_root-inl.h
@@ -21,6 +21,7 @@
 
 #include <sstream>
 
+#include "obj_ptr-inl.h"
 #include "read_barrier-inl.h"
 
 namespace art {
@@ -31,10 +32,15 @@
   return down_cast<MirrorType*>(
       ReadBarrier::BarrierForRoot<mirror::Object, kReadBarrierOption>(&root_, gc_root_source));
 }
+
 template<class MirrorType>
 inline GcRoot<MirrorType>::GcRoot(MirrorType* ref)
     : root_(mirror::CompressedReference<mirror::Object>::FromMirrorPtr(ref)) { }
 
+template<class MirrorType>
+inline GcRoot<MirrorType>::GcRoot(ObjPtr<MirrorType, kIsDebugBuild> ref)
+    : GcRoot(ref.Decode()) { }
+
 inline std::string RootInfo::ToString() const {
   std::ostringstream oss;
   Describe(oss);
diff --git a/runtime/gc_root.h b/runtime/gc_root.h
index 0a98f55..85cd0a4 100644
--- a/runtime/gc_root.h
+++ b/runtime/gc_root.h
@@ -24,6 +24,7 @@
 namespace art {
 class ArtField;
 class ArtMethod;
+template<class MirrorType, bool kPoison> class ObjPtr;
 
 namespace mirror {
 class Object;
@@ -196,7 +197,10 @@
   }
 
   ALWAYS_INLINE GcRoot() {}
-  explicit ALWAYS_INLINE GcRoot(MirrorType* ref) REQUIRES_SHARED(Locks::mutator_lock_);
+  explicit ALWAYS_INLINE GcRoot(MirrorType* ref)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+  explicit ALWAYS_INLINE GcRoot(ObjPtr<MirrorType, kIsDebugBuild> ref)
+      REQUIRES_SHARED(Locks::mutator_lock_);
 
  private:
   // Root visitors take pointers to root_ and place them in CompressedReference** arrays. We use a
diff --git a/runtime/handle_scope-inl.h b/runtime/handle_scope-inl.h
index 75a0391..1814746 100644
--- a/runtime/handle_scope-inl.h
+++ b/runtime/handle_scope-inl.h
@@ -135,6 +135,12 @@
   GetReferences()[i].Assign(object);
 }
 
+template<class MirrorType, bool kPoison>
+inline MutableHandle<MirrorType> StackHandleScopeCollection::NewHandle(
+    ObjPtr<MirrorType, kPoison> ptr) {
+  return NewHandle(ptr.Decode());
+}
+
 }  // namespace art
 
 #endif  // ART_RUNTIME_HANDLE_SCOPE_INL_H_
diff --git a/runtime/handle_scope.h b/runtime/handle_scope.h
index 2b283ae..fc729a5 100644
--- a/runtime/handle_scope.h
+++ b/runtime/handle_scope.h
@@ -252,6 +252,10 @@
     return scopes_.top()->NewHandle(object);
   }
 
+  template<class MirrorType, bool kPoison>
+  MutableHandle<MirrorType> NewHandle(ObjPtr<MirrorType, kPoison> ptr)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
  private:
   static constexpr size_t kNumReferencesPerScope = 4;
 
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 5934f13..6c8e53d 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -46,7 +46,7 @@
     CHECK(self->IsExceptionPending());
     return false;
   }
-  Object* obj;
+  ObjPtr<Object> obj;
   if (is_static) {
     obj = f->GetDeclaringClass();
   } else {
@@ -60,9 +60,15 @@
   // Report this field access to instrumentation if needed.
   instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
   if (UNLIKELY(instrumentation->HasFieldReadListeners())) {
-    Object* this_object = f->IsStatic() ? nullptr : obj;
-    instrumentation->FieldReadEvent(self, this_object, shadow_frame.GetMethod(),
-                                    shadow_frame.GetDexPC(), f);
+    ObjPtr<Object> this_object;
+    if (!f->IsStatic()) {
+      this_object = obj;
+    }
+    instrumentation->FieldReadEvent(self,
+                                    this_object.Decode(),
+                                    shadow_frame.GetMethod(),
+                                    shadow_frame.GetDexPC(),
+                                    f);
   }
   uint32_t vregA = is_static ? inst->VRegA_21c(inst_data) : inst->VRegA_22c(inst_data);
   switch (field_type) {
@@ -85,7 +91,7 @@
       shadow_frame.SetVRegLong(vregA, f->GetLong(obj));
       break;
     case Primitive::kPrimNot:
-      shadow_frame.SetVRegReference(vregA, f->GetObject(obj));
+      shadow_frame.SetVRegReference(vregA, f->GetObject(obj).Decode());
       break;
     default:
       LOG(FATAL) << "Unreachable: " << field_type;
@@ -241,7 +247,7 @@
     CHECK(self->IsExceptionPending());
     return false;
   }
-  Object* obj;
+  ObjPtr<Object> obj;
   if (is_static) {
     obj = f->GetDeclaringClass();
   } else {
@@ -258,9 +264,12 @@
   instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
   if (UNLIKELY(instrumentation->HasFieldWriteListeners())) {
     JValue field_value = GetFieldValue<field_type>(shadow_frame, vregA);
-    Object* this_object = f->IsStatic() ? nullptr : obj;
-    instrumentation->FieldWriteEvent(self, this_object, shadow_frame.GetMethod(),
-                                     shadow_frame.GetDexPC(), f, field_value);
+    ObjPtr<Object> this_object = f->IsStatic() ? nullptr : obj;
+    instrumentation->FieldWriteEvent(self, this_object.Decode(),
+                                     shadow_frame.GetMethod(),
+                                     shadow_frame.GetDexPC(),
+                                     f,
+                                     field_value);
   }
   switch (field_type) {
     case Primitive::kPrimBoolean:
@@ -286,14 +295,14 @@
       if (do_assignability_check && reg != nullptr) {
         // FieldHelper::GetType can resolve classes, use a handle wrapper which will restore the
         // object in the destructor.
-        Class* field_class;
+        ObjPtr<Class> field_class;
         {
           StackHandleScope<2> hs(self);
           HandleWrapper<mirror::Object> h_reg(hs.NewHandleWrapper(&reg));
-          HandleWrapper<mirror::Object> h_obj(hs.NewHandleWrapper(&obj));
+          HandleWrapperObjPtr<mirror::Object> h_obj(hs.NewHandleWrapper(&obj));
           field_class = f->GetType<true>();
         }
-        if (!reg->VerifierInstanceOf(field_class)) {
+        if (!reg->VerifierInstanceOf(field_class.Decode())) {
           // This should never happen.
           std::string temp1, temp2, temp3;
           self->ThrowNewExceptionF("Ljava/lang/VirtualMachineError;",
diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc
index 39846da..eb8cdbc 100644
--- a/runtime/interpreter/unstarted_runtime.cc
+++ b/runtime/interpreter/unstarted_runtime.cc
@@ -786,9 +786,9 @@
                            kAndroidHardcodedSystemPropertiesFieldName);
     return;
   }
-  Handle<mirror::ObjectArray<mirror::ObjectArray<mirror::String>>> h_2string_array(
-      hs.NewHandle(reinterpret_cast<mirror::ObjectArray<mirror::ObjectArray<mirror::String>>*>(
-          static_properties->GetObject(h_props_class.Get()))));
+  ObjPtr<mirror::Object> props = static_properties->GetObject(h_props_class.Get());
+  Handle<mirror::ObjectArray<mirror::ObjectArray<mirror::String>>> h_2string_array(hs.NewHandle(
+      props->AsObjectArray<mirror::ObjectArray<mirror::String>>()));
   if (h_2string_array.Get() == nullptr) {
     AbortTransactionOrFail(self, "Field %s is null", kAndroidHardcodedSystemPropertiesFieldName);
     return;
diff --git a/runtime/jdwp/object_registry.cc b/runtime/jdwp/object_registry.cc
index 9ba62c9..dc3bf16 100644
--- a/runtime/jdwp/object_registry.cc
+++ b/runtime/jdwp/object_registry.cc
@@ -19,6 +19,7 @@
 #include "handle_scope-inl.h"
 #include "jni_internal.h"
 #include "mirror/class.h"
+#include "obj_ptr-inl.h"
 #include "scoped_thread_state_change-inl.h"
 
 namespace art {
@@ -35,7 +36,7 @@
     : lock_("ObjectRegistry lock", kJdwpObjectRegistryLock), next_id_(1) {
 }
 
-JDWP::RefTypeId ObjectRegistry::AddRefType(mirror::Class* c) {
+JDWP::RefTypeId ObjectRegistry::AddRefType(ObjPtr<mirror::Class> c) {
   return Add(c);
 }
 
@@ -43,7 +44,7 @@
   return Add(c_h);
 }
 
-JDWP::ObjectId ObjectRegistry::Add(mirror::Object* o) {
+JDWP::ObjectId ObjectRegistry::Add(ObjPtr<mirror::Object> o) {
   if (o == nullptr) {
     return 0;
   }
@@ -118,7 +119,9 @@
   return entry->id;
 }
 
-bool ObjectRegistry::ContainsLocked(Thread* self, mirror::Object* o, int32_t identity_hash_code,
+bool ObjectRegistry::ContainsLocked(Thread* self,
+                                    ObjPtr<mirror::Object> o,
+                                    int32_t identity_hash_code,
                                     ObjectRegistryEntry** out_entry) {
   DCHECK(o != nullptr);
   for (auto it = object_to_entry_.lower_bound(identity_hash_code), end = object_to_entry_.end();
diff --git a/runtime/jdwp/object_registry.h b/runtime/jdwp/object_registry.h
index 7fa57c6..9cacc66 100644
--- a/runtime/jdwp/object_registry.h
+++ b/runtime/jdwp/object_registry.h
@@ -25,6 +25,7 @@
 #include "base/casts.h"
 #include "handle.h"
 #include "jdwp/jdwp.h"
+#include "obj_ptr.h"
 #include "safe_map.h"
 
 namespace art {
@@ -62,11 +63,11 @@
  public:
   ObjectRegistry();
 
-  JDWP::ObjectId Add(mirror::Object* o)
+  JDWP::ObjectId Add(ObjPtr<mirror::Object> o)
       REQUIRES_SHARED(Locks::mutator_lock_)
       REQUIRES(!Locks::thread_list_lock_, !Locks::thread_suspend_count_lock_, !lock_);
 
-  JDWP::RefTypeId AddRefType(mirror::Class* c)
+  JDWP::RefTypeId AddRefType(ObjPtr<mirror::Class> c)
       REQUIRES_SHARED(Locks::mutator_lock_)
       REQUIRES(!Locks::thread_list_lock_, !Locks::thread_suspend_count_lock_, !lock_);
 
@@ -121,7 +122,9 @@
   void Promote(ObjectRegistryEntry& entry)
       REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(lock_);
 
-  bool ContainsLocked(Thread* self, mirror::Object* o, int32_t identity_hash_code,
+  bool ContainsLocked(Thread* self,
+                      ObjPtr<mirror::Object> o,
+                      int32_t identity_hash_code,
                       ObjectRegistryEntry** out_entry)
       REQUIRES(lock_) REQUIRES_SHARED(Locks::mutator_lock_);
 
diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc
index 7b27578..7977815 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -97,15 +97,20 @@
                                  kind, c->GetDescriptor(&temp), name, sig);
 }
 
-static void ReportInvalidJNINativeMethod(const ScopedObjectAccess& soa, mirror::Class* c,
-                                         const char* kind, jint idx, bool return_errors)
+static void ReportInvalidJNINativeMethod(const ScopedObjectAccess& soa,
+                                         ObjPtr<mirror::Class> c,
+                                         const char* kind,
+                                         jint idx,
+                                         bool return_errors)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   LOG(return_errors ? ::android::base::ERROR : ::android::base::FATAL)
       << "Failed to register native method in " << PrettyDescriptor(c)
       << " in " << c->GetDexCache()->GetLocation()->ToModifiedUtf8()
       << ": " << kind << " is null at index " << idx;
   soa.Self()->ThrowNewExceptionF("Ljava/lang/NoSuchMethodError;",
-                                 "%s is null at index %d", kind, idx);
+                                 "%s is null at index %d",
+                                 kind,
+                                 idx);
 }
 
 static ObjPtr<mirror::Class> EnsureInitialized(Thread* self, ObjPtr<mirror::Class> klass)
@@ -282,7 +287,7 @@
     return JNI_ERR;
   }
   ScopedObjectAccess soa(env);
-  soa.Self()->SetException(soa.Decode<mirror::Throwable>(exception.get()).Decode());
+  soa.Self()->SetException(soa.Decode<mirror::Throwable>(exception.get()));
   return JNI_OK;
 }
 
@@ -417,7 +422,7 @@
     ScopedObjectAccess soa(env);
     ObjPtr<mirror::Class> c1 = soa.Decode<mirror::Class>(java_class1);
     ObjPtr<mirror::Class> c2 = soa.Decode<mirror::Class>(java_class2);
-    return c2->IsAssignableFrom(c1.Decode()) ? JNI_TRUE : JNI_FALSE;
+    return c2->IsAssignableFrom(c1) ? JNI_TRUE : JNI_FALSE;
   }
 
   static jboolean IsInstanceOf(JNIEnv* env, jobject jobj, jclass java_class) {
@@ -439,7 +444,7 @@
     if (exception == nullptr) {
       return JNI_ERR;
     }
-    soa.Self()->SetException(exception.Decode());
+    soa.Self()->SetException(exception);
     return JNI_OK;
   }
 
@@ -1227,7 +1232,7 @@
     ScopedObjectAccess soa(env);
     ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(obj);
     ArtField* f = soa.DecodeField(fid);
-    return soa.AddLocalReference<jobject>(f->GetObject(o.Decode()));
+    return soa.AddLocalReference<jobject>(f->GetObject(o));
   }
 
   static jobject GetStaticObjectField(JNIEnv* env, jclass, jfieldID fid) {
@@ -1244,7 +1249,7 @@
     ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(java_object);
     ObjPtr<mirror::Object> v = soa.Decode<mirror::Object>(java_value);
     ArtField* f = soa.DecodeField(fid);
-    f->SetObject<false>(o.Decode(), v.Decode());
+    f->SetObject<false>(o, v);
   }
 
   static void SetStaticObjectField(JNIEnv* env, jclass, jfieldID fid, jobject java_value) {
@@ -1252,7 +1257,7 @@
     ScopedObjectAccess soa(env);
     ObjPtr<mirror::Object> v = soa.Decode<mirror::Object>(java_value);
     ArtField* f = soa.DecodeField(fid);
-    f->SetObject<false>(f->GetDeclaringClass(), v.Decode());
+    f->SetObject<false>(f->GetDeclaringClass(), v);
   }
 
 #define GET_PRIMITIVE_FIELD(fn, instance) \
@@ -1261,7 +1266,7 @@
   ScopedObjectAccess soa(env); \
   ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(instance); \
   ArtField* f = soa.DecodeField(fid); \
-  return f->Get ##fn (o.Decode())
+  return f->Get ##fn (o)
 
 #define GET_STATIC_PRIMITIVE_FIELD(fn) \
   CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(fid); \
@@ -1275,7 +1280,7 @@
   ScopedObjectAccess soa(env); \
   ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(instance); \
   ArtField* f = soa.DecodeField(fid); \
-  f->Set ##fn <false>(o.Decode(), value)
+  f->Set ##fn <false>(o, value)
 
 #define SET_STATIC_PRIMITIVE_FIELD(fn, value) \
   CHECK_NON_NULL_ARGUMENT_RETURN_VOID(fid); \
@@ -2159,13 +2164,13 @@
       const char* sig = methods[i].signature;
       const void* fnPtr = methods[i].fnPtr;
       if (UNLIKELY(name == nullptr)) {
-        ReportInvalidJNINativeMethod(soa, c.Decode(), "method name", i, return_errors);
+        ReportInvalidJNINativeMethod(soa, c, "method name", i, return_errors);
         return JNI_ERR;
       } else if (UNLIKELY(sig == nullptr)) {
-        ReportInvalidJNINativeMethod(soa, c.Decode(), "method signature", i, return_errors);
+        ReportInvalidJNINativeMethod(soa, c, "method signature", i, return_errors);
         return JNI_ERR;
       } else if (UNLIKELY(fnPtr == nullptr)) {
-        ReportInvalidJNINativeMethod(soa, c.Decode(), "native function", i, return_errors);
+        ReportInvalidJNINativeMethod(soa, c, "native function", i, return_errors);
         return JNI_ERR;
       }
       bool is_fast = false;
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index 5a5f717..8aebd6e 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -341,13 +341,13 @@
 // Don't forget about primitive types.
 //   Object[]         = int[] --> false
 //
-inline bool Class::IsArrayAssignableFromArray(Class* src) {
+inline bool Class::IsArrayAssignableFromArray(ObjPtr<Class> src) {
   DCHECK(IsArrayClass())  << PrettyClass(this);
   DCHECK(src->IsArrayClass()) << PrettyClass(src);
   return GetComponentType()->IsAssignableFrom(src->GetComponentType());
 }
 
-inline bool Class::IsAssignableFromArray(Class* src) {
+inline bool Class::IsAssignableFromArray(ObjPtr<Class> src) {
   DCHECK(!IsInterface()) << PrettyClass(this);  // handled first in IsAssignableFrom
   DCHECK(src->IsArrayClass()) << PrettyClass(src);
   if (!IsArrayClass()) {
@@ -362,8 +362,10 @@
 }
 
 template <bool throw_on_failure, bool use_referrers_cache>
-inline bool Class::ResolvedFieldAccessTest(Class* access_to, ArtField* field,
-                                           uint32_t field_idx, DexCache* dex_cache) {
+inline bool Class::ResolvedFieldAccessTest(Class* access_to,
+                                           ArtField* field,
+                                           uint32_t field_idx,
+                                           DexCache* dex_cache) {
   DCHECK_EQ(use_referrers_cache, dex_cache == nullptr);
   if (UNLIKELY(!this->CanAccess(access_to))) {
     // The referrer class can't access the field's declaring class but may still be able
@@ -447,14 +449,20 @@
   return false;
 }
 
-inline bool Class::CanAccessResolvedField(Class* access_to, ArtField* field,
-                                          DexCache* dex_cache, uint32_t field_idx) {
-  return ResolvedFieldAccessTest<false, false>(access_to, field, field_idx, dex_cache);
+inline bool Class::CanAccessResolvedField(ObjPtr<Class> access_to,
+                                          ArtField* field,
+                                          ObjPtr<DexCache> dex_cache,
+                                          uint32_t field_idx) {
+  return ResolvedFieldAccessTest<false, false>(access_to.Decode(),
+                                               field,
+                                               field_idx,
+                                               dex_cache.Decode());
 }
 
-inline bool Class::CheckResolvedFieldAccess(Class* access_to, ArtField* field,
+inline bool Class::CheckResolvedFieldAccess(ObjPtr<Class> access_to,
+                                            ArtField* field,
                                             uint32_t field_idx) {
-  return ResolvedFieldAccessTest<true, true>(access_to, field, field_idx, nullptr);
+  return ResolvedFieldAccessTest<true, true>(access_to.Decode(), field, field_idx, nullptr);
 }
 
 inline bool Class::CanAccessResolvedMethod(Class* access_to, ArtMethod* method,
@@ -469,10 +477,10 @@
                                                                  nullptr);
 }
 
-inline bool Class::IsSubClass(Class* klass) {
+inline bool Class::IsSubClass(ObjPtr<Class> klass) {
   DCHECK(!IsInterface()) << PrettyClass(this);
   DCHECK(!IsArrayClass()) << PrettyClass(this);
-  Class* current = this;
+  ObjPtr<Class> current = this;
   do {
     if (current == klass) {
       return true;
@@ -1032,7 +1040,7 @@
   return GetComponentType<kVerifyFlags, kReadBarrierOption>() != nullptr;
 }
 
-inline bool Class::IsAssignableFrom(Class* src) {
+inline bool Class::IsAssignableFrom(ObjPtr<Class> src) {
   DCHECK(src != nullptr);
   if (this == src) {
     // Can always assign to things of the same type.
@@ -1113,6 +1121,34 @@
   }
 }
 
+inline bool Class::CanAccess(ObjPtr<Class> that) {
+  return that->IsPublic() || this->IsInSamePackage(that);
+}
+
+
+inline bool Class::CanAccessMember(ObjPtr<Class> access_to, uint32_t member_flags) {
+  // Classes can access all of their own members
+  if (this == access_to) {
+    return true;
+  }
+  // Public members are trivially accessible
+  if (member_flags & kAccPublic) {
+    return true;
+  }
+  // Private members are trivially not accessible
+  if (member_flags & kAccPrivate) {
+    return false;
+  }
+  // Check for protected access from a sub-class, which may or may not be in the same package.
+  if (member_flags & kAccProtected) {
+    if (!this->IsInterface() && this->IsSubClass(access_to)) {
+      return true;
+    }
+  }
+  // Allow protected access from other classes in the same package.
+  return this->IsInSamePackage(access_to);
+}
+
 }  // namespace mirror
 }  // namespace art
 
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index 2e5f532..40742d2 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -308,9 +308,9 @@
   }
 }
 
-bool Class::IsInSamePackage(Class* that) {
-  Class* klass1 = this;
-  Class* klass2 = that;
+bool Class::IsInSamePackage(ObjPtr<Class> that) {
+  ObjPtr<Class> klass1 = this;
+  ObjPtr<Class> klass2 = that;
   if (klass1 == klass2) {
     return true;
   }
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 6c1259b..d38f235 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -611,50 +611,28 @@
   }
 
   // Returns true if this class is in the same packages as that class.
-  bool IsInSamePackage(Class* that) REQUIRES_SHARED(Locks::mutator_lock_);
+  bool IsInSamePackage(ObjPtr<Class> that) REQUIRES_SHARED(Locks::mutator_lock_);
 
   static bool IsInSamePackage(const StringPiece& descriptor1, const StringPiece& descriptor2);
 
   // Returns true if this class can access that class.
-  bool CanAccess(Class* that) REQUIRES_SHARED(Locks::mutator_lock_) {
-    return that->IsPublic() || this->IsInSamePackage(that);
-  }
+  bool CanAccess(ObjPtr<Class> that) REQUIRES_SHARED(Locks::mutator_lock_);
 
   // Can this class access a member in the provided class with the provided member access flags?
   // Note that access to the class isn't checked in case the declaring class is protected and the
   // method has been exposed by a public sub-class
-  bool CanAccessMember(Class* access_to, uint32_t member_flags)
-      REQUIRES_SHARED(Locks::mutator_lock_) {
-    // Classes can access all of their own members
-    if (this == access_to) {
-      return true;
-    }
-    // Public members are trivially accessible
-    if (member_flags & kAccPublic) {
-      return true;
-    }
-    // Private members are trivially not accessible
-    if (member_flags & kAccPrivate) {
-      return false;
-    }
-    // Check for protected access from a sub-class, which may or may not be in the same package.
-    if (member_flags & kAccProtected) {
-      if (!this->IsInterface() && this->IsSubClass(access_to)) {
-        return true;
-      }
-    }
-    // Allow protected access from other classes in the same package.
-    return this->IsInSamePackage(access_to);
-  }
+  bool CanAccessMember(ObjPtr<Class> access_to, uint32_t member_flags)
+      REQUIRES_SHARED(Locks::mutator_lock_);
 
   // Can this class access a resolved field?
   // Note that access to field's class is checked and this may require looking up the class
   // referenced by the FieldId in the DexFile in case the declaring class is inaccessible.
-  bool CanAccessResolvedField(Class* access_to, ArtField* field,
-                              DexCache* dex_cache, uint32_t field_idx)
+  bool CanAccessResolvedField(ObjPtr<Class> access_to,
+                              ArtField* field,
+                              ObjPtr<DexCache> dex_cache,
+                              uint32_t field_idx)
       REQUIRES_SHARED(Locks::mutator_lock_);
-  bool CheckResolvedFieldAccess(Class* access_to, ArtField* field,
-                                uint32_t field_idx)
+  bool CheckResolvedFieldAccess(ObjPtr<Class> access_to, ArtField* field, uint32_t field_idx)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   // Can this class access a resolved method?
@@ -668,14 +646,14 @@
                                  uint32_t method_idx)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
-  bool IsSubClass(Class* klass) REQUIRES_SHARED(Locks::mutator_lock_);
+  bool IsSubClass(ObjPtr<Class> klass) REQUIRES_SHARED(Locks::mutator_lock_);
 
   // Can src be assigned to this class? For example, String can be assigned to Object (by an
   // upcast), however, an Object cannot be assigned to a String as a potentially exception throwing
   // downcast would be necessary. Similarly for interfaces, a class that implements (or an interface
   // that extends) another can be assigned to its parent, but not vice-versa. All Classes may assign
   // to themselves. Classes for primitive types may not assign to each other.
-  ALWAYS_INLINE bool IsAssignableFrom(Class* src) REQUIRES_SHARED(Locks::mutator_lock_);
+  ALWAYS_INLINE bool IsAssignableFrom(ObjPtr<Class> src) REQUIRES_SHARED(Locks::mutator_lock_);
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
            ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
@@ -1309,8 +1287,10 @@
   void SetVerifyError(Object* klass) REQUIRES_SHARED(Locks::mutator_lock_);
 
   template <bool throw_on_failure, bool use_referrers_cache>
-  bool ResolvedFieldAccessTest(Class* access_to, ArtField* field,
-                               uint32_t field_idx, DexCache* dex_cache)
+  bool ResolvedFieldAccessTest(Class* access_to,
+                               ArtField* field,
+                               uint32_t field_idx,
+                               DexCache* dex_cache)
       REQUIRES_SHARED(Locks::mutator_lock_);
   template <bool throw_on_failure, bool use_referrers_cache, InvokeType throw_invoke_type>
   bool ResolvedMethodAccessTest(Class* access_to, ArtMethod* resolved_method,
@@ -1318,8 +1298,8 @@
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   bool Implements(Class* klass) REQUIRES_SHARED(Locks::mutator_lock_);
-  bool IsArrayAssignableFromArray(Class* klass) REQUIRES_SHARED(Locks::mutator_lock_);
-  bool IsAssignableFromArray(Class* klass) REQUIRES_SHARED(Locks::mutator_lock_);
+  bool IsArrayAssignableFromArray(ObjPtr<Class> klass) REQUIRES_SHARED(Locks::mutator_lock_);
+  bool IsAssignableFromArray(ObjPtr<Class> klass) REQUIRES_SHARED(Locks::mutator_lock_);
 
   void CheckObjectAlloc() REQUIRES_SHARED(Locks::mutator_lock_);
 
diff --git a/runtime/mirror/field-inl.h b/runtime/mirror/field-inl.h
index 8b0f8ce..ec32cb6 100644
--- a/runtime/mirror/field-inl.h
+++ b/runtime/mirror/field-inl.h
@@ -78,6 +78,11 @@
   return ret.Get();
 }
 
+template<bool kTransactionActive>
+void Field::SetDeclaringClass(ObjPtr<mirror::Class> c) {
+  SetFieldObject<kTransactionActive>(OFFSET_OF_OBJECT_MEMBER(Field, declaring_class_), c.Decode());
+}
+
 }  // namespace mirror
 }  // namespace art
 
diff --git a/runtime/mirror/field.h b/runtime/mirror/field.h
index f378568..c5357c9 100644
--- a/runtime/mirror/field.h
+++ b/runtime/mirror/field.h
@@ -20,6 +20,7 @@
 #include "accessible_object.h"
 #include "base/enums.h"
 #include "gc_root.h"
+#include "obj_ptr.h"
 #include "object.h"
 #include "object_callbacks.h"
 #include "read_barrier_option.h"
@@ -109,9 +110,7 @@
   int32_t offset_;
 
   template<bool kTransactionActive>
-  void SetDeclaringClass(mirror::Class* c) REQUIRES_SHARED(Locks::mutator_lock_) {
-    SetFieldObject<kTransactionActive>(OFFSET_OF_OBJECT_MEMBER(Field, declaring_class_), c);
-  }
+  void SetDeclaringClass(ObjPtr<mirror::Class> c) REQUIRES_SHARED(Locks::mutator_lock_);
 
   template<bool kTransactionActive>
   void SetType(mirror::Class* type) REQUIRES_SHARED(Locks::mutator_lock_) {
diff --git a/runtime/mirror/object.cc b/runtime/mirror/object.cc
index c37deb5..90b97fd 100644
--- a/runtime/mirror/object.cc
+++ b/runtime/mirror/object.cc
@@ -213,7 +213,7 @@
       if (field.GetOffset().Int32Value() == field_offset.Int32Value()) {
         CHECK_NE(field.GetTypeAsPrimitiveType(), Primitive::kPrimNot);
         // TODO: resolve the field type for moving GC.
-        mirror::Class* field_type = field.GetType<!kMovingCollector>();
+        ObjPtr<mirror::Class> field_type = field.GetType<!kMovingCollector>();
         if (field_type != nullptr) {
           CHECK(field_type->IsAssignableFrom(new_value->GetClass()));
         }
@@ -230,7 +230,7 @@
       if (field.GetOffset().Int32Value() == field_offset.Int32Value()) {
         CHECK_NE(field.GetTypeAsPrimitiveType(), Primitive::kPrimNot);
         // TODO: resolve the field type for moving GC.
-        mirror::Class* field_type = field.GetType<!kMovingCollector>();
+        ObjPtr<mirror::Class> field_type = field.GetType<!kMovingCollector>();
         if (field_type != nullptr) {
           CHECK(field_type->IsAssignableFrom(new_value->GetClass()));
         }
diff --git a/runtime/mirror/object_test.cc b/runtime/mirror/object_test.cc
index 40ee3a2..a573ae6 100644
--- a/runtime/mirror/object_test.cc
+++ b/runtime/mirror/object_test.cc
@@ -384,12 +384,12 @@
 
   ArtField* field = FindFieldFromCode<StaticObjectRead, true>(field_idx, clinit, Thread::Current(),
                                                               sizeof(HeapReference<Object>));
-  Object* s0 = field->GetObj(klass);
+  ObjPtr<Object> s0 = field->GetObj(klass);
   EXPECT_TRUE(s0 != nullptr);
 
   Handle<CharArray> char_array(hs.NewHandle(CharArray::Alloc(soa.Self(), 0)));
   field->SetObj<false>(field->GetDeclaringClass(), char_array.Get());
-  EXPECT_EQ(char_array.Get(), field->GetObj(klass));
+  EXPECT_OBJ_PTR_EQ(char_array.Get(), field->GetObj(klass));
 
   field->SetObj<false>(field->GetDeclaringClass(), nullptr);
   EXPECT_EQ(nullptr, field->GetObj(klass));
@@ -759,7 +759,7 @@
   EXPECT_TRUE(!X.IsNull());
   EXPECT_TRUE(X.IsValid());
   EXPECT_TRUE(X.Decode() != nullptr);
-  EXPECT_EQ(h_X.Get(), X.Decode());
+  EXPECT_OBJ_PTR_EQ(h_X.Get(), X);
   // FindClass may cause thread suspension, it should invalidate X.
   ObjPtr<Class, /*kPoison*/ true> Y(class_linker_->FindClass(soa.Self(), "LY;", class_loader));
   EXPECT_TRUE(!Y.IsNull());
@@ -773,7 +773,7 @@
   X.Assign(h_X.Get());
   EXPECT_TRUE(!X.IsNull());
   EXPECT_TRUE(X.IsValid());
-  EXPECT_EQ(h_X.Get(), X.Decode());
+  EXPECT_OBJ_PTR_EQ(h_X.Get(), X);
 
   // Allow thread suspension to invalidate Y.
   soa.Self()->AllowThreadSuspension();
@@ -793,7 +793,7 @@
   unpoisoned = h_X.Get();
   EXPECT_FALSE(unpoisoned.IsNull());
   EXPECT_TRUE(unpoisoned == h_X.Get());
-  EXPECT_EQ(unpoisoned.Decode(), h_X.Get());
+  EXPECT_OBJ_PTR_EQ(unpoisoned, h_X.Get());
 }
 
 }  // namespace mirror
diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc
index acad2a9..64e5a63 100644
--- a/runtime/oat_file_manager.cc
+++ b/runtime/oat_file_manager.cc
@@ -30,6 +30,7 @@
 #include "handle_scope-inl.h"
 #include "mirror/class_loader.h"
 #include "oat_file_assistant.h"
+#include "obj_ptr-inl.h"
 #include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 #include "thread_list.h"
@@ -223,7 +224,7 @@
   }
 }
 
-static void IterateOverJavaDexFile(mirror::Object* dex_file,
+static void IterateOverJavaDexFile(ObjPtr<mirror::Object> dex_file,
                                    ArtField* const cookie_field,
                                    std::function<bool(const DexFile*)> fn)
     REQUIRES_SHARED(Locks::mutator_lock_) {
@@ -258,12 +259,12 @@
   ArtField* const cookie_field = soa.DecodeField(WellKnownClasses::dalvik_system_DexFile_cookie);
   ArtField* const dex_file_field =
       soa.DecodeField(WellKnownClasses::dalvik_system_DexPathList__Element_dexFile);
-  mirror::Object* dex_path_list =
+  ObjPtr<mirror::Object> dex_path_list =
       soa.DecodeField(WellKnownClasses::dalvik_system_PathClassLoader_pathList)->
       GetObject(class_loader.Get());
   if (dex_path_list != nullptr && dex_file_field != nullptr && cookie_field != nullptr) {
     // DexPathList has an array dexElements of Elements[] which each contain a dex file.
-    mirror::Object* dex_elements_obj =
+    ObjPtr<mirror::Object> dex_elements_obj =
         soa.DecodeField(WellKnownClasses::dalvik_system_DexPathList_dexElements)->
         GetObject(dex_path_list);
     // Loop through each dalvik.system.DexPathList$Element's dalvik.system.DexFile and look
@@ -276,7 +277,7 @@
           // Should never happen, fall back to java code to throw a NPE.
           break;
         }
-        mirror::Object* dex_file = dex_file_field->GetObject(element);
+        ObjPtr<mirror::Object> dex_file = dex_file_field->GetObject(element);
         IterateOverJavaDexFile(dex_file, cookie_field, fn);
       }
     }
@@ -360,7 +361,7 @@
 
     // We support this being dalvik.system.DexPathList$Element and dalvik.system.DexFile.
 
-    mirror::Object* dex_file;
+    ObjPtr<mirror::Object> dex_file;
     if (element_class == element->GetClass()) {
       dex_file = dex_file_field->GetObject(element);
     } else if (dexfile_class == element->GetClass()) {
diff --git a/runtime/obj_ptr.h b/runtime/obj_ptr.h
index d5ac33d..7c0c9df 100644
--- a/runtime/obj_ptr.h
+++ b/runtime/obj_ptr.h
@@ -88,11 +88,13 @@
     return Decode() == ptr.Decode();
   }
 
-  ALWAYS_INLINE bool operator==(const MirrorType* ptr) const REQUIRES_SHARED(Locks::mutator_lock_) {
+  template <typename PointerType>
+  ALWAYS_INLINE bool operator==(const PointerType* ptr) const
+      REQUIRES_SHARED(Locks::mutator_lock_) {
     return Decode() == ptr;
   }
 
-  ALWAYS_INLINE bool operator==(std::nullptr_t) const REQUIRES_SHARED(Locks::mutator_lock_) {
+  ALWAYS_INLINE bool operator==(std::nullptr_t) const {
     return IsNull();
   }
 
@@ -100,16 +102,18 @@
     return Decode() != ptr.Decode();
   }
 
-  ALWAYS_INLINE bool operator!=(const MirrorType* ptr) const REQUIRES_SHARED(Locks::mutator_lock_) {
+  template <typename PointerType>
+  ALWAYS_INLINE bool operator!=(const PointerType* ptr) const
+      REQUIRES_SHARED(Locks::mutator_lock_) {
     return Decode() != ptr;
   }
 
-  ALWAYS_INLINE bool operator!=(std::nullptr_t) const REQUIRES_SHARED(Locks::mutator_lock_) {
+  ALWAYS_INLINE bool operator!=(std::nullptr_t) const {
     return !IsNull();
   }
 
   // Decode unchecked does not check that object pointer is valid. Do not use if you can avoid it.
-  ALWAYS_INLINE MirrorType* DecodeUnchecked() const REQUIRES_SHARED(Locks::mutator_lock_) {
+  ALWAYS_INLINE MirrorType* DecodeUnchecked() const {
     if (kPoison) {
       return reinterpret_cast<MirrorType*>(
           static_cast<uintptr_t>(static_cast<uint32_t>(reference_ << kObjectAlignmentShift)));
@@ -133,14 +137,40 @@
   uintptr_t reference_;
 };
 
+template<class MirrorType, bool kPoison, typename PointerType>
+ALWAYS_INLINE bool operator==(const PointerType* a, const ObjPtr<MirrorType, kPoison>& b)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  return b == a;
+}
+
+template<class MirrorType, bool kPoison>
+ALWAYS_INLINE bool operator==(std::nullptr_t, const ObjPtr<MirrorType, kPoison>& b) {
+  return b == nullptr;
+}
+
+template<typename MirrorType, bool kPoison, typename PointerType>
+ALWAYS_INLINE bool operator!=(const PointerType* a, const ObjPtr<MirrorType, kPoison>& b)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  return b != a;
+}
+
+template<class MirrorType, bool kPoison>
+ALWAYS_INLINE bool operator!=(std::nullptr_t, const ObjPtr<MirrorType, kPoison>& b) {
+  return b != nullptr;
+}
+
 template<class MirrorType, bool kPoison = kIsDebugBuild>
 static inline ObjPtr<MirrorType, kPoison> MakeObjPtr(MirrorType* ptr) {
   return ObjPtr<MirrorType, kPoison>(ptr);
 }
 
+template<class MirrorType, bool kPoison = kIsDebugBuild>
+static inline ObjPtr<MirrorType, kPoison> MakeObjPtr(ObjPtr<MirrorType, kPoison> ptr) {
+  return ObjPtr<MirrorType, kPoison>(ptr);
+}
+
 template<class MirrorType, bool kPoison>
-ALWAYS_INLINE std::ostream& operator<<(std::ostream& os, ObjPtr<MirrorType, kPoison> ptr)
-    REQUIRES_SHARED(Locks::mutator_lock_);
+ALWAYS_INLINE std::ostream& operator<<(std::ostream& os, ObjPtr<MirrorType, kPoison> ptr);
 
 }  // namespace art
 
diff --git a/runtime/openjdkjvmti/transform.cc b/runtime/openjdkjvmti/transform.cc
index ac348e7..9c42b2ff8 100644
--- a/runtime/openjdkjvmti/transform.cc
+++ b/runtime/openjdkjvmti/transform.cc
@@ -209,9 +209,9 @@
       hs.NewHandle(path_list_field->GetObject(h_class_loader.Get())));
   CHECK(path_list.Get() != nullptr);
   CHECK(!self->IsExceptionPending());
-  art::Handle<art::mirror::ObjectArray<art::mirror::Object>> dex_elements_list(
-      hs.NewHandle(art::down_cast<art::mirror::ObjectArray<art::mirror::Object>*>(
-          dex_path_list_element_field->GetObject(path_list.Get()))));
+  art::Handle<art::mirror::ObjectArray<art::mirror::Object>> dex_elements_list(hs.NewHandle(
+      dex_path_list_element_field->GetObject(path_list.Get())->
+      AsObjectArray<art::mirror::Object>()));
   CHECK(!self->IsExceptionPending());
   CHECK(dex_elements_list.Get() != nullptr);
   size_t num_elements = dex_elements_list->GetLength();
diff --git a/runtime/proxy_test.cc b/runtime/proxy_test.cc
index 43b0b3d..1119ccf 100644
--- a/runtime/proxy_test.cc
+++ b/runtime/proxy_test.cc
@@ -180,7 +180,7 @@
   ArtField* field = &static_fields->At(0);
   EXPECT_STREQ("interfaces", field->GetName());
   EXPECT_STREQ("[Ljava/lang/Class;", field->GetTypeDescriptor());
-  EXPECT_EQ(interfacesFieldClass.Get(), field->GetType<true>());
+  EXPECT_OBJ_PTR_EQ(MakeObjPtr(interfacesFieldClass.Get()), field->GetType<true>());
   std::string temp;
   EXPECT_STREQ("L$Proxy1234;", field->GetDeclaringClass()->GetDescriptor(&temp));
   EXPECT_FALSE(field->IsPrimitiveType());
@@ -189,7 +189,7 @@
   field = &static_fields->At(1);
   EXPECT_STREQ("throws", field->GetName());
   EXPECT_STREQ("[[Ljava/lang/Class;", field->GetTypeDescriptor());
-  EXPECT_EQ(throwsFieldClass.Get(), field->GetType<true>());
+  EXPECT_OBJ_PTR_EQ(MakeObjPtr(throwsFieldClass.Get()), field->GetType<true>());
   EXPECT_STREQ("L$Proxy1234;", field->GetDeclaringClass()->GetDescriptor(&temp));
   EXPECT_FALSE(field->IsPrimitiveType());
 }
@@ -224,10 +224,10 @@
   ASSERT_TRUE(static_fields1 != nullptr);
   ASSERT_EQ(2u, static_fields1->size());
 
-  EXPECT_EQ(static_fields0->At(0).GetDeclaringClass(), proxyClass0.Get());
-  EXPECT_EQ(static_fields0->At(1).GetDeclaringClass(), proxyClass0.Get());
-  EXPECT_EQ(static_fields1->At(0).GetDeclaringClass(), proxyClass1.Get());
-  EXPECT_EQ(static_fields1->At(1).GetDeclaringClass(), proxyClass1.Get());
+  EXPECT_OBJ_PTR_EQ(static_fields0->At(0).GetDeclaringClass(), MakeObjPtr(proxyClass0.Get()));
+  EXPECT_OBJ_PTR_EQ(static_fields0->At(1).GetDeclaringClass(), MakeObjPtr(proxyClass0.Get()));
+  EXPECT_OBJ_PTR_EQ(static_fields1->At(0).GetDeclaringClass(), MakeObjPtr(proxyClass1.Get()));
+  EXPECT_OBJ_PTR_EQ(static_fields1->At(1).GetDeclaringClass(), MakeObjPtr(proxyClass1.Get()));
 
   ASSERT_EQ(Runtime::Current()->GetClassLinker()->GetImagePointerSize(), kRuntimePointerSize);
   ASSERT_FALSE(Runtime::Current()->IsActiveTransaction());
diff --git a/runtime/quick/inline_method_analyser.cc b/runtime/quick/inline_method_analyser.cc
index dc6f4eb..b009b47 100644
--- a/runtime/quick/inline_method_analyser.cc
+++ b/runtime/quick/inline_method_analyser.cc
@@ -738,8 +738,8 @@
   if (field == nullptr || field->IsStatic()) {
     return false;
   }
-  mirror::Class* method_class = method->GetDeclaringClass();
-  mirror::Class* field_class = field->GetDeclaringClass();
+  ObjPtr<mirror::Class> method_class = method->GetDeclaringClass();
+  ObjPtr<mirror::Class> field_class = field->GetDeclaringClass();
   if (!method_class->CanAccessResolvedField(field_class, field, dex_cache, field_idx) ||
       (is_put && field->IsFinal() && method_class != field_class)) {
     return false;
diff --git a/runtime/reflection.cc b/runtime/reflection.cc
index b663b4c..066bc12 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -244,13 +244,13 @@
 #define DO_FIRST_ARG(match_descriptor, get_fn, append) { \
           if (LIKELY(arg != nullptr && arg->GetClass()->DescriptorEquals(match_descriptor))) { \
             ArtField* primitive_field = arg->GetClass()->GetInstanceField(0); \
-            append(primitive_field-> get_fn(arg.Decode()));
+            append(primitive_field-> get_fn(arg));
 
 #define DO_ARG(match_descriptor, get_fn, append) \
           } else if (LIKELY(arg != nullptr && \
                             arg->GetClass<>()->DescriptorEquals(match_descriptor))) { \
             ArtField* primitive_field = arg->GetClass()->GetInstanceField(0); \
-            append(primitive_field-> get_fn(arg.Decode()));
+            append(primitive_field-> get_fn(arg));
 
 #define DO_FAIL(expected) \
           } else { \
@@ -801,28 +801,28 @@
   ArtField* primitive_field = &klass->GetIFieldsPtr()->At(0);
   if (klass->DescriptorEquals("Ljava/lang/Boolean;")) {
     src_class = class_linker->FindPrimitiveClass('Z');
-    boxed_value.SetZ(primitive_field->GetBoolean(o.Decode()));
+    boxed_value.SetZ(primitive_field->GetBoolean(o));
   } else if (klass->DescriptorEquals("Ljava/lang/Byte;")) {
     src_class = class_linker->FindPrimitiveClass('B');
-    boxed_value.SetB(primitive_field->GetByte(o.Decode()));
+    boxed_value.SetB(primitive_field->GetByte(o));
   } else if (klass->DescriptorEquals("Ljava/lang/Character;")) {
     src_class = class_linker->FindPrimitiveClass('C');
-    boxed_value.SetC(primitive_field->GetChar(o.Decode()));
+    boxed_value.SetC(primitive_field->GetChar(o));
   } else if (klass->DescriptorEquals("Ljava/lang/Float;")) {
     src_class = class_linker->FindPrimitiveClass('F');
-    boxed_value.SetF(primitive_field->GetFloat(o.Decode()));
+    boxed_value.SetF(primitive_field->GetFloat(o));
   } else if (klass->DescriptorEquals("Ljava/lang/Double;")) {
     src_class = class_linker->FindPrimitiveClass('D');
-    boxed_value.SetD(primitive_field->GetDouble(o.Decode()));
+    boxed_value.SetD(primitive_field->GetDouble(o));
   } else if (klass->DescriptorEquals("Ljava/lang/Integer;")) {
     src_class = class_linker->FindPrimitiveClass('I');
-    boxed_value.SetI(primitive_field->GetInt(o.Decode()));
+    boxed_value.SetI(primitive_field->GetInt(o));
   } else if (klass->DescriptorEquals("Ljava/lang/Long;")) {
     src_class = class_linker->FindPrimitiveClass('J');
-    boxed_value.SetJ(primitive_field->GetLong(o.Decode()));
+    boxed_value.SetJ(primitive_field->GetLong(o));
   } else if (klass->DescriptorEquals("Ljava/lang/Short;")) {
     src_class = class_linker->FindPrimitiveClass('S');
-    boxed_value.SetS(primitive_field->GetShort(o.Decode()));
+    boxed_value.SetS(primitive_field->GetShort(o));
   } else {
     std::string temp;
     ThrowIllegalArgumentException(
@@ -888,13 +888,13 @@
   }
   if ((access_flags & kAccProtected) != 0) {
     if (obj != nullptr && !obj->InstanceOf(calling_class) &&
-        !declaring_class->IsInSamePackage(calling_class.Decode())) {
+        !declaring_class->IsInSamePackage(calling_class)) {
       return false;
-    } else if (declaring_class->IsAssignableFrom(calling_class.Decode())) {
+    } else if (declaring_class->IsAssignableFrom(calling_class)) {
       return true;
     }
   }
-  return declaring_class->IsInSamePackage(calling_class.Decode());
+  return declaring_class->IsInSamePackage(calling_class);
 }
 
 void InvalidReceiverError(ObjPtr<mirror::Object> o, ObjPtr<mirror::Class> c) {
diff --git a/runtime/thread-inl.h b/runtime/thread-inl.h
index bb6eb79..d75a788 100644
--- a/runtime/thread-inl.h
+++ b/runtime/thread-inl.h
@@ -175,9 +175,7 @@
 
 inline void Thread::TransitionFromRunnableToSuspended(ThreadState new_state) {
   AssertThreadSuspensionIsAllowable();
-  if (kIsDebugBuild) {
-    PoisonObjectPointers();
-  }
+  PoisonObjectPointersIfDebug();
   DCHECK_EQ(this, Thread::Current());
   // Change to non-runnable state, thereby appearing suspended to the system.
   TransitionToSuspendedAndRunCheckpoints(new_state);
diff --git a/runtime/thread.cc b/runtime/thread.cc
index ec1bb3f..b8c7096 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -563,8 +563,8 @@
     ScopedObjectAccess soa(env);
 
     ArtField* f = soa.DecodeField(WellKnownClasses::java_lang_Thread_name);
-    mirror::String* java_name = reinterpret_cast<mirror::String*>(f->GetObject(
-        soa.Decode<mirror::Object>(java_peer).Decode()));
+    ObjPtr<mirror::String> java_name =
+        f->GetObject(soa.Decode<mirror::Object>(java_peer))->AsString();
     std::string thread_name;
     if (java_name != nullptr) {
       thread_name = java_name->ToModifiedUtf8();
@@ -845,11 +845,9 @@
   soa.DecodeField(WellKnownClasses::java_lang_Thread_daemon)->
       SetBoolean<kTransactionActive>(tlsPtr_.opeer, thread_is_daemon);
   soa.DecodeField(WellKnownClasses::java_lang_Thread_group)->
-      SetObject<kTransactionActive>(tlsPtr_.opeer,
-                                    soa.Decode<mirror::Object>(thread_group).Decode());
+      SetObject<kTransactionActive>(tlsPtr_.opeer, soa.Decode<mirror::Object>(thread_group));
   soa.DecodeField(WellKnownClasses::java_lang_Thread_name)->
-      SetObject<kTransactionActive>(tlsPtr_.opeer,
-                                    soa.Decode<mirror::Object>(thread_name).Decode());
+      SetObject<kTransactionActive>(tlsPtr_.opeer, soa.Decode<mirror::Object>(thread_name));
   soa.DecodeField(WellKnownClasses::java_lang_Thread_priority)->
       SetInt<kTransactionActive>(tlsPtr_.opeer, thread_priority);
 }
@@ -948,8 +946,11 @@
 
 mirror::String* Thread::GetThreadName(const ScopedObjectAccessAlreadyRunnable& soa) const {
   ArtField* f = soa.DecodeField(WellKnownClasses::java_lang_Thread_name);
-  return (tlsPtr_.opeer != nullptr) ?
-      reinterpret_cast<mirror::String*>(f->GetObject(tlsPtr_.opeer)) : nullptr;
+  if (tlsPtr_.opeer == nullptr) {
+    return nullptr;
+  }
+  ObjPtr<mirror::Object> name = f->GetObject(tlsPtr_.opeer);
+  return name == nullptr ? nullptr : name->AsString();
 }
 
 void Thread::GetThreadName(std::string& name) const {
@@ -1220,14 +1221,14 @@
     is_daemon = soa.DecodeField(WellKnownClasses::java_lang_Thread_daemon)
         ->GetBoolean(thread->tlsPtr_.opeer);
 
-    mirror::Object* thread_group =
+    ObjPtr<mirror::Object> thread_group =
         soa.DecodeField(WellKnownClasses::java_lang_Thread_group)->GetObject(thread->tlsPtr_.opeer);
 
     if (thread_group != nullptr) {
       ArtField* group_name_field =
           soa.DecodeField(WellKnownClasses::java_lang_ThreadGroup_name);
-      mirror::String* group_name_string =
-          reinterpret_cast<mirror::String*>(group_name_field->GetObject(thread_group));
+      ObjPtr<mirror::String> group_name_string =
+          group_name_field->GetObject(thread_group)->AsString();
       group_name = (group_name_string != nullptr) ? group_name_string->ToModifiedUtf8() : "<null>";
     }
   } else {
@@ -1711,7 +1712,7 @@
 
     // Thread.join() is implemented as an Object.wait() on the Thread.lock object. Signal anyone
     // who is waiting.
-    mirror::Object* lock =
+    ObjPtr<mirror::Object> lock =
         soa.DecodeField(WellKnownClasses::java_lang_Thread_lock)->GetObject(tlsPtr_.opeer);
     // (This conditional is only needed for tests, where Thread.lock won't have been set.)
     if (lock != nullptr) {
@@ -1803,7 +1804,7 @@
 void Thread::RemoveFromThreadGroup(ScopedObjectAccess& soa) {
   // this.group.removeThread(this);
   // group can be null if we're in the compiler or a test.
-  mirror::Object* ogroup = soa.DecodeField(WellKnownClasses::java_lang_Thread_group)
+  ObjPtr<mirror::Object> ogroup = soa.DecodeField(WellKnownClasses::java_lang_Thread_group)
       ->GetObject(tlsPtr_.opeer);
   if (ogroup != nullptr) {
     ScopedLocalRef<jobject> group(soa.Env(), soa.AddLocalReference<jobject>(ogroup));
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 87b6dc3..50466ed 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -4563,9 +4563,11 @@
     return nullptr;
   } else {
     std::string temp;
-    mirror::Class* klass = field->GetDeclaringClass();
+    ObjPtr<mirror::Class> klass = field->GetDeclaringClass();
     const RegType& field_klass =
-        FromClass(klass->GetDescriptor(&temp), klass, klass->CannotBeAssignedFromOtherTypes());
+        FromClass(klass->GetDescriptor(&temp),
+                  klass.Decode(),
+                  klass->CannotBeAssignedFromOtherTypes());
     if (obj_type.IsUninitializedTypes()) {
       // Field accesses through uninitialized references are only allowable for constructors where
       // the field is declared in this class.
@@ -4662,10 +4664,11 @@
       }
     }
 
-    mirror::Class* field_type_class =
+    ObjPtr<mirror::Class> field_type_class =
         can_load_classes_ ? field->GetType<true>() : field->GetType<false>();
     if (field_type_class != nullptr) {
-      field_type = &FromClass(field->GetTypeDescriptor(), field_type_class,
+      field_type = &FromClass(field->GetTypeDescriptor(),
+                              field_type_class.Decode(),
                               field_type_class->CannotBeAssignedFromOtherTypes());
     } else {
       DCHECK(!can_load_classes_ || self_->IsExceptionPending());
@@ -4785,12 +4788,12 @@
   // Get the field type.
   const RegType* field_type;
   {
-    mirror::Class* field_type_class = can_load_classes_ ? field->GetType<true>() :
+    ObjPtr<mirror::Class> field_type_class = can_load_classes_ ? field->GetType<true>() :
         field->GetType<false>();
 
     if (field_type_class != nullptr) {
       field_type = &FromClass(field->GetTypeDescriptor(),
-                              field_type_class,
+                              field_type_class.Decode(),
                               field_type_class->CannotBeAssignedFromOtherTypes());
     } else {
       Thread* self = Thread::Current();
diff --git a/runtime/verifier/reg_type-inl.h b/runtime/verifier/reg_type-inl.h
index d93aaa1..10f1be5 100644
--- a/runtime/verifier/reg_type-inl.h
+++ b/runtime/verifier/reg_type-inl.h
@@ -44,7 +44,7 @@
   }
 }
 
-inline bool RegType::CanAccessMember(mirror::Class* klass, uint32_t access_flags) const {
+inline bool RegType::CanAccessMember(ObjPtr<mirror::Class> klass, uint32_t access_flags) const {
   if ((access_flags & kAccPublic) != 0) {
     return true;
   }
diff --git a/runtime/verifier/reg_type.h b/runtime/verifier/reg_type.h
index 9170bb1..472381d 100644
--- a/runtime/verifier/reg_type.h
+++ b/runtime/verifier/reg_type.h
@@ -29,6 +29,7 @@
 #include "base/stringpiece.h"
 #include "gc_root.h"
 #include "handle_scope.h"
+#include "obj_ptr.h"
 #include "object_callbacks.h"
 #include "primitive.h"
 
@@ -205,7 +206,7 @@
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   // Can this type access a member with the given properties?
-  bool CanAccessMember(mirror::Class* klass, uint32_t access_flags) const
+  bool CanAccessMember(ObjPtr<mirror::Class> klass, uint32_t access_flags) const
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   // Can this type be assigned by src?
diff --git a/runtime/verifier/verifier_deps.cc b/runtime/verifier/verifier_deps.cc
index 350c838..3e1958f 100644
--- a/runtime/verifier/verifier_deps.cc
+++ b/runtime/verifier/verifier_deps.cc
@@ -19,6 +19,7 @@
 #include "compiler_callbacks.h"
 #include "leb128.h"
 #include "mirror/class-inl.h"
+#include "obj_ptr-inl.h"
 #include "runtime.h"
 
 namespace art {
@@ -107,10 +108,10 @@
   }
 }
 
-bool VerifierDeps::IsInClassPath(mirror::Class* klass) {
+bool VerifierDeps::IsInClassPath(ObjPtr<mirror::Class> klass) {
   DCHECK(klass != nullptr);
 
-  mirror::DexCache* dex_cache = klass->GetDexCache();
+  ObjPtr<mirror::DexCache> dex_cache = klass->GetDexCache();
   if (dex_cache == nullptr) {
     // This is a synthesized class, in this case always an array. They are not
     // defined in the compiled DEX files and therefore are part of the classpath.
diff --git a/runtime/verifier/verifier_deps.h b/runtime/verifier/verifier_deps.h
index dc8dfaf..3223f6f 100644
--- a/runtime/verifier/verifier_deps.h
+++ b/runtime/verifier/verifier_deps.h
@@ -26,6 +26,7 @@
 #include "base/array_ref.h"
 #include "base/mutex.h"
 #include "method_resolution_kind.h"
+#include "obj_ptr.h"
 #include "os.h"
 
 namespace art {
@@ -176,7 +177,7 @@
 
   // Returns true if `klass` is null or not defined in any of dex files which
   // were reported as being compiled.
-  bool IsInClassPath(mirror::Class* klass)
+  bool IsInClassPath(ObjPtr<mirror::Class> klass)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   // Returns the index of `str`. If it is defined in `dex_file_`, this is the dex