Clean up ScopedThreadStateChange to use ObjPtr

Also fixed inclusion of -inl.h files in .h files by adding
scoped_object_access-inl.h and scoped_fast_natvie_object_access-inl.h

Changed AddLocalReference / Decode to use ObjPtr.

Changed libartbenchmark to be debug to avoid linkage errors.

Bug: 31113334

Test: test-art-host

Change-Id: I4d2e160483a29d21e1e0e440585ed328b9811483
diff --git a/benchmark/Android.bp b/benchmark/Android.bp
index dd19888..014a2b3 100644
--- a/benchmark/Android.bp
+++ b/benchmark/Android.bp
@@ -17,7 +17,7 @@
 art_cc_library {
     name: "libartbenchmark",
     host_supported: true,
-    defaults: ["art_defaults", "art_debug_defaults"],
+    defaults: ["art_defaults" ],
     srcs: [
         "jni_loader.cc",
         "jobject-benchmark/jobject_benchmark.cc",
diff --git a/benchmark/jni-perf/perf_jni.cc b/benchmark/jni-perf/perf_jni.cc
index cd8d520..06dded8 100644
--- a/benchmark/jni-perf/perf_jni.cc
+++ b/benchmark/jni-perf/perf_jni.cc
@@ -17,7 +17,7 @@
 #include <assert.h>
 
 #include "jni.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread.h"
 
 namespace art {
diff --git a/benchmark/jobject-benchmark/jobject_benchmark.cc b/benchmark/jobject-benchmark/jobject_benchmark.cc
index e7ca9eb..4b2c024 100644
--- a/benchmark/jobject-benchmark/jobject_benchmark.cc
+++ b/benchmark/jobject-benchmark/jobject_benchmark.cc
@@ -16,8 +16,9 @@
 
 #include "jni.h"
 
+#include "java_vm_ext.h"
 #include "mirror/class-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 namespace {
@@ -25,10 +26,10 @@
 extern "C" JNIEXPORT void JNICALL Java_JObjectBenchmark_timeAddRemoveLocal(
     JNIEnv* env, jobject jobj, jint reps) {
   ScopedObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(jobj);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(jobj);
   CHECK(obj != nullptr);
   for (jint i = 0; i < reps; ++i) {
-    jobject ref = soa.Env()->AddLocalReference<jobject>(obj);
+    jobject ref = soa.Env()->AddLocalReference<jobject>(obj.Decode());
     soa.Env()->DeleteLocalRef(ref);
   }
 }
@@ -36,11 +37,11 @@
 extern "C" JNIEXPORT void JNICALL Java_JObjectBenchmark_timeDecodeLocal(
     JNIEnv* env, jobject jobj, jint reps) {
   ScopedObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(jobj);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(jobj);
   CHECK(obj != nullptr);
-  jobject ref = soa.Env()->AddLocalReference<jobject>(obj);
+  jobject ref = soa.Env()->AddLocalReference<jobject>(obj.Decode());
   for (jint i = 0; i < reps; ++i) {
-    CHECK_EQ(soa.Decode<mirror::Object*>(ref), obj);
+    CHECK_EQ(soa.Decode<mirror::Object>(ref), obj);
   }
   soa.Env()->DeleteLocalRef(ref);
 }
@@ -48,7 +49,7 @@
 extern "C" JNIEXPORT void JNICALL Java_JObjectBenchmark_timeAddRemoveGlobal(
     JNIEnv* env, jobject jobj, jint reps) {
   ScopedObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(jobj);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(jobj);
   CHECK(obj != nullptr);
   for (jint i = 0; i < reps; ++i) {
     jobject ref = soa.Vm()->AddGlobalRef(soa.Self(), obj);
@@ -59,11 +60,11 @@
 extern "C" JNIEXPORT void JNICALL Java_JObjectBenchmark_timeDecodeGlobal(
     JNIEnv* env, jobject jobj, jint reps) {
   ScopedObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(jobj);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(jobj);
   CHECK(obj != nullptr);
   jobject ref = soa.Vm()->AddGlobalRef(soa.Self(), obj);
   for (jint i = 0; i < reps; ++i) {
-    CHECK_EQ(soa.Decode<mirror::Object*>(ref), obj);
+    CHECK_EQ(soa.Decode<mirror::Object>(ref), obj);
   }
   soa.Vm()->DeleteGlobalRef(soa.Self(), ref);
 }
@@ -71,7 +72,7 @@
 extern "C" JNIEXPORT void JNICALL Java_JObjectBenchmark_timeAddRemoveWeakGlobal(
     JNIEnv* env, jobject jobj, jint reps) {
   ScopedObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(jobj);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(jobj);
   CHECK(obj != nullptr);
   for (jint i = 0; i < reps; ++i) {
     jobject ref = soa.Vm()->AddWeakGlobalRef(soa.Self(), obj);
@@ -82,11 +83,11 @@
 extern "C" JNIEXPORT void JNICALL Java_JObjectBenchmark_timeDecodeWeakGlobal(
     JNIEnv* env, jobject jobj, jint reps) {
   ScopedObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(jobj);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(jobj);
   CHECK(obj != nullptr);
   jobject ref = soa.Vm()->AddWeakGlobalRef(soa.Self(), obj);
   for (jint i = 0; i < reps; ++i) {
-    CHECK_EQ(soa.Decode<mirror::Object*>(ref), obj);
+    CHECK_EQ(soa.Decode<mirror::Object>(ref), obj);
   }
   soa.Vm()->DeleteWeakGlobalRef(soa.Self(), ref);
 }
@@ -95,7 +96,7 @@
     JNIEnv* env, jobject jobj, jint reps) {
   ScopedObjectAccess soa(env);
   for (jint i = 0; i < reps; ++i) {
-    soa.Decode<mirror::Object*>(jobj);
+    soa.Decode<mirror::Object>(jobj);
   }
 }
 
diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc
index 2af4d72..63abfeb 100644
--- a/compiler/common_compiler_test.cc
+++ b/compiler/common_compiler_test.cc
@@ -33,7 +33,7 @@
 #include "mirror/dex_cache.h"
 #include "mirror/object-inl.h"
 #include "oat_quick_method_header.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 #include "utils.h"
 
@@ -109,7 +109,8 @@
   FlushInstructionCache(reinterpret_cast<char*>(base), reinterpret_cast<char*>(base + len));
 }
 
-void CommonCompilerTest::MakeExecutable(mirror::ClassLoader* class_loader, const char* class_name) {
+void CommonCompilerTest::MakeExecutable(ObjPtr<mirror::ClassLoader> class_loader,
+                                        const char* class_name) {
   std::string class_descriptor(DotToDescriptor(class_name));
   Thread* self = Thread::Current();
   StackHandleScope<1> hs(self);
diff --git a/compiler/common_compiler_test.h b/compiler/common_compiler_test.h
index 5239121..4a02fd5 100644
--- a/compiler/common_compiler_test.h
+++ b/compiler/common_compiler_test.h
@@ -51,7 +51,7 @@
 
   static void MakeExecutable(const void* code_start, size_t code_length);
 
-  void MakeExecutable(mirror::ClassLoader* class_loader, const char* class_name)
+  void MakeExecutable(ObjPtr<mirror::ClassLoader> class_loader, const char* class_name)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
  protected:
diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc
index e0abf19..236a3b2 100644
--- a/compiler/dex/dex_to_dex_compiler.cc
+++ b/compiler/dex/dex_to_dex_compiler.cc
@@ -280,7 +280,7 @@
   ScopedObjectAccess soa(Thread::Current());
   StackHandleScope<1> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
-      soa.Decode<mirror::ClassLoader*>(unit_.GetClassLoader())));
+      soa.Decode<mirror::ClassLoader>(unit_.GetClassLoader())));
 
   ClassLinker* class_linker = unit_.GetClassLinker();
   ArtMethod* resolved_method = class_linker->ResolveMethod<ClassLinker::kForceICCECheck>(
diff --git a/compiler/driver/compiler_driver-inl.h b/compiler/driver/compiler_driver-inl.h
index 4b913f4..2d0dd3c 100644
--- a/compiler/driver/compiler_driver-inl.h
+++ b/compiler/driver/compiler_driver-inl.h
@@ -26,7 +26,7 @@
 #include "dex_compilation_unit.h"
 #include "mirror/class_loader.h"
 #include "mirror/dex_cache-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "handle_scope-inl.h"
 
 namespace art {
@@ -37,7 +37,7 @@
 
 inline mirror::ClassLoader* CompilerDriver::GetClassLoader(const ScopedObjectAccess& soa,
                                                            const DexCompilationUnit* mUnit) {
-  return soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader());
+  return soa.Decode<mirror::ClassLoader>(mUnit->GetClassLoader()).Decode();
 }
 
 inline mirror::Class* CompilerDriver::ResolveClass(
@@ -45,7 +45,7 @@
     Handle<mirror::ClassLoader> class_loader, uint16_t cls_index,
     const DexCompilationUnit* mUnit) {
   DCHECK_EQ(dex_cache->GetDexFile(), mUnit->GetDexFile());
-  DCHECK_EQ(class_loader.Get(), soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
+  DCHECK_EQ(class_loader.Get(), GetClassLoader(soa, mUnit));
   mirror::Class* cls = mUnit->GetClassLinker()->ResolveType(
       *mUnit->GetDexFile(), cls_index, dex_cache, class_loader);
   DCHECK_EQ(cls == nullptr, soa.Self()->IsExceptionPending());
@@ -60,7 +60,7 @@
     const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
     Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit) {
   DCHECK_EQ(dex_cache->GetDexFile(), mUnit->GetDexFile());
-  DCHECK_EQ(class_loader.Get(), soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
+  DCHECK_EQ(class_loader.Get(), GetClassLoader(soa, mUnit));
   const DexFile::MethodId& referrer_method_id =
       mUnit->GetDexFile()->GetMethodId(mUnit->GetDexMethodIndex());
   return ResolveClass(soa, dex_cache, class_loader, referrer_method_id.class_idx_, mUnit);
@@ -95,7 +95,7 @@
     const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
     Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit,
     uint32_t field_idx, bool is_static) {
-  DCHECK_EQ(class_loader.Get(), soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
+  DCHECK_EQ(class_loader.Get(), GetClassLoader(soa, mUnit));
   return ResolveFieldWithDexFile(soa, dex_cache, class_loader, mUnit->GetDexFile(), field_idx,
                                  is_static);
 }
@@ -258,7 +258,7 @@
     ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
     Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit,
     uint32_t method_idx, InvokeType invoke_type, bool check_incompatible_class_change) {
-  DCHECK_EQ(class_loader.Get(), soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
+  DCHECK_EQ(class_loader.Get(), GetClassLoader(soa, mUnit));
   ArtMethod* resolved_method =
       check_incompatible_class_change
           ? mUnit->GetClassLinker()->ResolveMethod<ClassLinker::kForceICCECheck>(
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index f1d3116..4f76420 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -60,7 +60,7 @@
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
 #include "mirror/throwable.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "ScopedLocalRef.h"
 #include "handle_scope-inl.h"
 #include "thread.h"
@@ -535,7 +535,7 @@
   ScopedObjectAccess soa(self);
   StackHandleScope<1> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader(
-      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+      hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader)));
   return GetDexToDexCompilationLevel(self, driver, class_loader, dex_file, class_def);
 }
 
@@ -610,7 +610,7 @@
       ScopedObjectAccess soa(self);
       StackHandleScope<1> hs(soa.Self());
       Handle<mirror::ClassLoader> class_loader_handle(hs.NewHandle(
-          soa.Decode<mirror::ClassLoader*>(class_loader)));
+          soa.Decode<mirror::ClassLoader>(class_loader)));
 
       // TODO: Lookup annotation from DexFile directly without resolving method.
       ArtMethod* method =
@@ -1626,7 +1626,7 @@
   {
     StackHandleScope<1> hs(soa.Self());
     Handle<mirror::ClassLoader> class_loader_handle(
-        hs.NewHandle(soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader())));
+        hs.NewHandle(soa.Decode<mirror::ClassLoader>(mUnit->GetClassLoader())));
     resolved_field = ResolveField(soa, dex_cache, class_loader_handle, mUnit, field_idx, false);
     referrer_class = resolved_field != nullptr
         ? ResolveCompilingMethodsClass(soa, dex_cache, class_loader_handle, mUnit) : nullptr;
@@ -1970,7 +1970,7 @@
     ScopedObjectAccess soa(self);
     StackHandleScope<2> hs(soa.Self());
     Handle<mirror::ClassLoader> class_loader(
-        hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+        hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader)));
     Handle<mirror::DexCache> dex_cache(hs.NewHandle(class_linker->FindDexCache(
         soa.Self(), dex_file, false)));
     // Resolve the class.
@@ -2067,7 +2067,7 @@
     const DexFile& dex_file = *manager_->GetDexFile();
     StackHandleScope<2> hs(soa.Self());
     Handle<mirror::ClassLoader> class_loader(
-        hs.NewHandle(soa.Decode<mirror::ClassLoader*>(manager_->GetClassLoader())));
+        hs.NewHandle(soa.Decode<mirror::ClassLoader>(manager_->GetClassLoader())));
     Handle<mirror::DexCache> dex_cache(hs.NewHandle(class_linker->RegisterDexFile(
         dex_file,
         class_loader.Get())));
@@ -2166,7 +2166,7 @@
     jobject jclass_loader = manager_->GetClassLoader();
     StackHandleScope<3> hs(soa.Self());
     Handle<mirror::ClassLoader> class_loader(
-        hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+        hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader)));
     Handle<mirror::Class> klass(
         hs.NewHandle(class_linker->FindClass(soa.Self(), descriptor, class_loader)));
     if (klass.Get() == nullptr) {
@@ -2254,7 +2254,7 @@
     jobject jclass_loader = manager_->GetClassLoader();
     StackHandleScope<3> hs(soa.Self());
     Handle<mirror::ClassLoader> class_loader(
-        hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+        hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader)));
     Handle<mirror::Class> klass(
         hs.NewHandle(class_linker->FindClass(soa.Self(), descriptor, class_loader)));
     // Class might have failed resolution. Then don't set it to verified.
@@ -2316,7 +2316,7 @@
     ScopedObjectAccess soa(Thread::Current());
     StackHandleScope<3> hs(soa.Self());
     Handle<mirror::ClassLoader> class_loader(
-        hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+        hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader)));
     Handle<mirror::Class> klass(
         hs.NewHandle(manager_->GetClassLinker()->FindClass(soa.Self(), descriptor, class_loader)));
 
@@ -2551,7 +2551,7 @@
     ScopedObjectAccess soa(Thread::Current());
     StackHandleScope<3> hs(soa.Self());
     Handle<mirror::ClassLoader> class_loader(
-        hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+        hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader)));
     Handle<mirror::Class> klass(
         hs.NewHandle(class_linker->FindClass(soa.Self(), descriptor, class_loader)));
     Handle<mirror::DexCache> dex_cache;
diff --git a/compiler/driver/compiler_driver_test.cc b/compiler/driver/compiler_driver_test.cc
index b9a5a78..96f17ac 100644
--- a/compiler/driver/compiler_driver_test.cc
+++ b/compiler/driver/compiler_driver_test.cc
@@ -32,7 +32,7 @@
 #include "mirror/object-inl.h"
 #include "handle_scope-inl.h"
 #include "jit/offline_profiling_info.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 
@@ -83,7 +83,7 @@
       ScopedObjectAccess soa(Thread::Current());
       StackHandleScope<1> hs(soa.Self());
       Handle<mirror::ClassLoader> loader(
-          hs.NewHandle(soa.Decode<mirror::ClassLoader*>(class_loader)));
+          hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader)));
       mirror::Class* c = class_linker->FindClass(soa.Self(), descriptor, loader);
       CHECK(c != nullptr);
       const auto pointer_size = class_linker->GetImagePointerSize();
diff --git a/compiler/elf_writer.cc b/compiler/elf_writer.cc
index ca0869a..0c06090 100644
--- a/compiler/elf_writer.cc
+++ b/compiler/elf_writer.cc
@@ -26,7 +26,7 @@
 #include "invoke_type.h"
 #include "mirror/object-inl.h"
 #include "oat.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 
diff --git a/compiler/exception_test.cc b/compiler/exception_test.cc
index 86f91c5..f9e5cb9 100644
--- a/compiler/exception_test.cc
+++ b/compiler/exception_test.cc
@@ -31,7 +31,7 @@
 #include "oat_quick_method_header.h"
 #include "optimizing/stack_map_stream.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "handle_scope-inl.h"
 #include "thread.h"
 
@@ -45,7 +45,7 @@
     ScopedObjectAccess soa(Thread::Current());
     StackHandleScope<2> hs(soa.Self());
     Handle<mirror::ClassLoader> class_loader(
-        hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("ExceptionHandle"))));
+        hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("ExceptionHandle"))));
     my_klass_ = class_linker_->FindClass(soa.Self(), "LExceptionHandle;", class_loader);
     ASSERT_TRUE(my_klass_ != nullptr);
     Handle<mirror::Class> klass(hs.NewHandle(my_klass_));
@@ -219,7 +219,7 @@
   ASSERT_TRUE(internal != nullptr);
   jobjectArray ste_array = Thread::InternalStackTraceToStackTraceElementArray(soa, internal);
   ASSERT_TRUE(ste_array != nullptr);
-  auto* trace_array = soa.Decode<mirror::ObjectArray<mirror::StackTraceElement>*>(ste_array);
+  auto trace_array = soa.Decode<mirror::ObjectArray<mirror::StackTraceElement>>(ste_array);
 
   ASSERT_TRUE(trace_array != nullptr);
   ASSERT_TRUE(trace_array->Get(0) != nullptr);
diff --git a/compiler/image_test.cc b/compiler/image_test.cc
index ea4b7ee..4689c9d 100644
--- a/compiler/image_test.cc
+++ b/compiler/image_test.cc
@@ -33,7 +33,7 @@
 #include "lock_word.h"
 #include "mirror/object-inl.h"
 #include "oat_writer.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "signal_catcher.h"
 #include "utils.h"
 
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index 6b5758b..41bda60 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -63,7 +63,7 @@
 #include "oat_file.h"
 #include "oat_file_manager.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "handle_scope-inl.h"
 #include "utils/dex_cache_arrays_layout-inl.h"
 
diff --git a/compiler/jni/jni_compiler_test.cc b/compiler/jni/jni_compiler_test.cc
index 1430188..19d55a3 100644
--- a/compiler/jni/jni_compiler_test.cc
+++ b/compiler/jni/jni_compiler_test.cc
@@ -36,7 +36,7 @@
 #include "nativeloader/native_loader.h"
 #include "runtime.h"
 #include "ScopedLocalRef.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread.h"
 
 extern "C" JNIEXPORT jint JNICALL Java_MyClassNatives_bar(JNIEnv*, jobject, jint count) {
@@ -238,7 +238,7 @@
     ScopedObjectAccess soa(Thread::Current());
     StackHandleScope<1> hs(soa.Self());
     Handle<mirror::ClassLoader> loader(
-        hs.NewHandle(soa.Decode<mirror::ClassLoader*>(class_loader)));
+        hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader)));
     // Compile the native method before starting the runtime
     mirror::Class* c = class_linker_->FindClass(soa.Self(), "LMyClassNatives;", loader);
     const auto pointer_size = class_linker_->GetImagePointerSize();
@@ -1140,8 +1140,8 @@
     // Build stack trace
     jobject internal = Thread::Current()->CreateInternalStackTrace<false>(soa);
     jobjectArray ste_array = Thread::InternalStackTraceToStackTraceElementArray(soa, internal);
-    mirror::ObjectArray<mirror::StackTraceElement>* trace_array =
-        soa.Decode<mirror::ObjectArray<mirror::StackTraceElement>*>(ste_array);
+    ObjPtr<mirror::ObjectArray<mirror::StackTraceElement>> trace_array =
+        soa.Decode<mirror::ObjectArray<mirror::StackTraceElement>>(ste_array);
     EXPECT_TRUE(trace_array != nullptr);
     EXPECT_EQ(11, trace_array->GetLength());
 
@@ -1205,7 +1205,7 @@
   // Add 10 local references
   ScopedObjectAccess soa(env);
   for (int i = 0; i < 10; i++) {
-    soa.AddLocalReference<jobject>(soa.Decode<mirror::Object*>(thisObj));
+    soa.AddLocalReference<jobject>(soa.Decode<mirror::Object>(thisObj));
   }
   return x+1;
 }
@@ -1283,7 +1283,7 @@
 
   Thread* self = Thread::Current();
   ScopedObjectAccess soa(self);
-  EXPECT_TRUE(self->HoldsLock(soa.Decode<mirror::Object*>(thisObj)));
+  EXPECT_TRUE(self->HoldsLock(soa.Decode<mirror::Object>(thisObj).Decode()));
   return nullptr;
 }
 
diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc
index 24d102d..c392dc5 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -38,7 +38,7 @@
 #include "mirror/object_array-inl.h"
 #include "oat_file-inl.h"
 #include "oat_writer.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "utils/test_dex_file_builder.h"
 
 namespace art {
@@ -501,7 +501,8 @@
   ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
   for (const DexFile* dex_file : dex_files) {
     ScopedObjectAccess soa(Thread::Current());
-    class_linker->RegisterDexFile(*dex_file, soa.Decode<mirror::ClassLoader*>(class_loader));
+    class_linker->RegisterDexFile(*dex_file,
+                                  soa.Decode<mirror::ClassLoader>(class_loader).Decode());
   }
   compiler_driver_->SetDexFilesForOatFile(dex_files);
   compiler_driver_->CompileAll(class_loader, dex_files, &timings);
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index c840a9e..54ec7c1 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -50,7 +50,7 @@
 #include "oat_quick_method_header.h"
 #include "os.h"
 #include "safe_map.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "type_lookup_table.h"
 #include "utils/dex_cache_arrays_layout-inl.h"
 #include "vdex_file.h"
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index f21dc0e..31d1704 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -41,7 +41,7 @@
 #include "sharpening.h"
 #include "ssa_builder.h"
 #include "ssa_phi_elimination.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread.h"
 
 namespace art {
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index 3b08d9f..f7d67db 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -22,7 +22,7 @@
 #include "dex_instruction-inl.h"
 #include "driver/compiler_options.h"
 #include "imtable-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 
@@ -675,7 +675,7 @@
 
   ClassLinker* class_linker = dex_compilation_unit_->GetClassLinker();
   Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
-      soa.Decode<mirror::ClassLoader*>(dex_compilation_unit_->GetClassLoader())));
+      soa.Decode<mirror::ClassLoader>(dex_compilation_unit_->GetClassLoader())));
   Handle<mirror::Class> compiling_class(hs.NewHandle(GetCompilingClass()));
   // We fetch the referenced class eagerly (that is, the class pointed by in the MethodId
   // at method_idx), as `CanAccessResolvedMethod` expects it be be in the dex cache.
@@ -1284,7 +1284,7 @@
   ScopedObjectAccess soa(Thread::Current());
   StackHandleScope<1> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
-      soa.Decode<mirror::ClassLoader*>(compilation_unit.GetClassLoader())));
+      soa.Decode<mirror::ClassLoader>(compilation_unit.GetClassLoader())));
   Handle<mirror::DexCache> dex_cache = compilation_unit.GetDexCache();
 
   return driver->ResolveCompilingMethodsClass(soa, dex_cache, class_loader, &compilation_unit);
@@ -1303,7 +1303,7 @@
   StackHandleScope<3> hs(soa.Self());
   Handle<mirror::DexCache> dex_cache = dex_compilation_unit_->GetDexCache();
   Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
-      soa.Decode<mirror::ClassLoader*>(dex_compilation_unit_->GetClassLoader())));
+      soa.Decode<mirror::ClassLoader>(dex_compilation_unit_->GetClassLoader())));
   Handle<mirror::Class> cls(hs.NewHandle(compiler_driver_->ResolveClass(
       soa, dex_cache, class_loader, type_index, dex_compilation_unit_)));
   Handle<mirror::Class> outer_class(hs.NewHandle(GetOutermostCompilingClass()));
@@ -1344,7 +1344,7 @@
   StackHandleScope<3> hs(soa.Self());
   Handle<mirror::DexCache> dex_cache = dex_compilation_unit_->GetDexCache();
   Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
-      soa.Decode<mirror::ClassLoader*>(dex_compilation_unit_->GetClassLoader())));
+      soa.Decode<mirror::ClassLoader>(dex_compilation_unit_->GetClassLoader())));
   ArtField* resolved_field = compiler_driver_->ResolveField(
       soa, dex_cache, class_loader, dex_compilation_unit_, field_index, true);
 
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index ff829af..3bb1c1d 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -18,7 +18,7 @@
 
 #include "intrinsics.h"
 #include "mirror/class-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 
diff --git a/compiler/optimizing/intrinsics.cc b/compiler/optimizing/intrinsics.cc
index 4d4bbcf..2131279 100644
--- a/compiler/optimizing/intrinsics.cc
+++ b/compiler/optimizing/intrinsics.cc
@@ -25,7 +25,7 @@
 #include "mirror/dex_cache-inl.h"
 #include "nodes.h"
 #include "quick/inline_method_analyser.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 #include "utils.h"
 
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index 9cfa89b..ef9bf23 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -25,7 +25,7 @@
 #include "base/stl_util.h"
 #include "intrinsics.h"
 #include "mirror/class-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index c5d7611..84356e8 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -899,7 +899,7 @@
     ScopedObjectAccess soa(Thread::Current());
     StackHandleScope<1> hs(soa.Self());
     Handle<mirror::ClassLoader> loader(hs.NewHandle(
-        soa.Decode<mirror::ClassLoader*>(class_loader)));
+        soa.Decode<mirror::ClassLoader>(class_loader)));
     method = compiler_driver->ResolveMethod(
         soa, dex_cache, loader, &dex_compilation_unit, method_idx, invoke_type);
   }
diff --git a/compiler/optimizing/optimizing_unit_test.h b/compiler/optimizing/optimizing_unit_test.h
index dd5cb1c..2a23c92 100644
--- a/compiler/optimizing/optimizing_unit_test.h
+++ b/compiler/optimizing/optimizing_unit_test.h
@@ -22,7 +22,7 @@
 #include "common_compiler_test.h"
 #include "dex_file.h"
 #include "dex_instruction.h"
-#include "handle_scope-inl.h"
+#include "handle_scope.h"
 #include "scoped_thread_state_change.h"
 #include "ssa_builder.h"
 #include "ssa_liveness_analysis.h"
diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc
index 4289cf7..5a47df1 100644
--- a/compiler/optimizing/reference_type_propagation.cc
+++ b/compiler/optimizing/reference_type_propagation.cc
@@ -20,7 +20,7 @@
 #include "class_linker-inl.h"
 #include "mirror/class-inl.h"
 #include "mirror/dex_cache.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 
diff --git a/compiler/optimizing/sharpening.cc b/compiler/optimizing/sharpening.cc
index abec55f..a4a3e06 100644
--- a/compiler/optimizing/sharpening.cc
+++ b/compiler/optimizing/sharpening.cc
@@ -31,7 +31,7 @@
 #include "mirror/string.h"
 #include "nodes.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 3b2715d..b706420 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -77,7 +77,7 @@
 #include "runtime.h"
 #include "runtime_options.h"
 #include "ScopedLocalRef.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "utils.h"
 #include "verifier/verifier_deps.h"
 #include "well_known_classes.h"
@@ -1567,7 +1567,7 @@
       ScopedObjectAccess soa(self);
       dex_caches_.push_back(soa.AddLocalReference<jobject>(
           class_linker->RegisterDexFile(*dex_file,
-                                        soa.Decode<mirror::ClassLoader*>(class_loader_))));
+                                        soa.Decode<mirror::ClassLoader>(class_loader_).Decode())));
     }
 
     return true;
diff --git a/imgdiag/imgdiag.cc b/imgdiag/imgdiag.cc
index 106cf2f..ace21aa 100644
--- a/imgdiag/imgdiag.cc
+++ b/imgdiag/imgdiag.cc
@@ -34,7 +34,7 @@
 #include "mirror/class-inl.h"
 #include "mirror/object-inl.h"
 #include "image.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "os.h"
 
 #include "cmdline.h"
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 06d9814..f3f418d 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -57,7 +57,7 @@
 #include "oat_file_manager.h"
 #include "os.h"
 #include "safe_map.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "ScopedLocalRef.h"
 #include "stack_map.h"
 #include "string_reference.h"
@@ -2474,7 +2474,7 @@
   // Use the class loader while dumping.
   StackHandleScope<1> scope(self);
   Handle<mirror::ClassLoader> loader_handle = scope.NewHandle(
-      soa.Decode<mirror::ClassLoader*>(class_loader));
+      soa.Decode<mirror::ClassLoader>(class_loader));
   options->class_loader_ = &loader_handle;
 
   OatDumper oat_dumper(*oat_file, *options);
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc
index 1af3660..d58f38c 100644
--- a/patchoat/patchoat.cc
+++ b/patchoat/patchoat.cc
@@ -46,7 +46,7 @@
 #include "offsets.h"
 #include "os.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread.h"
 #include "utils.h"
 
diff --git a/runtime/arch/stub_test.cc b/runtime/arch/stub_test.cc
index 3424e3c..5e39f42 100644
--- a/runtime/arch/stub_test.cc
+++ b/runtime/arch/stub_test.cc
@@ -26,7 +26,7 @@
 #include "linear_alloc.h"
 #include "mirror/class-inl.h"
 #include "mirror/string-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 
@@ -1796,7 +1796,7 @@
 
   ScopedObjectAccess soa(self);
   StackHandleScope<3> hs(self);
-  Handle<mirror::Object> obj(hs.NewHandle(soa.Decode<mirror::Object*>(o)));
+  Handle<mirror::Object> obj(hs.NewHandle(soa.Decode<mirror::Object>(o)));
   Handle<mirror::Class> c(hs.NewHandle(obj->GetClass()));
   // Need a method as a referrer
   ArtMethod* m = c->GetDirectMethod(0, kRuntimePointerSize);
@@ -1995,11 +1995,11 @@
 
   jobject jarray_list = env->NewObject(arraylist_jclass, arraylist_constructor);
   ASSERT_NE(nullptr, jarray_list);
-  Handle<mirror::Object> array_list(hs.NewHandle(soa.Decode<mirror::Object*>(jarray_list)));
+  Handle<mirror::Object> array_list(hs.NewHandle(soa.Decode<mirror::Object>(jarray_list)));
 
   jobject jobj = env->NewObject(obj_jclass, obj_constructor);
   ASSERT_NE(nullptr, jobj);
-  Handle<mirror::Object> obj(hs.NewHandle(soa.Decode<mirror::Object*>(jobj)));
+  Handle<mirror::Object> obj(hs.NewHandle(soa.Decode<mirror::Object>(jobj)));
 
   // Invocation tests.
 
diff --git a/runtime/art_field-inl.h b/runtime/art_field-inl.h
index ef75f94..ca96169 100644
--- a/runtime/art_field-inl.h
+++ b/runtime/art_field-inl.h
@@ -28,7 +28,7 @@
 #include "mirror/object-inl.h"
 #include "primitive.h"
 #include "thread-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "well_known_classes.h"
 
 namespace art {
diff --git a/runtime/art_field.cc b/runtime/art_field.cc
index ea5078e..3b4db0b 100644
--- a/runtime/art_field.cc
+++ b/runtime/art_field.cc
@@ -24,7 +24,7 @@
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "utils.h"
 #include "well_known_classes.h"
 
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index 73cce5e..73c6cf1 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -36,7 +36,7 @@
 #include "quick/quick_method_frame_info.h"
 #include "read_barrier-inl.h"
 #include "runtime-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 #include "utils.h"
 
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index 193bea1..c97c328 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -40,7 +40,7 @@
 #include "mirror/object-inl.h"
 #include "mirror/string.h"
 #include "oat_file-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "well_known_classes.h"
 
 namespace art {
@@ -52,7 +52,7 @@
 
 ArtMethod* ArtMethod::FromReflectedMethod(const ScopedObjectAccessAlreadyRunnable& soa,
                                           jobject jlr_method) {
-  auto* executable = soa.Decode<mirror::Executable*>(jlr_method);
+  ObjPtr<mirror::Executable> executable = soa.Decode<mirror::Executable>(jlr_method);
   DCHECK(executable != nullptr);
   return executable->GetArtMethod();
 }
@@ -350,7 +350,7 @@
   ScopedObjectAccess soa(self);
   StackHandleScope<1> shs(self);
 
-  mirror::Class* annotation = soa.Decode<mirror::Class*>(klass);
+  ObjPtr<mirror::Class> annotation = soa.Decode<mirror::Class>(klass);
   DCHECK(annotation->IsAnnotation());
   Handle<mirror::Class> annotation_handle(shs.NewHandle(annotation));
 
diff --git a/runtime/base/mutex.cc b/runtime/base/mutex.cc
index 9d56954..1183dea 100644
--- a/runtime/base/mutex.cc
+++ b/runtime/base/mutex.cc
@@ -26,7 +26,7 @@
 #include "base/value_object.h"
 #include "mutex-inl.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 
 namespace art {
diff --git a/runtime/check_jni.cc b/runtime/check_jni.cc
index a980535..9f07702 100644
--- a/runtime/check_jni.cc
+++ b/runtime/check_jni.cc
@@ -36,7 +36,7 @@
 #include "mirror/string-inl.h"
 #include "mirror/throwable.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread.h"
 #include "well_known_classes.h"
 
@@ -269,12 +269,12 @@
    */
   bool CheckInstanceFieldID(ScopedObjectAccess& soa, jobject java_object, jfieldID fid)
       REQUIRES_SHARED(Locks::mutator_lock_) {
-    mirror::Object* o = soa.Decode<mirror::Object*>(java_object);
+    ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(java_object);
     if (o == nullptr) {
       AbortF("field operation on NULL object: %p", java_object);
       return false;
     }
-    if (!Runtime::Current()->GetHeap()->IsValidObjectAddress(o)) {
+    if (!Runtime::Current()->GetHeap()->IsValidObjectAddress(o.Decode())) {
       Runtime::Current()->GetHeap()->DumpSpaces(LOG_STREAM(ERROR));
       AbortF("field operation on invalid %s: %p",
              ToStr<IndirectRefKind>(GetIndirectRefKind(java_object)).c_str(),
@@ -333,15 +333,15 @@
       return false;
     }
     if (invoke != kVirtual) {
-      mirror::Class* c = soa.Decode<mirror::Class*>(jc);
-      if (!m->GetDeclaringClass()->IsAssignableFrom(c)) {
+      ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(jc);
+      if (!m->GetDeclaringClass()->IsAssignableFrom(c.Decode())) {
         AbortF("can't call %s %s with class %s", invoke == kStatic ? "static" : "nonvirtual",
             PrettyMethod(m).c_str(), PrettyClass(c).c_str());
         return false;
       }
     }
     if (invoke != kStatic) {
-      mirror::Object* o = soa.Decode<mirror::Object*>(jobj);
+      ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(jobj);
       if (o == nullptr) {
         AbortF("can't call %s on null object", PrettyMethod(m).c_str());
         return false;
@@ -360,12 +360,12 @@
    */
   bool CheckStaticFieldID(ScopedObjectAccess& soa, jclass java_class, jfieldID fid)
       REQUIRES_SHARED(Locks::mutator_lock_) {
-    mirror::Class* c = soa.Decode<mirror::Class*>(java_class);
+    ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(java_class);
     ArtField* f = CheckFieldID(soa, fid);
     if (f == nullptr) {
       return false;
     }
-    if (f->GetDeclaringClass() != c) {
+    if (c != f->GetDeclaringClass()) {
       AbortF("static jfieldID %p not valid for class %s", fid, PrettyClass(c).c_str());
       return false;
     }
@@ -387,8 +387,8 @@
     if (m == nullptr) {
       return false;
     }
-    mirror::Class* c = soa.Decode<mirror::Class*>(java_class);
-    if (!m->GetDeclaringClass()->IsAssignableFrom(c)) {
+    ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(java_class);
+    if (!m->GetDeclaringClass()->IsAssignableFrom(c.Decode())) {
       AbortF("can't call static %s on class %s", PrettyMethod(m).c_str(), PrettyClass(c).c_str());
       return false;
     }
@@ -408,7 +408,7 @@
     if (m == nullptr) {
       return false;
     }
-    mirror::Object* o = soa.Decode<mirror::Object*>(java_object);
+    ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(java_object);
     if (o == nullptr) {
       AbortF("can't call %s on null object", PrettyMethod(m).c_str());
       return false;
@@ -557,14 +557,14 @@
 
   bool CheckReflectedMethod(ScopedObjectAccess& soa, jobject jmethod)
       REQUIRES_SHARED(Locks::mutator_lock_) {
-    mirror::Object* method = soa.Decode<mirror::Object*>(jmethod);
+    ObjPtr<mirror::Object> method = soa.Decode<mirror::Object>(jmethod);
     if (method == nullptr) {
       AbortF("expected non-null method");
       return false;
     }
     mirror::Class* c = method->GetClass();
-    if (soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_reflect_Method) != c &&
-        soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_reflect_Constructor) != c) {
+    if (soa.Decode<mirror::Class>(WellKnownClasses::java_lang_reflect_Method) != c &&
+        soa.Decode<mirror::Class>(WellKnownClasses::java_lang_reflect_Constructor) != c) {
       AbortF("expected java.lang.reflect.Method or "
           "java.lang.reflect.Constructor but got object of type %s: %p",
           PrettyTypeOf(method).c_str(), jmethod);
@@ -589,13 +589,13 @@
 
   bool CheckReflectedField(ScopedObjectAccess& soa, jobject jfield)
       REQUIRES_SHARED(Locks::mutator_lock_) {
-    mirror::Object* field = soa.Decode<mirror::Object*>(jfield);
+    ObjPtr<mirror::Object> field = soa.Decode<mirror::Object>(jfield);
     if (field == nullptr) {
       AbortF("expected non-null java.lang.reflect.Field");
       return false;
     }
     mirror::Class* c = field->GetClass();
-    if (soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_reflect_Field) != c) {
+    if (soa.Decode<mirror::Class>(WellKnownClasses::java_lang_reflect_Field) != c) {
       AbortF("expected java.lang.reflect.Field but got object of type %s: %p",
              PrettyTypeOf(field).c_str(), jfield);
       return false;
@@ -605,10 +605,10 @@
 
   bool CheckThrowable(ScopedObjectAccess& soa, jthrowable jobj)
       REQUIRES_SHARED(Locks::mutator_lock_) {
-    mirror::Object* obj = soa.Decode<mirror::Object*>(jobj);
+    ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(jobj);
     if (!obj->GetClass()->IsThrowableClass()) {
       AbortF("expected java.lang.Throwable but got object of type "
-             "%s: %p", PrettyTypeOf(obj).c_str(), obj);
+             "%s: %p", PrettyTypeOf(obj).c_str(), obj.Decode());
       return false;
     }
     return true;
@@ -616,10 +616,10 @@
 
   bool CheckThrowableClass(ScopedObjectAccess& soa, jclass jc)
       REQUIRES_SHARED(Locks::mutator_lock_) {
-    mirror::Class* c = soa.Decode<mirror::Class*>(jc);
+    ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(jc);
     if (!c->IsThrowableClass()) {
       AbortF("expected java.lang.Throwable class but got object of "
-             "type %s: %p", PrettyDescriptor(c).c_str(), c);
+             "type %s: %p", PrettyDescriptor(c).c_str(), c.Decode());
       return false;
     }
     return true;
@@ -647,9 +647,9 @@
 
   bool CheckInstantiableNonArray(ScopedObjectAccess& soa, jclass jc)
       REQUIRES_SHARED(Locks::mutator_lock_) {
-    mirror::Class* c = soa.Decode<mirror::Class*>(jc);
+    ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(jc);
     if (!c->IsInstantiableNonArray()) {
-      AbortF("can't make objects of type %s: %p", PrettyDescriptor(c).c_str(), c);
+      AbortF("can't make objects of type %s: %p", PrettyDescriptor(c).c_str(), c.Decode());
       return false;
     }
     return true;
@@ -660,7 +660,7 @@
     if (!CheckArray(soa, array)) {
       return false;
     }
-    mirror::Array* a = soa.Decode<mirror::Array*>(array);
+    ObjPtr<mirror::Array> a = soa.Decode<mirror::Array>(array);
     if (a->GetClass()->GetComponentType()->GetPrimitiveType() != type) {
       AbortF("incompatible array type %s expected %s[]: %p",
              PrettyDescriptor(a->GetClass()).c_str(), PrettyDescriptor(type).c_str(), array);
@@ -692,20 +692,20 @@
       return false;
     }
     if (is_static) {
-      mirror::Object* o = soa.Decode<mirror::Object*>(obj);
+      ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(obj);
       if (o == nullptr || !o->IsClass()) {
         AbortF("attempt to access static field %s with a class argument of type %s: %p",
                PrettyField(field).c_str(), PrettyTypeOf(o).c_str(), fid);
         return false;
       }
-      mirror::Class* c = o->AsClass();
-      if (field->GetDeclaringClass() != c) {
+      ObjPtr<mirror::Class> c = o->AsClass();
+      if (c != field->GetDeclaringClass()) {
         AbortF("attempt to access static field %s with an incompatible class argument of %s: %p",
                PrettyField(field).c_str(), PrettyDescriptor(c).c_str(), fid);
         return false;
       }
     } else {
-      mirror::Object* o = soa.Decode<mirror::Object*>(obj);
+      ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(obj);
       if (o == nullptr || !field->GetDeclaringClass()->IsAssignableFrom(o->GetClass())) {
         AbortF("attempt to access field %s from an object argument of type %s: %p",
                PrettyField(field).c_str(), PrettyTypeOf(o).c_str(), fid);
@@ -763,7 +763,7 @@
       }
     }
 
-    mirror::Object* obj = soa.Decode<mirror::Object*>(java_object);
+    ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(java_object);
     if (obj == nullptr) {
       // Either java_object is invalid or is a cleared weak.
       IndirectRef ref = reinterpret_cast<IndirectRef>(java_object);
@@ -772,12 +772,12 @@
         okay = false;
       } else {
         obj = soa.Vm()->DecodeWeakGlobal(soa.Self(), ref);
-        okay = Runtime::Current()->IsClearedJniWeakGlobal(obj);
+        okay = Runtime::Current()->IsClearedJniWeakGlobal(obj.Decode());
       }
       if (!okay) {
         AbortF("%s is an invalid %s: %p (%p)",
                what, ToStr<IndirectRefKind>(GetIndirectRefKind(java_object)).c_str(),
-               java_object, obj);
+               java_object, obj.Decode());
         return false;
       }
     }
@@ -786,7 +786,7 @@
       Runtime::Current()->GetHeap()->DumpSpaces(LOG_STREAM(ERROR));
       AbortF("%s is an invalid %s: %p (%p)",
              what, ToStr<IndirectRefKind>(GetIndirectRefKind(java_object)).c_str(),
-             java_object, obj);
+             java_object, obj.Decode());
       return false;
     }
 
@@ -936,10 +936,10 @@
         break;
       case 'c': {  // jclass
         jclass jc = arg.c;
-        mirror::Class* c = soa.Decode<mirror::Class*>(jc);
+        ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(jc);
         if (c == nullptr) {
           *msg += "NULL";
-        } else if (!Runtime::Current()->GetHeap()->IsValidObjectAddress(c)) {
+        } else if (!Runtime::Current()->GetHeap()->IsValidObjectAddress(c.Decode())) {
           StringAppendF(msg, "INVALID POINTER:%p", jc);
         } else if (!c->IsClass()) {
           *msg += "INVALID NON-CLASS OBJECT OF TYPE:" + PrettyTypeOf(c);
@@ -1107,12 +1107,12 @@
       return false;
     }
 
-    mirror::Array* a = soa.Decode<mirror::Array*>(java_array);
-    if (UNLIKELY(!Runtime::Current()->GetHeap()->IsValidObjectAddress(a))) {
+    ObjPtr<mirror::Array> a = soa.Decode<mirror::Array>(java_array);
+    if (UNLIKELY(!Runtime::Current()->GetHeap()->IsValidObjectAddress(a.Decode()))) {
       Runtime::Current()->GetHeap()->DumpSpaces(LOG_STREAM(ERROR));
       AbortF("jarray is an invalid %s: %p (%p)",
              ToStr<IndirectRefKind>(GetIndirectRefKind(java_array)).c_str(),
-             java_array, a);
+             java_array, a.Decode());
       return false;
     } else if (!a->IsArrayInstance()) {
       AbortF("jarray argument has non-array type: %s", PrettyTypeOf(a).c_str());
@@ -1411,7 +1411,7 @@
                                    void* original_ptr) {
     ScopedObjectAccess soa(env);
 
-    mirror::Array* a = soa.Decode<mirror::Array*>(java_array);
+    ObjPtr<mirror::Array> a = soa.Decode<mirror::Array>(java_array);
     size_t component_size = a->GetClass()->GetComponentSize();
     size_t byte_count = a->GetLength() * component_size;
     void* result = Create(original_ptr, byte_count, true);
diff --git a/runtime/check_reference_map_visitor.h b/runtime/check_reference_map_visitor.h
index 843d4c1..ab712f9 100644
--- a/runtime/check_reference_map_visitor.h
+++ b/runtime/check_reference_map_visitor.h
@@ -19,7 +19,7 @@
 
 #include "art_method-inl.h"
 #include "oat_quick_method_header.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "stack_map.h"
 
 namespace art {
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 5106aec..0743cf3 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -91,7 +91,7 @@
 #include "os.h"
 #include "runtime.h"
 #include "ScopedLocalRef.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 #include "trace.h"
 #include "utils.h"
@@ -1085,8 +1085,8 @@
 bool ClassLinker::IsBootClassLoader(ScopedObjectAccessAlreadyRunnable& soa,
                                     mirror::ClassLoader* class_loader) {
   return class_loader == nullptr ||
-      class_loader->GetClass() ==
-          soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_BootClassLoader);
+       soa.Decode<mirror::Class>(WellKnownClasses::java_lang_BootClassLoader) ==
+           class_loader->GetClass();
 }
 
 static mirror::String* GetDexPathListElementName(ScopedObjectAccessUnchecked& soa,
@@ -1125,8 +1125,8 @@
   CHECK(dex_path_list_field != nullptr);
   CHECK(dex_elements_field != nullptr);
   while (!ClassLinker::IsBootClassLoader(soa, class_loader)) {
-    if (class_loader->GetClass() !=
-        soa.Decode<mirror::Class*>(WellKnownClasses::dalvik_system_PathClassLoader)) {
+    if (soa.Decode<mirror::Class>(WellKnownClasses::dalvik_system_PathClassLoader) !=
+        class_loader->GetClass()) {
       *error_msg = StringPrintf("Unknown class loader type %s", PrettyTypeOf(class_loader).c_str());
       // Unsupported class loader.
       return false;
@@ -1703,7 +1703,7 @@
         return false;
       }
       // Add the temporary dex path list elements at the end.
-      auto* elements = soa.Decode<mirror::ObjectArray<mirror::Object>*>(dex_elements);
+      auto elements = soa.Decode<mirror::ObjectArray<mirror::Object>>(dex_elements);
       for (size_t i = 0, num_elems = elements->GetLength(); i < num_elems; ++i) {
         mirror::Object* element = elements->GetWithoutChecks(i);
         if (element != nullptr) {
@@ -2187,7 +2187,7 @@
                                            const char* descriptor,
                                            mirror::Class* klass) {
   DCHECK(klass != nullptr);
-  self->PoisonObjectPointers();
+  Thread::PoisonObjectPointersIfDebug();
 
   // For temporary classes we must wait for them to be retired.
   if (init_done_ && klass->IsTemp()) {
@@ -2304,8 +2304,8 @@
   }
 
   // Unsupported class-loader?
-  if (class_loader->GetClass() !=
-      soa.Decode<mirror::Class*>(WellKnownClasses::dalvik_system_PathClassLoader)) {
+  if (soa.Decode<mirror::Class>(WellKnownClasses::dalvik_system_PathClassLoader) !=
+      class_loader->GetClass()) {
     *result = nullptr;
     return false;
   }
@@ -2482,7 +2482,7 @@
       return nullptr;
     } else {
       // success, return mirror::Class*
-      return soa.Decode<mirror::Class*>(result.get());
+      return soa.Decode<mirror::Class>(result.get()).Decode();
     }
   }
   UNREACHABLE();
@@ -4205,9 +4205,9 @@
   // Set the class access flags incl. VerificationAttempted, so we do not try to set the flag on
   // the methods.
   klass->SetAccessFlags(kAccClassIsProxy | kAccPublic | kAccFinal | kAccVerificationAttempted);
-  klass->SetClassLoader(soa.Decode<mirror::ClassLoader*>(loader));
+  klass->SetClassLoader(soa.Decode<mirror::ClassLoader>(loader).Decode());
   DCHECK_EQ(klass->GetPrimitiveType(), Primitive::kPrimNot);
-  klass->SetName(soa.Decode<mirror::String*>(name));
+  klass->SetName(soa.Decode<mirror::String>(name).Decode());
   klass->SetDexCache(GetClassRoot(kJavaLangReflectProxy)->GetDexCache());
   mirror::Class::SetStatus(klass, mirror::Class::kStatusIdx, self);
   std::string descriptor(GetDescriptorForProxy(klass.Get()));
@@ -4245,7 +4245,7 @@
   const size_t num_direct_methods = 1;
 
   // They have as many virtual methods as the array
-  auto h_methods = hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Method>*>(methods));
+  auto h_methods = hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Method>>(methods));
   DCHECK_EQ(h_methods->GetClass(), mirror::Method::ArrayClass())
       << PrettyClass(h_methods->GetClass());
   const size_t num_virtual_methods = h_methods->GetLength();
@@ -4287,7 +4287,7 @@
     // Link the fields and virtual methods, creating vtable and iftables.
     // The new class will replace the old one in the class table.
     Handle<mirror::ObjectArray<mirror::Class>> h_interfaces(
-        hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Class>*>(interfaces)));
+        hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Class>>(interfaces)));
     if (!LinkClass(self, descriptor.c_str(), klass, h_interfaces, &new_class)) {
       mirror::Class::SetStatus(klass, mirror::Class::kStatusError, self);
       return nullptr;
@@ -4298,11 +4298,13 @@
   klass.Assign(new_class.Get());
 
   CHECK_EQ(interfaces_sfield.GetDeclaringClass(), klass.Get());
-  interfaces_sfield.SetObject<false>(klass.Get(),
-                                     soa.Decode<mirror::ObjectArray<mirror::Class>*>(interfaces));
+  interfaces_sfield.SetObject<false>(
+      klass.Get(),
+      soa.Decode<mirror::ObjectArray<mirror::Class>>(interfaces).Decode());
   CHECK_EQ(throws_sfield.GetDeclaringClass(), klass.Get());
   throws_sfield.SetObject<false>(
-      klass.Get(), soa.Decode<mirror::ObjectArray<mirror::ObjectArray<mirror::Class> >*>(throws));
+      klass.Get(),
+      soa.Decode<mirror::ObjectArray<mirror::ObjectArray<mirror::Class>>>(throws).Decode());
 
   {
     // Lock on klass is released. Lock new class object.
@@ -4322,7 +4324,7 @@
     }
 
     StackHandleScope<1> hs2(self);
-    Handle<mirror::String> decoded_name = hs2.NewHandle(soa.Decode<mirror::String*>(name));
+    Handle<mirror::String> decoded_name = hs2.NewHandle(soa.Decode<mirror::String>(name));
     std::string interfaces_field_name(StringPrintf("java.lang.Class[] %s.interfaces",
                                                    decoded_name->ToModifiedUtf8().c_str()));
     CHECK_EQ(PrettyField(klass->GetStaticField(0)), interfaces_field_name);
@@ -4332,9 +4334,9 @@
     CHECK_EQ(PrettyField(klass->GetStaticField(1)), throws_field_name);
 
     CHECK_EQ(klass.Get()->GetInterfaces(),
-             soa.Decode<mirror::ObjectArray<mirror::Class>*>(interfaces));
+             soa.Decode<mirror::ObjectArray<mirror::Class>>(interfaces).Decode());
     CHECK_EQ(klass.Get()->GetThrows(),
-             soa.Decode<mirror::ObjectArray<mirror::ObjectArray<mirror::Class>>*>(throws));
+             soa.Decode<mirror::ObjectArray<mirror::ObjectArray<mirror::Class>>>(throws).Decode());
   }
   return klass.Get();
 }
@@ -8193,7 +8195,7 @@
 
   // Create PathClassLoader.
   Handle<mirror::Class> h_path_class_class = hs.NewHandle(
-      soa.Decode<mirror::Class*>(WellKnownClasses::dalvik_system_PathClassLoader));
+      soa.Decode<mirror::Class>(WellKnownClasses::dalvik_system_PathClassLoader));
   Handle<mirror::Object> h_path_class_loader = hs.NewHandle(
       h_path_class_class->AllocObject(self));
   DCHECK(h_path_class_loader.Get() != nullptr);
@@ -8210,7 +8212,7 @@
                                "Ljava/lang/ClassLoader;");
   DCHECK(parent_field != nullptr);
   mirror::Object* boot_cl =
-      soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_BootClassLoader)->AllocObject(self);
+      soa.Decode<mirror::Class>(WellKnownClasses::java_lang_BootClassLoader)->AllocObject(self);
   parent_field->SetObject<false>(h_path_class_loader.Get(), boot_cl);
 
   // Make it a global ref and return.
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 4f73218..a5aa0d0 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -42,7 +42,7 @@
 #include "mirror/stack_trace_element.h"
 #include "mirror/string-inl.h"
 #include "handle_scope-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 
 namespace art {
@@ -777,7 +777,7 @@
   ScopedObjectAccess soa(Thread::Current());
   StackHandleScope<1> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader(
-      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Nested"))));
+      hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("Nested"))));
 
   mirror::Class* outer = class_linker_->FindClass(soa.Self(), "LNested;", class_loader);
   ASSERT_TRUE(outer != nullptr);
@@ -811,7 +811,7 @@
 
   StackHandleScope<1> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader(
-      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("MyClass"))));
+      hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("MyClass"))));
   AssertNonExistentClass("LMyClass;");
   mirror::Class* MyClass = class_linker_->FindClass(soa.Self(), "LMyClass;", class_loader);
   ASSERT_TRUE(MyClass != nullptr);
@@ -937,9 +937,9 @@
   ScopedObjectAccess soa(Thread::Current());
   StackHandleScope<2> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader_1(
-      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("MyClass"))));
+      hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("MyClass"))));
   Handle<mirror::ClassLoader> class_loader_2(
-      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("MyClass"))));
+      hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("MyClass"))));
   mirror::Class* MyClass_1 = class_linker_->FindClass(soa.Self(), "LMyClass;", class_loader_1);
   mirror::Class* MyClass_2 = class_linker_->FindClass(soa.Self(), "LMyClass;", class_loader_2);
   EXPECT_TRUE(MyClass_1 != nullptr);
@@ -951,7 +951,7 @@
   ScopedObjectAccess soa(Thread::Current());
   StackHandleScope<2> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader(
-      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Statics"))));
+      hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("Statics"))));
   Handle<mirror::Class> statics(
       hs.NewHandle(class_linker_->FindClass(soa.Self(), "LStatics;", class_loader)));
   class_linker_->EnsureInitialized(soa.Self(), statics, true, true);
@@ -1028,7 +1028,7 @@
   ScopedObjectAccess soa(Thread::Current());
   StackHandleScope<6> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader(
-      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Interfaces"))));
+      hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("Interfaces"))));
   Handle<mirror::Class> I(
       hs.NewHandle(class_linker_->FindClass(soa.Self(), "LInterfaces$I;", class_loader)));
   Handle<mirror::Class> J(
@@ -1097,7 +1097,7 @@
   const DexFile* dex_file = GetFirstDexFile(jclass_loader);
   StackHandleScope<1> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader(
-      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+      hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader)));
   mirror::Class* klass = class_linker_->FindClass(soa.Self(), "LStaticsFromCode;", class_loader);
   ArtMethod* clinit = klass->FindClassInitializer(kRuntimePointerSize);
   ArtMethod* getS0 = klass->FindDirectMethod("getS0", "()Ljava/lang/Object;", kRuntimePointerSize);
@@ -1227,7 +1227,7 @@
 
   StackHandleScope<2> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader(
-      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Statics"))));
+      hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("Statics"))));
   Handle<mirror::Class> statics(
       hs.NewHandle(class_linker_->FindClass(soa.Self(), "LStatics;", class_loader)));
 
@@ -1242,7 +1242,7 @@
 
   StackHandleScope<3> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader(
-      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Statics"))));
+      hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("Statics"))));
 
   // java.lang.Object is a bootstrap class.
   Handle<mirror::Class> jlo_class(
diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc
index 11722b2..eda1ddd 100644
--- a/runtime/common_runtime_test.cc
+++ b/runtime/common_runtime_test.cc
@@ -47,7 +47,7 @@
 #include "os.h"
 #include "primitive.h"
 #include "runtime-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread.h"
 #include "well_known_classes.h"
 
@@ -511,12 +511,12 @@
 
   StackHandleScope<2> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader = hs.NewHandle(
-      soa.Decode<mirror::ClassLoader*>(jclass_loader));
+      soa.Decode<mirror::ClassLoader>(jclass_loader));
 
   DCHECK_EQ(class_loader->GetClass(),
-            soa.Decode<mirror::Class*>(WellKnownClasses::dalvik_system_PathClassLoader));
+            soa.Decode<mirror::Class>(WellKnownClasses::dalvik_system_PathClassLoader).Decode());
   DCHECK_EQ(class_loader->GetParent()->GetClass(),
-            soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_BootClassLoader));
+            soa.Decode<mirror::Class>(WellKnownClasses::java_lang_BootClassLoader).Decode());
 
   // The class loader is a PathClassLoader which inherits from BaseDexClassLoader.
   // We need to get the DexPathList and loop through it.
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 6ed44fc..0206cae 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -48,7 +48,7 @@
 #include "mirror/throwable.h"
 #include "reflection.h"
 #include "safe_map.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "ScopedLocalRef.h"
 #include "ScopedPrimitiveArray.h"
 #include "handle_scope-inl.h"
@@ -390,7 +390,8 @@
     return nullptr;
   }
 
-  mirror::Class* java_lang_Thread = soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_Thread);
+  ObjPtr<mirror::Class> java_lang_Thread =
+      soa.Decode<mirror::Class>(WellKnownClasses::java_lang_Thread);
   if (!java_lang_Thread->IsAssignableFrom(thread_peer->GetClass())) {
     // This isn't a thread.
     *error = JDWP::ERR_INVALID_THREAD;
@@ -431,21 +432,22 @@
     return JDWP::JT_CLASS_OBJECT;
   }
   {
-    mirror::Class* thread_class = soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_Thread);
+    ObjPtr<mirror::Class> thread_class =
+        soa.Decode<mirror::Class>(WellKnownClasses::java_lang_Thread);
     if (thread_class->IsAssignableFrom(c)) {
       return JDWP::JT_THREAD;
     }
   }
   {
-    mirror::Class* thread_group_class =
-        soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_ThreadGroup);
+    ObjPtr<mirror::Class> thread_group_class =
+        soa.Decode<mirror::Class>(WellKnownClasses::java_lang_ThreadGroup);
     if (thread_group_class->IsAssignableFrom(c)) {
       return JDWP::JT_THREAD_GROUP;
     }
   }
   {
-    mirror::Class* class_loader_class =
-        soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_ClassLoader);
+    ObjPtr<mirror::Class> class_loader_class =
+        soa.Decode<mirror::Class>(WellKnownClasses::java_lang_ClassLoader);
     if (class_loader_class->IsAssignableFrom(c)) {
       return JDWP::JT_CLASS_LOADER;
     }
@@ -1946,7 +1948,8 @@
   }
   {
     ScopedObjectAccessUnchecked soa(Thread::Current());
-    mirror::Class* java_lang_String = soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_String);
+    ObjPtr<mirror::Class> java_lang_String =
+        soa.Decode<mirror::Class>(WellKnownClasses::java_lang_String);
     if (!java_lang_String->IsAssignableFrom(obj->GetClass())) {
       // This isn't a string.
       return JDWP::ERR_INVALID_STRING;
@@ -2014,7 +2017,7 @@
     expandBufAddObjectId(pReply, JDWP::ObjectId(0));
     error = JDWP::ERR_NONE;
   } else if (error == JDWP::ERR_NONE) {
-    mirror::Class* c = soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_Thread);
+    ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(WellKnownClasses::java_lang_Thread);
     CHECK(c != nullptr);
     ArtField* f = soa.DecodeField(WellKnownClasses::java_lang_Thread_group);
     CHECK(f != nullptr);
@@ -2038,7 +2041,8 @@
     *error = JDWP::ERR_INVALID_OBJECT;
     return nullptr;
   }
-  mirror::Class* c = soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_ThreadGroup);
+  ObjPtr<mirror::Class> c =
+      soa.Decode<mirror::Class>(WellKnownClasses::java_lang_ThreadGroup);
   CHECK(c != nullptr);
   if (!c->IsAssignableFrom(thread_group->GetClass())) {
     // This is not a java.lang.ThreadGroup.
diff --git a/runtime/dex_file_annotations.cc b/runtime/dex_file_annotations.cc
index 789a5bd..5763479 100644
--- a/runtime/dex_file_annotations.cc
+++ b/runtime/dex_file_annotations.cc
@@ -255,7 +255,7 @@
   }
 
   mirror::Class* annotation_member_class =
-      soa.Decode<mirror::Class*>(WellKnownClasses::libcore_reflect_AnnotationMember);
+      soa.Decode<mirror::Class>(WellKnownClasses::libcore_reflect_AnnotationMember).Decode();
   mirror::Class* annotation_member_array_class =
       class_linker->FindArrayClass(self, &annotation_member_class);
   if (annotation_member_array_class == nullptr) {
@@ -782,7 +782,7 @@
   ScopedObjectAccessUnchecked soa(self);
   StackHandleScope<2> hs(self);
   Handle<mirror::Class> annotation_array_class(hs.NewHandle(
-      soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_annotation_Annotation__array)));
+      soa.Decode<mirror::Class>(WellKnownClasses::java_lang_annotation_Annotation__array)));
   if (annotation_set == nullptr) {
     return mirror::ObjectArray<mirror::Object>::Alloc(self, annotation_array_class.Get(), 0);
   }
@@ -840,7 +840,7 @@
   ScopedObjectAccessUnchecked soa(self);
   StackHandleScope<1> hs(self);
   mirror::Class* annotation_array_class =
-      soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_annotation_Annotation__array);
+      soa.Decode<mirror::Class>(WellKnownClasses::java_lang_annotation_Annotation__array).Decode();
   mirror::Class* annotation_array_array_class =
       Runtime::Current()->GetClassLinker()->FindArrayClass(self, &annotation_array_class);
   if (annotation_array_array_class == nullptr) {
diff --git a/runtime/dex_file_test.cc b/runtime/dex_file_test.cc
index 8dd5f37..8e1501f 100644
--- a/runtime/dex_file_test.cc
+++ b/runtime/dex_file_test.cc
@@ -24,7 +24,7 @@
 #include "dex_file-inl.h"
 #include "mem_map.h"
 #include "os.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 #include "utils.h"
 
diff --git a/runtime/dex_file_verifier_test.cc b/runtime/dex_file_verifier_test.cc
index c5a4d75..e392870 100644
--- a/runtime/dex_file_verifier_test.cc
+++ b/runtime/dex_file_verifier_test.cc
@@ -27,7 +27,7 @@
 #include "common_runtime_test.h"
 #include "dex_file-inl.h"
 #include "leb128.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 #include "utils.h"
 
diff --git a/runtime/dex_method_iterator_test.cc b/runtime/dex_method_iterator_test.cc
index 2681ad0..9f28c8c 100644
--- a/runtime/dex_method_iterator_test.cc
+++ b/runtime/dex_method_iterator_test.cc
@@ -19,7 +19,7 @@
 #include "base/stl_util.h"
 #include "common_runtime_test.h"
 #include "oat_file.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 
 namespace art {
diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc
index bfa2b69..38ee468 100644
--- a/runtime/entrypoints/entrypoint_utils.cc
+++ b/runtime/entrypoints/entrypoint_utils.cc
@@ -33,7 +33,7 @@
 #include "nth_caller_visitor.h"
 #include "oat_quick_method_header.h"
 #include "reflection.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "well_known_classes.h"
 
 namespace art {
@@ -165,7 +165,7 @@
           CHECK(soa.Self()->IsExceptionPending());
           return zero;
         }
-        soa.Decode<mirror::ObjectArray<mirror::Object>* >(args_jobj)->Set<false>(i, val);
+        soa.Decode<mirror::ObjectArray<mirror::Object>>(args_jobj)->Set<false>(i, val);
       }
     }
   }
@@ -187,13 +187,13 @@
       return zero;
     } else {
       ArtMethod* interface_method =
-          soa.Decode<mirror::Method*>(interface_method_jobj)->GetArtMethod();
+          soa.Decode<mirror::Method>(interface_method_jobj)->GetArtMethod();
       // This can cause thread suspension.
       PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
       mirror::Class* result_type = interface_method->GetReturnType(true /* resolve */, pointer_size);
-      mirror::Object* result_ref = soa.Decode<mirror::Object*>(result);
+      ObjPtr<mirror::Object> result_ref = soa.Decode<mirror::Object>(result);
       JValue result_unboxed;
-      if (!UnboxPrimitiveForResult(result_ref, result_type, &result_unboxed)) {
+      if (!UnboxPrimitiveForResult(result_ref.Decode(), result_type, &result_unboxed)) {
         DCHECK(soa.Self()->IsExceptionPending());
         return zero;
       }
@@ -207,9 +207,9 @@
       bool declares_exception = false;
       {
         ScopedAssertNoThreadSuspension ants(__FUNCTION__);
-        mirror::Object* rcvr = soa.Decode<mirror::Object*>(rcvr_jobj);
+        ObjPtr<mirror::Object> rcvr = soa.Decode<mirror::Object>(rcvr_jobj);
         mirror::Class* proxy_class = rcvr->GetClass();
-        mirror::Method* interface_method = soa.Decode<mirror::Method*>(interface_method_jobj);
+        ObjPtr<mirror::Method> interface_method = soa.Decode<mirror::Method>(interface_method_jobj);
         ArtMethod* proxy_method = rcvr->GetClass()->FindVirtualMethodForInterface(
             interface_method->GetArtMethod(), kRuntimePointerSize);
         auto virtual_methods = proxy_class->GetVirtualMethodsSlice(kRuntimePointerSize);
diff --git a/runtime/entrypoints/jni/jni_entrypoints.cc b/runtime/entrypoints/jni/jni_entrypoints.cc
index 22226c1..fd23ced 100644
--- a/runtime/entrypoints/jni/jni_entrypoints.cc
+++ b/runtime/entrypoints/jni/jni_entrypoints.cc
@@ -18,7 +18,7 @@
 #include "base/logging.h"
 #include "entrypoints/entrypoint_utils.h"
 #include "mirror/object-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread.h"
 
 namespace art {
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index cfd948e..c52bc8e 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -36,7 +36,7 @@
 #include "oat_quick_method_header.h"
 #include "quick_exception_handler.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "stack.h"
 #include "debugger.h"
 
@@ -834,7 +834,7 @@
 void BuildQuickArgumentVisitor::FixupReferences() {
   // Fixup any references which may have changed.
   for (const auto& pair : references_) {
-    pair.second->Assign(soa_->Decode<mirror::Object*>(pair.first));
+    pair.second->Assign(soa_->Decode<mirror::Object>(pair.first).Decode());
     soa_->Env()->DeleteLocalRef(pair.first);
   }
 }
@@ -926,7 +926,7 @@
 void RememberForGcArgumentVisitor::FixupReferences() {
   // Fixup any references which may have changed.
   for (const auto& pair : references_) {
-    pair.second->Assign(soa_->Decode<mirror::Object*>(pair.first));
+    pair.second->Assign(soa_->Decode<mirror::Object>(pair.first).Decode());
     soa_->Env()->DeleteLocalRef(pair.first);
   }
 }
diff --git a/runtime/gc/accounting/card_table_test.cc b/runtime/gc/accounting/card_table_test.cc
index 819cb85..67ab14c 100644
--- a/runtime/gc/accounting/card_table_test.cc
+++ b/runtime/gc/accounting/card_table_test.cc
@@ -23,7 +23,7 @@
 #include "handle_scope-inl.h"
 #include "mirror/class-inl.h"
 #include "mirror/string-inl.h"  // Strings are easiest to allocate
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread_pool.h"
 #include "utils.h"
 
diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc
index ab8942a..8b91075 100644
--- a/runtime/gc/collector/concurrent_copying.cc
+++ b/runtime/gc/collector/concurrent_copying.cc
@@ -32,7 +32,7 @@
 #include "intern_table.h"
 #include "mirror/class-inl.h"
 #include "mirror/object-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 #include "thread_list.h"
 #include "well_known_classes.h"
diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc
index ad3dd33..b89d99c 100644
--- a/runtime/gc/collector/mark_sweep.cc
+++ b/runtime/gc/collector/mark_sweep.cc
@@ -41,7 +41,7 @@
 #include "mark_sweep-inl.h"
 #include "mirror/object-inl.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 #include "thread_list.h"
 
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 4e6dd2b..88e4624 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -61,6 +61,7 @@
 #include "intern_table.h"
 #include "jit/jit.h"
 #include "jit/jit_code_cache.h"
+#include "obj_ptr-inl.h"
 #include "mirror/class-inl.h"
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
@@ -69,7 +70,7 @@
 #include "reflection.h"
 #include "runtime.h"
 #include "ScopedLocalRef.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "handle_scope-inl.h"
 #include "thread_list.h"
 #include "well_known_classes.h"
@@ -1507,13 +1508,14 @@
       << static_cast<int>(100 * managed_utilization) << "%.";
 }
 
-bool Heap::IsValidObjectAddress(const mirror::Object* obj) const {
+bool Heap::IsValidObjectAddress(ObjPtr<mirror::Object> obj) const {
   // Note: we deliberately don't take the lock here, and mustn't test anything that would require
   // taking the lock.
   if (obj == nullptr) {
     return true;
   }
-  return IsAligned<kObjectAlignment>(obj) && FindSpaceFromObject(obj, true) != nullptr;
+  return IsAligned<kObjectAlignment>(obj.Decode()) &&
+      FindSpaceFromObject(obj.Decode(), true) != nullptr;
 }
 
 bool Heap::IsNonDiscontinuousSpaceHeapAddress(const mirror::Object* obj) const {
@@ -3565,9 +3567,9 @@
   max_allowed_footprint_ = max_allowed_footprint;
 }
 
-bool Heap::IsMovableObject(const mirror::Object* obj) const {
+bool Heap::IsMovableObject(ObjPtr<mirror::Object> obj) const {
   if (kMovingCollector) {
-    space::Space* space = FindContinuousSpaceFromObject(obj, true);
+    space::Space* space = FindContinuousSpaceFromObject(obj.Decode(), true);
     if (space != nullptr) {
       // TODO: Check large object?
       return space->CanMoveObjects();
@@ -3727,7 +3729,7 @@
   args[0].l = arg.get();
   InvokeWithJValues(soa, nullptr, WellKnownClasses::java_lang_ref_FinalizerReference_add, args);
   // Restore object in case it gets moved.
-  *object = soa.Decode<mirror::Object*>(arg.get());
+  *object = soa.Decode<mirror::Object>(arg.get()).Decode();
 }
 
 void Heap::RequestConcurrentGCAndSaveObject(Thread* self, bool force_full, mirror::Object** obj) {
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index 10bebef..e32f057 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -34,6 +34,7 @@
 #include "gc/collector_type.h"
 #include "gc/space/large_object_space.h"
 #include "globals.h"
+#include "obj_ptr.h"
 #include "object_callbacks.h"
 #include "offsets.h"
 #include "process_state.h"
@@ -274,7 +275,7 @@
   // A weaker test than IsLiveObject or VerifyObject that doesn't require the heap lock,
   // and doesn't abort on error, allowing the caller to report more
   // meaningful diagnostics.
-  bool IsValidObjectAddress(const mirror::Object* obj) const REQUIRES_SHARED(Locks::mutator_lock_);
+  bool IsValidObjectAddress(ObjPtr<mirror::Object> obj) const REQUIRES_SHARED(Locks::mutator_lock_);
 
   // Faster alternative to IsHeapAddress since finding if an object is in the large object space is
   // very slow.
@@ -290,7 +291,7 @@
       REQUIRES_SHARED(Locks::heap_bitmap_lock_, Locks::mutator_lock_);
 
   // Returns true if there is any chance that the object (obj) will move.
-  bool IsMovableObject(const mirror::Object* obj) const REQUIRES_SHARED(Locks::mutator_lock_);
+  bool IsMovableObject(ObjPtr<mirror::Object> obj) const REQUIRES_SHARED(Locks::mutator_lock_);
 
   // Enables us to compacting GC until objects are released.
   void IncrementDisableMovingGC(Thread* self) REQUIRES(!*gc_complete_lock_);
diff --git a/runtime/gc/heap_test.cc b/runtime/gc/heap_test.cc
index a3cefd9..515a6fd 100644
--- a/runtime/gc/heap_test.cc
+++ b/runtime/gc/heap_test.cc
@@ -22,7 +22,7 @@
 #include "mirror/class-inl.h"
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 namespace gc {
diff --git a/runtime/gc/reference_processor.cc b/runtime/gc/reference_processor.cc
index e172f85..9694597 100644
--- a/runtime/gc/reference_processor.cc
+++ b/runtime/gc/reference_processor.cc
@@ -24,7 +24,7 @@
 #include "reference_processor-inl.h"
 #include "reflection.h"
 #include "ScopedLocalRef.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "task_processor.h"
 #include "utils.h"
 #include "well_known_classes.h"
diff --git a/runtime/gc/reference_queue_test.cc b/runtime/gc/reference_queue_test.cc
index 2a1635d..5b8a3c2 100644
--- a/runtime/gc/reference_queue_test.cc
+++ b/runtime/gc/reference_queue_test.cc
@@ -20,7 +20,7 @@
 #include "reference_queue.h"
 #include "handle_scope-inl.h"
 #include "mirror/class-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 namespace gc {
diff --git a/runtime/gc/space/large_object_space.cc b/runtime/gc/space/large_object_space.cc
index 16d1f93..0030326 100644
--- a/runtime/gc/space/large_object_space.cc
+++ b/runtime/gc/space/large_object_space.cc
@@ -27,7 +27,7 @@
 #include "base/stl_util.h"
 #include "image.h"
 #include "os.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "space-inl.h"
 #include "thread-inl.h"
 
diff --git a/runtime/gc/space/space_create_test.cc b/runtime/gc/space/space_create_test.cc
index 170f927..7bc4dc4 100644
--- a/runtime/gc/space/space_create_test.cc
+++ b/runtime/gc/space/space_create_test.cc
@@ -18,7 +18,7 @@
 
 #include "dlmalloc_space.h"
 #include "rosalloc_space.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 namespace gc {
diff --git a/runtime/gc/space/space_test.h b/runtime/gc/space/space_test.h
index bd600fe..17d7c87 100644
--- a/runtime/gc/space/space_test.h
+++ b/runtime/gc/space/space_test.h
@@ -26,7 +26,7 @@
 #include "mirror/class-inl.h"
 #include "mirror/class_loader.h"
 #include "mirror/object-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread_list.h"
 #include "zygote_space.h"
 
diff --git a/runtime/gc/system_weak_test.cc b/runtime/gc/system_weak_test.cc
index 7c1ec8a..af8a444 100644
--- a/runtime/gc/system_weak_test.cc
+++ b/runtime/gc/system_weak_test.cc
@@ -26,7 +26,7 @@
 #include "handle_scope-inl.h"
 #include "heap.h"
 #include "mirror/string.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread_list.h"
 
 namespace art {
diff --git a/runtime/gc/task_processor.cc b/runtime/gc/task_processor.cc
index a49121b..0704a68 100644
--- a/runtime/gc/task_processor.cc
+++ b/runtime/gc/task_processor.cc
@@ -17,7 +17,7 @@
 #include "task_processor.h"
 
 #include "base/time_utils.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 namespace gc {
diff --git a/runtime/handle_scope-inl.h b/runtime/handle_scope-inl.h
index 2e1b8ed3..75a0391 100644
--- a/runtime/handle_scope-inl.h
+++ b/runtime/handle_scope-inl.h
@@ -21,6 +21,7 @@
 
 #include "base/mutex.h"
 #include "handle.h"
+#include "obj_ptr-inl.h"
 #include "thread-inl.h"
 #include "verify_object-inl.h"
 
@@ -107,12 +108,21 @@
   return h;
 }
 
+template<size_t kNumReferences> template<class MirrorType, bool kPoison>
+inline MutableHandle<MirrorType> StackHandleScope<kNumReferences>::NewHandle(
+    ObjPtr<MirrorType, kPoison> object) {
+  return NewHandle(object.Decode());
+}
+
 template<size_t kNumReferences> template<class T>
 inline HandleWrapper<T> StackHandleScope<kNumReferences>::NewHandleWrapper(T** object) {
-  SetReference(pos_, *object);
-  MutableHandle<T> h(GetHandle<T>(pos_));
-  pos_++;
-  return HandleWrapper<T>(object, h);
+  return HandleWrapper<T>(object, NewHandle(*object));
+}
+
+template<size_t kNumReferences> template<class T>
+inline HandleWrapperObjPtr<T> StackHandleScope<kNumReferences>::NewHandleWrapper(
+    ObjPtr<T>* object) {
+  return HandleWrapperObjPtr<T>(object, NewHandle(*object));
 }
 
 template<size_t kNumReferences>
diff --git a/runtime/handle_scope.h b/runtime/handle_scope.h
index 37eed99..2b283ae 100644
--- a/runtime/handle_scope.h
+++ b/runtime/handle_scope.h
@@ -28,6 +28,9 @@
 #include "verify_object.h"
 
 namespace art {
+
+template<class MirrorType, bool kPoison> class ObjPtr;
+
 namespace mirror {
 class Object;
 }
@@ -125,7 +128,7 @@
 };
 
 // A wrapper which wraps around Object** and restores the pointer in the destructor.
-// TODO: Add more functionality.
+// TODO: Delete
 template<class T>
 class HandleWrapper : public MutableHandle<T> {
  public:
@@ -143,6 +146,26 @@
   T** const obj_;
 };
 
+
+// A wrapper which wraps around ObjPtr<Object>* and restores the pointer in the destructor.
+// TODO: Add more functionality.
+template<class T>
+class HandleWrapperObjPtr : public MutableHandle<T> {
+ public:
+  HandleWrapperObjPtr(ObjPtr<T>* obj, const MutableHandle<T>& handle)
+      : MutableHandle<T>(handle), obj_(obj) {}
+
+  HandleWrapperObjPtr(const HandleWrapperObjPtr&) = default;
+
+  ~HandleWrapperObjPtr() {
+    *obj_ = ObjPtr<T>(MutableHandle<T>::Get());
+  }
+
+ private:
+  ObjPtr<T>* const obj_;
+};
+
+
 // Scoped handle storage of a fixed size that is usually stack allocated.
 template<size_t kNumReferences>
 class PACKED(4) StackHandleScope FINAL : public HandleScope {
@@ -157,6 +180,14 @@
   ALWAYS_INLINE HandleWrapper<T> NewHandleWrapper(T** object)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
+  template<class T>
+  ALWAYS_INLINE HandleWrapperObjPtr<T> NewHandleWrapper(ObjPtr<T>* object)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
+  template<class MirrorType, bool kPoison>
+  ALWAYS_INLINE MutableHandle<MirrorType> NewHandle(ObjPtr<MirrorType, kPoison> object)
+    REQUIRES_SHARED(Locks::mutator_lock_);
+
   ALWAYS_INLINE void SetReference(size_t i, mirror::Object* object)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
diff --git a/runtime/handle_scope_test.cc b/runtime/handle_scope_test.cc
index 58f3800..c269a37 100644
--- a/runtime/handle_scope_test.cc
+++ b/runtime/handle_scope_test.cc
@@ -17,7 +17,7 @@
 #include "base/enums.h"
 #include "gtest/gtest.h"
 #include "handle_scope-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread.h"
 
 namespace art {
diff --git a/runtime/hprof/hprof.cc b/runtime/hprof/hprof.cc
index 921dde1..ecb2157 100644
--- a/runtime/hprof/hprof.cc
+++ b/runtime/hprof/hprof.cc
@@ -59,7 +59,7 @@
 #include "mirror/object-inl.h"
 #include "os.h"
 #include "safe_map.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread_list.h"
 
 namespace art {
diff --git a/runtime/indirect_reference_table.cc b/runtime/indirect_reference_table.cc
index 1f39a1e..202e472 100644
--- a/runtime/indirect_reference_table.cc
+++ b/runtime/indirect_reference_table.cc
@@ -21,7 +21,7 @@
 #include "nth_caller_visitor.h"
 #include "reference_table.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread.h"
 #include "utils.h"
 #include "verify_object-inl.h"
diff --git a/runtime/indirect_reference_table_test.cc b/runtime/indirect_reference_table_test.cc
index 61bcadd..58d487d 100644
--- a/runtime/indirect_reference_table_test.cc
+++ b/runtime/indirect_reference_table_test.cc
@@ -19,7 +19,7 @@
 #include "class_linker-inl.h"
 #include "common_runtime_test.h"
 #include "mirror/object-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 
diff --git a/runtime/instrumentation_test.cc b/runtime/instrumentation_test.cc
index abe3184..7f9f04f 100644
--- a/runtime/instrumentation_test.cc
+++ b/runtime/instrumentation_test.cc
@@ -25,7 +25,7 @@
 #include "handle_scope-inl.h"
 #include "jvalue.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread_list.h"
 #include "thread-inl.h"
 
@@ -458,7 +458,7 @@
   instrumentation::Instrumentation* instr = runtime->GetInstrumentation();
   ClassLinker* class_linker = runtime->GetClassLinker();
   StackHandleScope<1> hs(soa.Self());
-  Handle<mirror::ClassLoader> loader(hs.NewHandle(soa.Decode<mirror::ClassLoader*>(class_loader)));
+  Handle<mirror::ClassLoader> loader(hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader)));
   mirror::Class* klass = class_linker->FindClass(soa.Self(), "LInstrumentation;", loader);
   ASSERT_TRUE(klass != nullptr);
   ArtMethod* method_to_deoptimize = klass->FindDeclaredDirectMethod("instanceMethod", "()V",
@@ -505,7 +505,7 @@
   instrumentation::Instrumentation* instr = runtime->GetInstrumentation();
   ClassLinker* class_linker = runtime->GetClassLinker();
   StackHandleScope<1> hs(soa.Self());
-  Handle<mirror::ClassLoader> loader(hs.NewHandle(soa.Decode<mirror::ClassLoader*>(class_loader)));
+  Handle<mirror::ClassLoader> loader(hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader)));
   mirror::Class* klass = class_linker->FindClass(soa.Self(), "LInstrumentation;", loader);
   ASSERT_TRUE(klass != nullptr);
   ArtMethod* method_to_deoptimize = klass->FindDeclaredDirectMethod("instanceMethod", "()V",
diff --git a/runtime/intern_table_test.cc b/runtime/intern_table_test.cc
index 620e15b..74cec57 100644
--- a/runtime/intern_table_test.cc
+++ b/runtime/intern_table_test.cc
@@ -20,7 +20,7 @@
 #include "mirror/object.h"
 #include "handle_scope-inl.h"
 #include "mirror/string.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index 0003e72..c270df7 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -23,7 +23,7 @@
 #include "interpreter_mterp_impl.h"
 #include "interpreter_switch_impl.h"
 #include "mirror/string-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "ScopedLocalRef.h"
 #include "stack.h"
 #include "unstarted_runtime.h"
@@ -51,7 +51,7 @@
         ScopedThreadStateChange tsc(self, kNative);
         jresult = fn(soa.Env(), klass.get());
       }
-      result->SetL(soa.Decode<Object*>(jresult));
+      result->SetL(soa.Decode<Object>(jresult).Decode());
     } else if (shorty == "V") {
       typedef void (fntype)(JNIEnv*, jclass);
       fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni());
@@ -93,7 +93,7 @@
         ScopedThreadStateChange tsc(self, kNative);
         jresult = fn(soa.Env(), klass.get(), arg0.get());
       }
-      result->SetL(soa.Decode<Object*>(jresult));
+      result->SetL(soa.Decode<Object>(jresult).Decode());
     } else if (shorty == "IIZ") {
       typedef jint (fntype)(JNIEnv*, jclass, jint, jboolean);
       fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni());
@@ -191,7 +191,7 @@
         ScopedThreadStateChange tsc(self, kNative);
         jresult = fn(soa.Env(), rcvr.get());
       }
-      result->SetL(soa.Decode<Object*>(jresult));
+      result->SetL(soa.Decode<Object>(jresult).Decode());
     } else if (shorty == "V") {
       typedef void (fntype)(JNIEnv*, jobject);
       fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni());
@@ -212,7 +212,7 @@
         ScopedThreadStateChange tsc(self, kNative);
         jresult = fn(soa.Env(), rcvr.get(), arg0.get());
       }
-      result->SetL(soa.Decode<Object*>(jresult));
+      result->SetL(soa.Decode<Object>(jresult).Decode());
       ScopedThreadStateChange tsc(self, kNative);
     } else if (shorty == "III") {
       typedef jint (fntype)(JNIEnv*, jobject, jint, jint);
diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc
index 98e358b..39846da 100644
--- a/runtime/interpreter/unstarted_runtime.cc
+++ b/runtime/interpreter/unstarted_runtime.cc
@@ -1619,9 +1619,9 @@
     uint32_t* args ATTRIBUTE_UNUSED, JValue* result) {
   ScopedObjectAccessUnchecked soa(self);
   if (Runtime::Current()->IsActiveTransaction()) {
-    result->SetL(soa.Decode<mirror::Object*>(self->CreateInternalStackTrace<true>(soa)));
+    result->SetL(soa.Decode<mirror::Object>(self->CreateInternalStackTrace<true>(soa)).Decode());
   } else {
-    result->SetL(soa.Decode<mirror::Object*>(self->CreateInternalStackTrace<false>(soa)));
+    result->SetL(soa.Decode<mirror::Object>(self->CreateInternalStackTrace<false>(soa)).Decode());
   }
 }
 
diff --git a/runtime/interpreter/unstarted_runtime_test.cc b/runtime/interpreter/unstarted_runtime_test.cc
index ba751ec..6a4add3 100644
--- a/runtime/interpreter/unstarted_runtime_test.cc
+++ b/runtime/interpreter/unstarted_runtime_test.cc
@@ -31,7 +31,7 @@
 #include "mirror/class_loader.h"
 #include "mirror/string-inl.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread.h"
 #include "transaction.h"
 
diff --git a/runtime/java_vm_ext.cc b/runtime/java_vm_ext.cc
index 979495a..0c752ef 100644
--- a/runtime/java_vm_ext.cc
+++ b/runtime/java_vm_ext.cc
@@ -36,7 +36,7 @@
 #include "runtime-inl.h"
 #include "runtime_options.h"
 #include "ScopedLocalRef.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 #include "thread_list.h"
 
@@ -532,17 +532,17 @@
   return true;
 }
 
-jobject JavaVMExt::AddGlobalRef(Thread* self, mirror::Object* obj) {
+jobject JavaVMExt::AddGlobalRef(Thread* self, ObjPtr<mirror::Object> obj) {
   // Check for null after decoding the object to handle cleared weak globals.
   if (obj == nullptr) {
     return nullptr;
   }
   WriterMutexLock mu(self, globals_lock_);
-  IndirectRef ref = globals_.Add(IRT_FIRST_SEGMENT, obj);
+  IndirectRef ref = globals_.Add(IRT_FIRST_SEGMENT, obj.Decode());
   return reinterpret_cast<jobject>(ref);
 }
 
-jweak JavaVMExt::AddWeakGlobalRef(Thread* self, mirror::Object* obj) {
+jweak JavaVMExt::AddWeakGlobalRef(Thread* self, ObjPtr<mirror::Object> obj) {
   if (obj == nullptr) {
     return nullptr;
   }
@@ -550,7 +550,7 @@
   while (UNLIKELY(!MayAccessWeakGlobals(self))) {
     weak_globals_add_condition_.WaitHoldingLocks(self);
   }
-  IndirectRef ref = weak_globals_.Add(IRT_FIRST_SEGMENT, obj);
+  IndirectRef ref = weak_globals_.Add(IRT_FIRST_SEGMENT, obj.Decode());
   return reinterpret_cast<jweak>(ref);
 }
 
@@ -755,15 +755,15 @@
     ScopedObjectAccess soa(env);
     // As the incoming class loader is reachable/alive during the call of this function,
     // it's okay to decode it without worrying about unexpectedly marking it alive.
-    mirror::ClassLoader* loader = soa.Decode<mirror::ClassLoader*>(class_loader);
+    ObjPtr<mirror::ClassLoader> loader = soa.Decode<mirror::ClassLoader>(class_loader);
 
     ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-    if (class_linker->IsBootClassLoader(soa, loader)) {
+    if (class_linker->IsBootClassLoader(soa, loader.Decode())) {
       loader = nullptr;
       class_loader = nullptr;
     }
 
-    class_loader_allocator = class_linker->GetAllocatorForClassLoader(loader);
+    class_loader_allocator = class_linker->GetAllocatorForClassLoader(loader.Decode());
     CHECK(class_loader_allocator != nullptr);
   }
   if (library != nullptr) {
diff --git a/runtime/java_vm_ext.h b/runtime/java_vm_ext.h
index a10a72f..558ffff 100644
--- a/runtime/java_vm_ext.h
+++ b/runtime/java_vm_ext.h
@@ -22,6 +22,7 @@
 #include "base/macros.h"
 #include "base/mutex.h"
 #include "indirect_reference_table.h"
+#include "obj_ptr.h"
 #include "reference_table.h"
 
 namespace art {
@@ -123,10 +124,10 @@
   void BroadcastForNewWeakGlobals() REQUIRES_SHARED(Locks::mutator_lock_)
       REQUIRES(!weak_globals_lock_);
 
-  jobject AddGlobalRef(Thread* self, mirror::Object* obj)
+  jobject AddGlobalRef(Thread* self, ObjPtr<mirror::Object> obj)
       REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!globals_lock_);
 
-  jweak AddWeakGlobalRef(Thread* self, mirror::Object* obj)
+  jweak AddWeakGlobalRef(Thread* self, ObjPtr<mirror::Object> obj)
     REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!weak_globals_lock_);
 
   void DeleteGlobalRef(Thread* self, jobject obj) REQUIRES(!globals_lock_);
diff --git a/runtime/jdwp/jdwp_event.cc b/runtime/jdwp/jdwp_event.cc
index e2d29fe..6aebe9f9 100644
--- a/runtime/jdwp/jdwp_event.cc
+++ b/runtime/jdwp/jdwp_event.cc
@@ -30,7 +30,7 @@
 #include "jdwp/jdwp_expand_buf.h"
 #include "jdwp/jdwp_priv.h"
 #include "jdwp/object_registry.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 
 #include "handle_scope-inl.h"
diff --git a/runtime/jdwp/jdwp_handler.cc b/runtime/jdwp/jdwp_handler.cc
index f6008ac..0f2d188 100644
--- a/runtime/jdwp/jdwp_handler.cc
+++ b/runtime/jdwp/jdwp_handler.cc
@@ -31,7 +31,7 @@
 #include "jdwp/jdwp_expand_buf.h"
 #include "jdwp/jdwp_priv.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 #include "utils.h"
 
diff --git a/runtime/jdwp/jdwp_main.cc b/runtime/jdwp/jdwp_main.cc
index dbf04fe..e3bf3e5 100644
--- a/runtime/jdwp/jdwp_main.cc
+++ b/runtime/jdwp/jdwp_main.cc
@@ -25,7 +25,7 @@
 #include "base/time_utils.h"
 #include "debugger.h"
 #include "jdwp/jdwp_priv.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 
diff --git a/runtime/jdwp/object_registry.cc b/runtime/jdwp/object_registry.cc
index 5989b61..9ba62c9 100644
--- a/runtime/jdwp/object_registry.cc
+++ b/runtime/jdwp/object_registry.cc
@@ -19,7 +19,7 @@
 #include "handle_scope-inl.h"
 #include "jni_internal.h"
 #include "mirror/class.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index c9227b1..2c6b249 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -32,7 +32,7 @@
 #include "linear_alloc.h"
 #include "mem_map.h"
 #include "oat_file-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread_list.h"
 
 namespace art {
diff --git a/runtime/jit/profile_compilation_info_test.cc b/runtime/jit/profile_compilation_info_test.cc
index c8f4d94..764458a 100644
--- a/runtime/jit/profile_compilation_info_test.cc
+++ b/runtime/jit/profile_compilation_info_test.cc
@@ -26,7 +26,7 @@
 #include "mirror/class_loader.h"
 #include "handle_scope-inl.h"
 #include "jit/offline_profiling_info.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 
diff --git a/runtime/jit/profile_saver.cc b/runtime/jit/profile_saver.cc
index a4bc3fc..d23821b 100644
--- a/runtime/jit/profile_saver.cc
+++ b/runtime/jit/profile_saver.cc
@@ -26,7 +26,7 @@
 #include "base/time_utils.h"
 #include "compiler_filter.h"
 #include "oat_file_manager.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 
 namespace art {
diff --git a/runtime/jit/profiling_info.cc b/runtime/jit/profiling_info.cc
index 216df2f..6ba187e 100644
--- a/runtime/jit/profiling_info.cc
+++ b/runtime/jit/profiling_info.cc
@@ -20,7 +20,7 @@
 #include "dex_instruction.h"
 #include "jit/jit.h"
 #include "jit/jit_code_cache.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread.h"
 
 namespace art {
diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc
index a11f9ab..7b27578 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -52,7 +52,7 @@
 #include "reflection.h"
 #include "runtime.h"
 #include "safe_map.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "ScopedLocalRef.h"
 #include "thread.h"
 #include "utf.h"
@@ -108,7 +108,7 @@
                                  "%s is null at index %d", kind, idx);
 }
 
-static mirror::Class* EnsureInitialized(Thread* self, mirror::Class* klass)
+static ObjPtr<mirror::Class> EnsureInitialized(Thread* self, ObjPtr<mirror::Class> klass)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   if (LIKELY(klass->IsInitialized())) {
     return klass;
@@ -124,7 +124,7 @@
 static jmethodID FindMethodID(ScopedObjectAccess& soa, jclass jni_class,
                               const char* name, const char* sig, bool is_static)
     REQUIRES_SHARED(Locks::mutator_lock_) {
-  mirror::Class* c = EnsureInitialized(soa.Self(), soa.Decode<mirror::Class*>(jni_class));
+  ObjPtr<mirror::Class> c = EnsureInitialized(soa.Self(), soa.Decode<mirror::Class>(jni_class));
   if (c == nullptr) {
     return nullptr;
   }
@@ -143,31 +143,31 @@
     }
   }
   if (method == nullptr || method->IsStatic() != is_static) {
-    ThrowNoSuchMethodError(soa, c, name, sig, is_static ? "static" : "non-static");
+    ThrowNoSuchMethodError(soa, c.Decode(), name, sig, is_static ? "static" : "non-static");
     return nullptr;
   }
   return soa.EncodeMethod(method);
 }
 
-static mirror::ClassLoader* GetClassLoader(const ScopedObjectAccess& soa)
+static ObjPtr<mirror::ClassLoader> GetClassLoader(const ScopedObjectAccess& soa)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   ArtMethod* method = soa.Self()->GetCurrentMethod(nullptr);
   // If we are running Runtime.nativeLoad, use the overriding ClassLoader it set.
   if (method == soa.DecodeMethod(WellKnownClasses::java_lang_Runtime_nativeLoad)) {
-    return soa.Decode<mirror::ClassLoader*>(soa.Self()->GetClassLoaderOverride());
+    return soa.Decode<mirror::ClassLoader>(soa.Self()->GetClassLoaderOverride());
   }
   // If we have a method, use its ClassLoader for context.
   if (method != nullptr) {
     return method->GetDeclaringClass()->GetClassLoader();
   }
   // We don't have a method, so try to use the system ClassLoader.
-  mirror::ClassLoader* class_loader =
-      soa.Decode<mirror::ClassLoader*>(Runtime::Current()->GetSystemClassLoader());
+  ObjPtr<mirror::ClassLoader> class_loader =
+      soa.Decode<mirror::ClassLoader>(Runtime::Current()->GetSystemClassLoader());
   if (class_loader != nullptr) {
     return class_loader;
   }
   // See if the override ClassLoader is set for gtests.
-  class_loader = soa.Decode<mirror::ClassLoader*>(soa.Self()->GetClassLoaderOverride());
+  class_loader = soa.Decode<mirror::ClassLoader>(soa.Self()->GetClassLoaderOverride());
   if (class_loader != nullptr) {
     // If so, CommonCompilerTest should have marked the runtime as a compiler not compiling an
     // image.
@@ -184,7 +184,7 @@
     REQUIRES_SHARED(Locks::mutator_lock_) {
   StackHandleScope<2> hs(soa.Self());
   Handle<mirror::Class> c(
-      hs.NewHandle(EnsureInitialized(soa.Self(), soa.Decode<mirror::Class*>(jni_class))));
+      hs.NewHandle(EnsureInitialized(soa.Self(), soa.Decode<mirror::Class>(jni_class))));
   if (c.Get() == nullptr) {
     return nullptr;
   }
@@ -272,7 +272,7 @@
   if (mid == nullptr) {
     ScopedObjectAccess soa(env);
     LOG(ERROR) << "No <init>" << signature << " in "
-        << PrettyClass(soa.Decode<mirror::Class*>(exception_class));
+        << PrettyClass(soa.Decode<mirror::Class>(exception_class));
     return JNI_ERR;
   }
 
@@ -282,7 +282,7 @@
     return JNI_ERR;
   }
   ScopedObjectAccess soa(env);
-  soa.Self()->SetException(soa.Decode<mirror::Throwable*>(exception.get()));
+  soa.Self()->SetException(soa.Decode<mirror::Throwable>(exception.get()).Decode());
   return JNI_OK;
 }
 
@@ -363,12 +363,12 @@
   static jfieldID FromReflectedField(JNIEnv* env, jobject jlr_field) {
     CHECK_NON_NULL_ARGUMENT(jlr_field);
     ScopedObjectAccess soa(env);
-    mirror::Object* obj_field = soa.Decode<mirror::Object*>(jlr_field);
+    ObjPtr<mirror::Object> obj_field = soa.Decode<mirror::Object>(jlr_field);
     if (obj_field->GetClass() != mirror::Field::StaticClass()) {
       // Not even a java.lang.reflect.Field, return null. TODO, is this check necessary?
       return nullptr;
     }
-    auto* field = static_cast<mirror::Field*>(obj_field);
+    ObjPtr<mirror::Field> field = down_cast<mirror::Field*>(obj_field.Decode());
     return soa.EncodeField(field->GetArtField());
   }
 
@@ -398,14 +398,14 @@
   static jclass GetObjectClass(JNIEnv* env, jobject java_object) {
     CHECK_NON_NULL_ARGUMENT(java_object);
     ScopedObjectAccess soa(env);
-    mirror::Object* o = soa.Decode<mirror::Object*>(java_object);
+    ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(java_object);
     return soa.AddLocalReference<jclass>(o->GetClass());
   }
 
   static jclass GetSuperclass(JNIEnv* env, jclass java_class) {
     CHECK_NON_NULL_ARGUMENT(java_class);
     ScopedObjectAccess soa(env);
-    mirror::Class* c = soa.Decode<mirror::Class*>(java_class);
+    ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(java_class);
     return soa.AddLocalReference<jclass>(c->IsInterface() ? nullptr : c->GetSuperClass());
   }
 
@@ -415,9 +415,9 @@
     CHECK_NON_NULL_ARGUMENT_RETURN(java_class1, JNI_FALSE);
     CHECK_NON_NULL_ARGUMENT_RETURN(java_class2, JNI_FALSE);
     ScopedObjectAccess soa(env);
-    mirror::Class* c1 = soa.Decode<mirror::Class*>(java_class1);
-    mirror::Class* c2 = soa.Decode<mirror::Class*>(java_class2);
-    return c2->IsAssignableFrom(c1) ? JNI_TRUE : JNI_FALSE;
+    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;
   }
 
   static jboolean IsInstanceOf(JNIEnv* env, jobject jobj, jclass java_class) {
@@ -427,19 +427,19 @@
       return JNI_TRUE;
     } else {
       ScopedObjectAccess soa(env);
-      mirror::Object* obj = soa.Decode<mirror::Object*>(jobj);
-      mirror::Class* c = soa.Decode<mirror::Class*>(java_class);
+      ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(jobj);
+      ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(java_class);
       return obj->InstanceOf(c) ? JNI_TRUE : JNI_FALSE;
     }
   }
 
   static jint Throw(JNIEnv* env, jthrowable java_exception) {
     ScopedObjectAccess soa(env);
-    mirror::Throwable* exception = soa.Decode<mirror::Throwable*>(java_exception);
+    ObjPtr<mirror::Throwable> exception = soa.Decode<mirror::Throwable>(java_exception);
     if (exception == nullptr) {
       return JNI_ERR;
     }
-    soa.Self()->SetException(exception);
+    soa.Self()->SetException(exception.Decode());
     return JNI_OK;
   }
 
@@ -509,7 +509,7 @@
 
   static jobject PopLocalFrame(JNIEnv* env, jobject java_survivor) {
     ScopedObjectAccess soa(env);
-    mirror::Object* survivor = soa.Decode<mirror::Object*>(java_survivor);
+    ObjPtr<mirror::Object> survivor = soa.Decode<mirror::Object>(java_survivor);
     soa.Env()->PopFrame();
     return soa.AddLocalReference<jobject>(survivor);
   }
@@ -522,8 +522,8 @@
 
   static jobject NewGlobalRef(JNIEnv* env, jobject obj) {
     ScopedObjectAccess soa(env);
-    mirror::Object* decoded_obj = soa.Decode<mirror::Object*>(obj);
-    return soa.Vm()->AddGlobalRef(soa.Self(), decoded_obj);
+    ObjPtr<mirror::Object> decoded_obj = soa.Decode<mirror::Object>(obj);
+    return soa.Vm()->AddGlobalRef(soa.Self(), decoded_obj.Decode());
   }
 
   static void DeleteGlobalRef(JNIEnv* env, jobject obj) {
@@ -534,8 +534,8 @@
 
   static jweak NewWeakGlobalRef(JNIEnv* env, jobject obj) {
     ScopedObjectAccess soa(env);
-    mirror::Object* decoded_obj = soa.Decode<mirror::Object*>(obj);
-    return soa.Vm()->AddWeakGlobalRef(soa.Self(), decoded_obj);
+    ObjPtr<mirror::Object> decoded_obj = soa.Decode<mirror::Object>(obj);
+    return soa.Vm()->AddWeakGlobalRef(soa.Self(), decoded_obj.Decode());
   }
 
   static void DeleteWeakGlobalRef(JNIEnv* env, jweak obj) {
@@ -546,7 +546,7 @@
 
   static jobject NewLocalRef(JNIEnv* env, jobject obj) {
     ScopedObjectAccess soa(env);
-    mirror::Object* decoded_obj = soa.Decode<mirror::Object*>(obj);
+    ObjPtr<mirror::Object> decoded_obj = soa.Decode<mirror::Object>(obj);
     // Check for null after decoding the object to handle cleared weak globals.
     if (decoded_obj == nullptr) {
       return nullptr;
@@ -579,7 +579,7 @@
       return JNI_TRUE;
     } else {
       ScopedObjectAccess soa(env);
-      return (soa.Decode<mirror::Object*>(obj1) == soa.Decode<mirror::Object*>(obj2))
+      return (soa.Decode<mirror::Object>(obj1) == soa.Decode<mirror::Object>(obj2))
               ? JNI_TRUE : JNI_FALSE;
     }
   }
@@ -587,7 +587,7 @@
   static jobject AllocObject(JNIEnv* env, jclass java_class) {
     CHECK_NON_NULL_ARGUMENT(java_class);
     ScopedObjectAccess soa(env);
-    mirror::Class* c = EnsureInitialized(soa.Self(), soa.Decode<mirror::Class*>(java_class));
+    ObjPtr<mirror::Class> c = EnsureInitialized(soa.Self(), soa.Decode<mirror::Class>(java_class));
     if (c == nullptr) {
       return nullptr;
     }
@@ -613,7 +613,8 @@
     CHECK_NON_NULL_ARGUMENT(java_class);
     CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
-    mirror::Class* c = EnsureInitialized(soa.Self(), soa.Decode<mirror::Class*>(java_class));
+    ObjPtr<mirror::Class> c = EnsureInitialized(soa.Self(),
+                                                soa.Decode<mirror::Class>(java_class));
     if (c == nullptr) {
       return nullptr;
     }
@@ -639,7 +640,8 @@
     CHECK_NON_NULL_ARGUMENT(java_class);
     CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
-    mirror::Class* c = EnsureInitialized(soa.Self(), soa.Decode<mirror::Class*>(java_class));
+    ObjPtr<mirror::Class> c = EnsureInitialized(soa.Self(),
+                                                soa.Decode<mirror::Class>(java_class));
     if (c == nullptr) {
       return nullptr;
     }
@@ -1223,9 +1225,9 @@
     CHECK_NON_NULL_ARGUMENT(obj);
     CHECK_NON_NULL_ARGUMENT(fid);
     ScopedObjectAccess soa(env);
-    mirror::Object* o = soa.Decode<mirror::Object*>(obj);
+    ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(obj);
     ArtField* f = soa.DecodeField(fid);
-    return soa.AddLocalReference<jobject>(f->GetObject(o));
+    return soa.AddLocalReference<jobject>(f->GetObject(o.Decode()));
   }
 
   static jobject GetStaticObjectField(JNIEnv* env, jclass, jfieldID fid) {
@@ -1239,27 +1241,27 @@
     CHECK_NON_NULL_ARGUMENT_RETURN_VOID(java_object);
     CHECK_NON_NULL_ARGUMENT_RETURN_VOID(fid);
     ScopedObjectAccess soa(env);
-    mirror::Object* o = soa.Decode<mirror::Object*>(java_object);
-    mirror::Object* v = soa.Decode<mirror::Object*>(java_value);
+    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, v);
+    f->SetObject<false>(o.Decode(), v.Decode());
   }
 
   static void SetStaticObjectField(JNIEnv* env, jclass, jfieldID fid, jobject java_value) {
     CHECK_NON_NULL_ARGUMENT_RETURN_VOID(fid);
     ScopedObjectAccess soa(env);
-    mirror::Object* v = soa.Decode<mirror::Object*>(java_value);
+    ObjPtr<mirror::Object> v = soa.Decode<mirror::Object>(java_value);
     ArtField* f = soa.DecodeField(fid);
-    f->SetObject<false>(f->GetDeclaringClass(), v);
+    f->SetObject<false>(f->GetDeclaringClass(), v.Decode());
   }
 
 #define GET_PRIMITIVE_FIELD(fn, instance) \
   CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(instance); \
   CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(fid); \
   ScopedObjectAccess soa(env); \
-  mirror::Object* o = soa.Decode<mirror::Object*>(instance); \
+  ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(instance); \
   ArtField* f = soa.DecodeField(fid); \
-  return f->Get ##fn (o)
+  return f->Get ##fn (o.Decode())
 
 #define GET_STATIC_PRIMITIVE_FIELD(fn) \
   CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(fid); \
@@ -1271,9 +1273,9 @@
   CHECK_NON_NULL_ARGUMENT_RETURN_VOID(instance); \
   CHECK_NON_NULL_ARGUMENT_RETURN_VOID(fid); \
   ScopedObjectAccess soa(env); \
-  mirror::Object* o = soa.Decode<mirror::Object*>(instance); \
+  ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(instance); \
   ArtField* f = soa.DecodeField(fid); \
-  f->Set ##fn <false>(o, value)
+  f->Set ##fn <false>(o.Decode(), value)
 
 #define SET_STATIC_PRIMITIVE_FIELD(fn, value) \
   CHECK_NON_NULL_ARGUMENT_RETURN_VOID(fid); \
@@ -1657,20 +1659,20 @@
   static jsize GetStringLength(JNIEnv* env, jstring java_string) {
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(java_string);
     ScopedObjectAccess soa(env);
-    return soa.Decode<mirror::String*>(java_string)->GetLength();
+    return soa.Decode<mirror::String>(java_string)->GetLength();
   }
 
   static jsize GetStringUTFLength(JNIEnv* env, jstring java_string) {
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(java_string);
     ScopedObjectAccess soa(env);
-    return soa.Decode<mirror::String*>(java_string)->GetUtfLength();
+    return soa.Decode<mirror::String>(java_string)->GetUtfLength();
   }
 
   static void GetStringRegion(JNIEnv* env, jstring java_string, jsize start, jsize length,
                               jchar* buf) {
     CHECK_NON_NULL_ARGUMENT_RETURN_VOID(java_string);
     ScopedObjectAccess soa(env);
-    mirror::String* s = soa.Decode<mirror::String*>(java_string);
+    ObjPtr<mirror::String> s = soa.Decode<mirror::String>(java_string);
     if (start < 0 || length < 0 || length > s->GetLength() - start) {
       ThrowSIOOBE(soa, start, length, s->GetLength());
     } else {
@@ -1690,7 +1692,7 @@
                                  char* buf) {
     CHECK_NON_NULL_ARGUMENT_RETURN_VOID(java_string);
     ScopedObjectAccess soa(env);
-    mirror::String* s = soa.Decode<mirror::String*>(java_string);
+    ObjPtr<mirror::String> s = soa.Decode<mirror::String>(java_string);
     if (start < 0 || length < 0 || length > s->GetLength() - start) {
       ThrowSIOOBE(soa, start, length, s->GetLength());
     } else {
@@ -1710,7 +1712,7 @@
   static const jchar* GetStringChars(JNIEnv* env, jstring java_string, jboolean* is_copy) {
     CHECK_NON_NULL_ARGUMENT(java_string);
     ScopedObjectAccess soa(env);
-    mirror::String* s = soa.Decode<mirror::String*>(java_string);
+    ObjPtr<mirror::String> s = soa.Decode<mirror::String>(java_string);
     gc::Heap* heap = Runtime::Current()->GetHeap();
     if (heap->IsMovableObject(s) || s->IsCompressed()) {
       jchar* chars = new jchar[s->GetLength()];
@@ -1736,7 +1738,7 @@
   static void ReleaseStringChars(JNIEnv* env, jstring java_string, const jchar* chars) {
     CHECK_NON_NULL_ARGUMENT_RETURN_VOID(java_string);
     ScopedObjectAccess soa(env);
-    mirror::String* s = soa.Decode<mirror::String*>(java_string);
+    ObjPtr<mirror::String> s = soa.Decode<mirror::String>(java_string);
     if (s->IsCompressed() || (s->IsCompressed() == false && chars != s->GetValue())) {
       delete[] chars;
     }
@@ -1745,11 +1747,11 @@
   static const jchar* GetStringCritical(JNIEnv* env, jstring java_string, jboolean* is_copy) {
     CHECK_NON_NULL_ARGUMENT(java_string);
     ScopedObjectAccess soa(env);
-    mirror::String* s = soa.Decode<mirror::String*>(java_string);
+    ObjPtr<mirror::String> s = soa.Decode<mirror::String>(java_string);
     gc::Heap* heap = Runtime::Current()->GetHeap();
     if (heap->IsMovableObject(s)) {
       StackHandleScope<1> hs(soa.Self());
-      HandleWrapper<mirror::String> h(hs.NewHandleWrapper(&s));
+      HandleWrapperObjPtr<mirror::String> h(hs.NewHandleWrapper(&s));
       if (!kUseReadBarrier) {
         heap->IncrementDisableMovingGC(soa.Self());
       } else {
@@ -1782,7 +1784,7 @@
     CHECK_NON_NULL_ARGUMENT_RETURN_VOID(java_string);
     ScopedObjectAccess soa(env);
     gc::Heap* heap = Runtime::Current()->GetHeap();
-    mirror::String* s = soa.Decode<mirror::String*>(java_string);
+    ObjPtr<mirror::String> s = soa.Decode<mirror::String>(java_string);
     if (heap->IsMovableObject(s)) {
       if (!kUseReadBarrier) {
         heap->DecrementDisableMovingGC(soa.Self());
@@ -1803,7 +1805,7 @@
       *is_copy = JNI_TRUE;
     }
     ScopedObjectAccess soa(env);
-    mirror::String* s = soa.Decode<mirror::String*>(java_string);
+    ObjPtr<mirror::String> s = soa.Decode<mirror::String>(java_string);
     size_t byte_count = s->GetUtfLength();
     char* bytes = new char[byte_count + 1];
     CHECK(bytes != nullptr);  // bionic aborts anyway.
@@ -1826,7 +1828,7 @@
   static jsize GetArrayLength(JNIEnv* env, jarray java_array) {
     CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(java_array);
     ScopedObjectAccess soa(env);
-    mirror::Object* obj = soa.Decode<mirror::Object*>(java_array);
+    ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(java_array);
     if (UNLIKELY(!obj->IsArrayInstance())) {
       soa.Vm()->JniAbortF("GetArrayLength", "not an array: %s", PrettyTypeOf(obj).c_str());
       return 0;
@@ -1838,8 +1840,8 @@
   static jobject GetObjectArrayElement(JNIEnv* env, jobjectArray java_array, jsize index) {
     CHECK_NON_NULL_ARGUMENT(java_array);
     ScopedObjectAccess soa(env);
-    mirror::ObjectArray<mirror::Object>* array =
-        soa.Decode<mirror::ObjectArray<mirror::Object>*>(java_array);
+    ObjPtr<mirror::ObjectArray<mirror::Object>> array =
+        soa.Decode<mirror::ObjectArray<mirror::Object>>(java_array);
     return soa.AddLocalReference<jobject>(array->Get(index));
   }
 
@@ -1847,10 +1849,10 @@
                                     jobject java_value) {
     CHECK_NON_NULL_ARGUMENT_RETURN_VOID(java_array);
     ScopedObjectAccess soa(env);
-    mirror::ObjectArray<mirror::Object>* array =
-        soa.Decode<mirror::ObjectArray<mirror::Object>*>(java_array);
-    mirror::Object* value = soa.Decode<mirror::Object*>(java_value);
-    array->Set<false>(index, value);
+    ObjPtr<mirror::ObjectArray<mirror::Object>> array =
+        soa.Decode<mirror::ObjectArray<mirror::Object>>(java_array);
+    ObjPtr<mirror::Object> value = soa.Decode<mirror::Object>(java_value);
+    array->Set<false>(index, value.Decode());
   }
 
   static jbooleanArray NewBooleanArray(JNIEnv* env, jsize length) {
@@ -1893,7 +1895,7 @@
     ScopedObjectAccess soa(env);
     mirror::Class* array_class;
     {
-      mirror::Class* element_class = soa.Decode<mirror::Class*>(element_jclass);
+      mirror::Class* element_class = soa.Decode<mirror::Class>(element_jclass).Decode();
       if (UNLIKELY(element_class->IsPrimitive())) {
         soa.Vm()->JniAbortF("NewObjectArray", "not an object type: %s",
                             PrettyDescriptor(element_class).c_str());
@@ -1910,7 +1912,7 @@
     mirror::ObjectArray<mirror::Object>* result =
         mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), array_class, length);
     if (result != nullptr && initial_element != nullptr) {
-      mirror::Object* initial_object = soa.Decode<mirror::Object*>(initial_element);
+      ObjPtr<mirror::Object> initial_object = soa.Decode<mirror::Object>(initial_element);
       if (initial_object != nullptr) {
         mirror::Class* element_class = result->GetClass()->GetComponentType();
         if (UNLIKELY(!element_class->IsAssignableFrom(initial_object->GetClass()))) {
@@ -1921,7 +1923,7 @@
           return nullptr;
         } else {
           for (jsize i = 0; i < length; ++i) {
-            result->SetWithoutChecks<false>(i, initial_object);
+            result->SetWithoutChecks<false>(i, initial_object.Decode());
           }
         }
       }
@@ -1936,7 +1938,7 @@
   static void* GetPrimitiveArrayCritical(JNIEnv* env, jarray java_array, jboolean* is_copy) {
     CHECK_NON_NULL_ARGUMENT(java_array);
     ScopedObjectAccess soa(env);
-    mirror::Array* array = soa.Decode<mirror::Array*>(java_array);
+    ObjPtr<mirror::Array> array = soa.Decode<mirror::Array>(java_array);
     if (UNLIKELY(!array->GetClass()->IsPrimitiveArray())) {
       soa.Vm()->JniAbortF("GetPrimitiveArrayCritical", "expected primitive array, given %s",
                           PrettyDescriptor(array->GetClass()).c_str());
@@ -1952,7 +1954,7 @@
         heap->IncrementDisableThreadFlip(soa.Self());
       }
       // Re-decode in case the object moved since IncrementDisableGC waits for GC to complete.
-      array = soa.Decode<mirror::Array*>(java_array);
+      array = soa.Decode<mirror::Array>(java_array);
     }
     if (is_copy != nullptr) {
       *is_copy = JNI_FALSE;
@@ -1964,14 +1966,14 @@
                                             jint mode) {
     CHECK_NON_NULL_ARGUMENT_RETURN_VOID(java_array);
     ScopedObjectAccess soa(env);
-    mirror::Array* array = soa.Decode<mirror::Array*>(java_array);
+    ObjPtr<mirror::Array> array = soa.Decode<mirror::Array>(java_array);
     if (UNLIKELY(!array->GetClass()->IsPrimitiveArray())) {
       soa.Vm()->JniAbortF("ReleasePrimitiveArrayCritical", "expected primitive array, given %s",
                           PrettyDescriptor(array->GetClass()).c_str());
       return;
     }
     const size_t component_size = array->GetClass()->GetComponentSize();
-    ReleasePrimitiveArray(soa, array, component_size, elements, mode);
+    ReleasePrimitiveArray(soa, array.Decode(), component_size, elements, mode);
   }
 
   static jboolean* GetBooleanArrayElements(JNIEnv* env, jbooleanArray array, jboolean* is_copy) {
@@ -2145,7 +2147,7 @@
     }
     CHECK_NON_NULL_ARGUMENT_FN_NAME("RegisterNatives", java_class, JNI_ERR);
     ScopedObjectAccess soa(env);
-    mirror::Class* c = soa.Decode<mirror::Class*>(java_class);
+    ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(java_class);
     if (UNLIKELY(method_count == 0)) {
       LOG(WARNING) << "JNI RegisterNativeMethods: attempt to register 0 native methods for "
           << PrettyDescriptor(c);
@@ -2157,13 +2159,13 @@
       const char* sig = methods[i].signature;
       const void* fnPtr = methods[i].fnPtr;
       if (UNLIKELY(name == nullptr)) {
-        ReportInvalidJNINativeMethod(soa, c, "method name", i, return_errors);
+        ReportInvalidJNINativeMethod(soa, c.Decode(), "method name", i, return_errors);
         return JNI_ERR;
       } else if (UNLIKELY(sig == nullptr)) {
-        ReportInvalidJNINativeMethod(soa, c, "method signature", i, return_errors);
+        ReportInvalidJNINativeMethod(soa, c.Decode(), "method signature", i, return_errors);
         return JNI_ERR;
       } else if (UNLIKELY(fnPtr == nullptr)) {
-        ReportInvalidJNINativeMethod(soa, c, "native function", i, return_errors);
+        ReportInvalidJNINativeMethod(soa, c.Decode(), "native function", i, return_errors);
         return JNI_ERR;
       }
       bool is_fast = false;
@@ -2206,17 +2208,17 @@
       // the parent.
       ArtMethod* m = nullptr;
       bool warn_on_going_to_parent = down_cast<JNIEnvExt*>(env)->vm->IsCheckJniEnabled();
-      for (mirror::Class* current_class = c;
+      for (ObjPtr<mirror::Class> current_class = c;
            current_class != nullptr;
            current_class = current_class->GetSuperClass()) {
         // Search first only comparing methods which are native.
-        m = FindMethod<true>(current_class, name, sig);
+        m = FindMethod<true>(current_class.Decode(), name, sig);
         if (m != nullptr) {
           break;
         }
 
         // Search again comparing to all methods, to find non-native methods that match.
-        m = FindMethod<false>(current_class, name, sig);
+        m = FindMethod<false>(current_class.Decode(), name, sig);
         if (m != nullptr) {
           break;
         }
@@ -2238,14 +2240,14 @@
             << "Failed to register native method "
             << PrettyDescriptor(c) << "." << name << sig << " in "
             << c->GetDexCache()->GetLocation()->ToModifiedUtf8();
-        ThrowNoSuchMethodError(soa, c, name, sig, "static or non-static");
+        ThrowNoSuchMethodError(soa, c.Decode(), name, sig, "static or non-static");
         return JNI_ERR;
       } else if (!m->IsNative()) {
         LOG(return_errors ? ::android::base::ERROR : ::android::base::FATAL)
             << "Failed to register non-native method "
             << PrettyDescriptor(c) << "." << name << sig
             << " as native";
-        ThrowNoSuchMethodError(soa, c, name, sig, "native");
+        ThrowNoSuchMethodError(soa, c.Decode(), name, sig, "native");
         return JNI_ERR;
       }
 
@@ -2260,7 +2262,7 @@
   static jint UnregisterNatives(JNIEnv* env, jclass java_class) {
     CHECK_NON_NULL_ARGUMENT_RETURN(java_class, JNI_ERR);
     ScopedObjectAccess soa(env);
-    mirror::Class* c = soa.Decode<mirror::Class*>(java_class);
+    ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(java_class);
 
     VLOG(jni) << "[Unregistering JNI native methods for " << PrettyClass(c) << "]";
 
@@ -2283,24 +2285,24 @@
   static jint MonitorEnter(JNIEnv* env, jobject java_object) NO_THREAD_SAFETY_ANALYSIS {
     CHECK_NON_NULL_ARGUMENT_RETURN(java_object, JNI_ERR);
     ScopedObjectAccess soa(env);
-    mirror::Object* o = soa.Decode<mirror::Object*>(java_object);
+    ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(java_object);
     o = o->MonitorEnter(soa.Self());
     if (soa.Self()->IsExceptionPending()) {
       return JNI_ERR;
     }
-    soa.Env()->monitors.Add(o);
+    soa.Env()->monitors.Add(o.Decode());
     return JNI_OK;
   }
 
   static jint MonitorExit(JNIEnv* env, jobject java_object) NO_THREAD_SAFETY_ANALYSIS {
     CHECK_NON_NULL_ARGUMENT_RETURN(java_object, JNI_ERR);
     ScopedObjectAccess soa(env);
-    mirror::Object* o = soa.Decode<mirror::Object*>(java_object);
+    ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(java_object);
     o->MonitorExit(soa.Self());
     if (soa.Self()->IsExceptionPending()) {
       return JNI_ERR;
     }
-    soa.Env()->monitors.Remove(o);
+    soa.Env()->monitors.Remove(o.Decode());
     return JNI_OK;
   }
 
@@ -2409,7 +2411,7 @@
   static ArtArrayT* DecodeAndCheckArrayType(ScopedObjectAccess& soa, JArrayT java_array,
                                            const char* fn_name, const char* operation)
       REQUIRES_SHARED(Locks::mutator_lock_) {
-    ArtArrayT* array = soa.Decode<ArtArrayT*>(java_array);
+    ObjPtr<ArtArrayT> array = soa.Decode<ArtArrayT>(java_array);
     if (UNLIKELY(ArtArrayT::GetArrayClass() != array->GetClass())) {
       soa.Vm()->JniAbortF(fn_name,
                           "attempt to %s %s primitive array elements with an object of type %s",
@@ -2419,7 +2421,7 @@
       return nullptr;
     }
     DCHECK_EQ(sizeof(ElementT), array->GetClass()->GetComponentSize());
-    return array;
+    return array.Decode();
   }
 
   template <typename ArrayT, typename ElementT, typename ArtArrayT>
diff --git a/runtime/jni_internal_test.cc b/runtime/jni_internal_test.cc
index fe0081c..9bd6f6d 100644
--- a/runtime/jni_internal_test.cc
+++ b/runtime/jni_internal_test.cc
@@ -22,7 +22,7 @@
 #include "java_vm_ext.h"
 #include "jni_env_ext.h"
 #include "mirror/string-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "ScopedLocalRef.h"
 
 namespace art {
@@ -58,7 +58,7 @@
   void ExpectException(jclass exception_class) {
     ScopedObjectAccess soa(env_);
     EXPECT_TRUE(env_->ExceptionCheck())
-        << PrettyDescriptor(soa.Decode<mirror::Class*>(exception_class));
+        << PrettyDescriptor(soa.Decode<mirror::Class>(exception_class));
     jthrowable exception = env_->ExceptionOccurred();
     EXPECT_NE(nullptr, exception);
     env_->ExceptionClear();
@@ -619,7 +619,7 @@
         class_loader_ = LoadDex("MyClassNatives");
         StackHandleScope<1> hs(soa.Self());
         Handle<mirror::ClassLoader> loader(
-            hs.NewHandle(soa.Decode<mirror::ClassLoader*>(class_loader_)));
+            hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader_)));
         mirror::Class* c = class_linker_->FindClass(soa.Self(), "LMyClassNatives;", loader);
         const auto pointer_size = class_linker_->GetImagePointerSize();
         ArtMethod* method = direct ? c->FindDirectMethod(method_name, method_sig, pointer_size) :
@@ -1598,7 +1598,7 @@
 TEST_F(JniInternalTest, GetStringChars_ReleaseStringChars) {
   jstring s = env_->NewStringUTF("hello");
   ScopedObjectAccess soa(env_);
-  mirror::String* s_m = soa.Decode<mirror::String*>(s);
+  ObjPtr<mirror::String> s_m = soa.Decode<mirror::String>(s);
   ASSERT_TRUE(s != nullptr);
 
   jchar expected[] = { 'h', 'e', 'l', 'l', 'o' };
@@ -2236,7 +2236,7 @@
 
 static bool IsLocked(JNIEnv* env, jobject jobj) {
   ScopedObjectAccess soa(env);
-  LockWord lock_word = soa.Decode<mirror::Object*>(jobj)->GetLockWord(true);
+  LockWord lock_word = soa.Decode<mirror::Object>(jobj)->GetLockWord(true);
   switch (lock_word.GetState()) {
     case LockWord::kHashCode:
     case LockWord::kUnlocked:
diff --git a/runtime/jobject_comparator.cc b/runtime/jobject_comparator.cc
index 1f424b3..443f095 100644
--- a/runtime/jobject_comparator.cc
+++ b/runtime/jobject_comparator.cc
@@ -19,7 +19,7 @@
 #include "mirror/array-inl.h"
 #include "mirror/class-inl.h"
 #include "mirror/object-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 
@@ -32,8 +32,8 @@
   }
   ScopedObjectAccess soa(Thread::Current());
   StackHandleScope<2> hs(soa.Self());
-  Handle<mirror::Object> obj1(hs.NewHandle(soa.Decode<mirror::Object*>(jobj1)));
-  Handle<mirror::Object> obj2(hs.NewHandle(soa.Decode<mirror::Object*>(jobj2)));
+  Handle<mirror::Object> obj1(hs.NewHandle(soa.Decode<mirror::Object>(jobj1)));
+  Handle<mirror::Object> obj2(hs.NewHandle(soa.Decode<mirror::Object>(jobj2)));
   if (obj1.Get() == nullptr) {
     return true;
   } else if (obj2.Get() == nullptr) {
diff --git a/runtime/mirror/dex_cache_test.cc b/runtime/mirror/dex_cache_test.cc
index 43ba362..ac04200 100644
--- a/runtime/mirror/dex_cache_test.cc
+++ b/runtime/mirror/dex_cache_test.cc
@@ -24,7 +24,7 @@
 #include "mirror/class_loader-inl.h"
 #include "mirror/dex_cache-inl.h"
 #include "handle_scope-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 namespace mirror {
@@ -56,7 +56,7 @@
   ClassLinker* const class_linker = runtime->GetClassLinker();
   StackHandleScope<1> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
-      soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+      soa.Decode<mirror::ClassLoader>(jclass_loader)));
   mirror::Class* klass = class_linker->FindClass(soa.Self(), "LMain;", class_loader);
   ASSERT_TRUE(klass != nullptr);
   LinearAlloc* const linear_alloc = klass->GetClassLoader()->GetAllocator();
@@ -72,7 +72,7 @@
   ClassLinker* const class_linker = runtime->GetClassLinker();
   StackHandleScope<3> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
-      soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+      soa.Decode<mirror::ClassLoader>(jclass_loader)));
   Handle<mirror::Class> klass1 =
       hs.NewHandle(class_linker->FindClass(soa.Self(), "Lpackage1/Package1;", class_loader));
   ASSERT_TRUE(klass1.Get() != nullptr);
diff --git a/runtime/mirror/object_test.cc b/runtime/mirror/object_test.cc
index 0f3447e..40ee3a2 100644
--- a/runtime/mirror/object_test.cc
+++ b/runtime/mirror/object_test.cc
@@ -38,7 +38,7 @@
 #include "obj_ptr.h"
 #include "object-inl.h"
 #include "object_array-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "string-inl.h"
 
 namespace art {
@@ -365,7 +365,7 @@
   const DexFile* dex_file = GetFirstDexFile(class_loader);
 
   StackHandleScope<2> hs(soa.Self());
-  Handle<mirror::ClassLoader> loader(hs.NewHandle(soa.Decode<ClassLoader*>(class_loader)));
+  Handle<mirror::ClassLoader> loader(hs.NewHandle(soa.Decode<ClassLoader>(class_loader)));
   Class* klass = class_linker_->FindClass(soa.Self(), "LStaticsFromCode;", loader);
   ArtMethod* clinit = klass->FindClassInitializer(kRuntimePointerSize);
   const DexFile::TypeId* klass_type_id = dex_file->FindTypeId("LStaticsFromCode;");
@@ -495,8 +495,8 @@
   jobject jclass_loader_1 = LoadDex("ProtoCompare");
   jobject jclass_loader_2 = LoadDex("ProtoCompare2");
   StackHandleScope<4> hs(soa.Self());
-  Handle<ClassLoader> class_loader_1(hs.NewHandle(soa.Decode<ClassLoader*>(jclass_loader_1)));
-  Handle<ClassLoader> class_loader_2(hs.NewHandle(soa.Decode<ClassLoader*>(jclass_loader_2)));
+  Handle<ClassLoader> class_loader_1(hs.NewHandle(soa.Decode<ClassLoader>(jclass_loader_1)));
+  Handle<ClassLoader> class_loader_2(hs.NewHandle(soa.Decode<ClassLoader>(jclass_loader_2)));
 
   Class* klass1 = linker->FindClass(soa.Self(), "LProtoCompare;", class_loader_1);
   ASSERT_TRUE(klass1 != nullptr);
@@ -538,7 +538,7 @@
   ScopedObjectAccess soa(Thread::Current());
   jobject jclass_loader = LoadDex("XandY");
   StackHandleScope<3> hs(soa.Self());
-  Handle<ClassLoader> class_loader(hs.NewHandle(soa.Decode<ClassLoader*>(jclass_loader)));
+  Handle<ClassLoader> class_loader(hs.NewHandle(soa.Decode<ClassLoader>(jclass_loader)));
 
   Class* X = class_linker_->FindClass(soa.Self(), "LX;", class_loader);
   Class* Y = class_linker_->FindClass(soa.Self(), "LY;", class_loader);
@@ -575,7 +575,7 @@
   ScopedObjectAccess soa(Thread::Current());
   jobject jclass_loader = LoadDex("XandY");
   StackHandleScope<1> hs(soa.Self());
-  Handle<ClassLoader> class_loader(hs.NewHandle(soa.Decode<ClassLoader*>(jclass_loader)));
+  Handle<ClassLoader> class_loader(hs.NewHandle(soa.Decode<ClassLoader>(jclass_loader)));
   Class* X = class_linker_->FindClass(soa.Self(), "LX;", class_loader);
   Class* Y = class_linker_->FindClass(soa.Self(), "LY;", class_loader);
 
@@ -613,7 +613,7 @@
   ScopedObjectAccess soa(Thread::Current());
   jobject jclass_loader = LoadDex("XandY");
   StackHandleScope<1> hs(soa.Self());
-  Handle<ClassLoader> class_loader(hs.NewHandle(soa.Decode<ClassLoader*>(jclass_loader)));
+  Handle<ClassLoader> class_loader(hs.NewHandle(soa.Decode<ClassLoader>(jclass_loader)));
   Class* X = class_linker_->FindClass(soa.Self(), "LX;", class_loader);
   Class* Y = class_linker_->FindClass(soa.Self(), "LY;", class_loader);
   ASSERT_TRUE(X != nullptr);
@@ -752,7 +752,7 @@
   EXPECT_FALSE(null_ptr != null_ptr);
   EXPECT_FALSE(null_ptr != nullptr);
   null_ptr.AssertValid();
-  Handle<ClassLoader> class_loader(hs.NewHandle(soa.Decode<ClassLoader*>(jclass_loader)));
+  Handle<ClassLoader> class_loader(hs.NewHandle(soa.Decode<ClassLoader>(jclass_loader)));
   Handle<mirror::Class> h_X(
       hs.NewHandle(class_linker_->FindClass(soa.Self(), "LX;", class_loader)));
   ObjPtr<Class, /*kPoison*/ true> X(h_X.Get());
diff --git a/runtime/monitor.cc b/runtime/monitor.cc
index 49b83a7..3bc1b06 100644
--- a/runtime/monitor.cc
+++ b/runtime/monitor.cc
@@ -30,7 +30,7 @@
 #include "mirror/class-inl.h"
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread.h"
 #include "thread_list.h"
 #include "verifier/method_verifier.h"
diff --git a/runtime/monitor_pool_test.cc b/runtime/monitor_pool_test.cc
index e1837f5..a111c6c 100644
--- a/runtime/monitor_pool_test.cc
+++ b/runtime/monitor_pool_test.cc
@@ -17,7 +17,7 @@
 #include "monitor_pool.h"
 
 #include "common_runtime_test.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 
 namespace art {
diff --git a/runtime/monitor_test.cc b/runtime/monitor_test.cc
index ac6a4f3..4ee46dc 100644
--- a/runtime/monitor_test.cc
+++ b/runtime/monitor_test.cc
@@ -27,7 +27,7 @@
 #include "mirror/class-inl.h"
 #include "mirror/string-inl.h"  // Strings are easiest to allocate
 #include "object_lock.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread_pool.h"
 
 namespace art {
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index 384de34..0677d5b 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -34,7 +34,7 @@
 #include "oat_file_manager.h"
 #include "os.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "ScopedLocalRef.h"
 #include "ScopedUtfChars.h"
 #include "utils.h"
@@ -217,7 +217,7 @@
   bool all_deleted = true;
   {
     ScopedObjectAccess soa(env);
-    mirror::Object* dex_files_object = soa.Decode<mirror::Object*>(cookie);
+    ObjPtr<mirror::Object> dex_files_object = soa.Decode<mirror::Object>(cookie);
     mirror::LongArray* long_dex_files = dex_files_object->AsLongArray();
     // Delete dex files associated with this dalvik.system.DexFile since there should not be running
     // code using it. dex_files is a vector due to multidex.
@@ -277,7 +277,7 @@
       ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
       StackHandleScope<1> hs(soa.Self());
       Handle<mirror::ClassLoader> class_loader(
-          hs.NewHandle(soa.Decode<mirror::ClassLoader*>(javaLoader)));
+          hs.NewHandle(soa.Decode<mirror::ClassLoader>(javaLoader)));
       class_linker->RegisterDexFile(*dex_file, class_loader.Get());
       mirror::Class* result = class_linker->DefineClass(soa.Self(),
                                                         descriptor.c_str(),
@@ -287,7 +287,7 @@
                                                         *dex_class_def);
       // Add the used dex file. This only required for the DexFile.loadClass API since normal
       // class loaders already keep their dex files live.
-      class_linker->InsertDexFileInToClassLoader(soa.Decode<mirror::Object*>(dexFile),
+      class_linker->InsertDexFileInToClassLoader(soa.Decode<mirror::Object>(dexFile).Decode(),
                                                  class_loader.Get());
       if (result != nullptr) {
         VLOG(class_linker) << "DexFile_defineClassNative returning " << result
diff --git a/runtime/native/dalvik_system_InMemoryDexClassLoader_DexData.cc b/runtime/native/dalvik_system_InMemoryDexClassLoader_DexData.cc
index 94933bc..fdced21 100644
--- a/runtime/native/dalvik_system_InMemoryDexClassLoader_DexData.cc
+++ b/runtime/native/dalvik_system_InMemoryDexClassLoader_DexData.cc
@@ -24,7 +24,7 @@
 #include "mirror/class_loader.h"
 #include "mirror/object-inl.h"
 #include "oat_file.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "ScopedUtfChars.h"
 
 namespace art {
@@ -148,7 +148,7 @@
     ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
     StackHandleScope<1> handle_scope(soa.Self());
     Handle<mirror::ClassLoader> class_loader(
-        handle_scope.NewHandle(soa.Decode<mirror::ClassLoader*>(loader)));
+        handle_scope.NewHandle(soa.Decode<mirror::ClassLoader>(loader)));
     class_linker->RegisterDexFile(*dex_file, class_loader.Get());
     mirror::Class* result = class_linker->DefineClass(
         soa.Self(), class_descriptor, hash, class_loader, *dex_file, *dex_class_def);
@@ -157,7 +157,7 @@
       // InMemoryClassLoader/DexData instance now that a class has
       // been loaded.
       class_linker->InsertDexFileInToClassLoader(
-          soa.Decode<mirror::Object*>(dexData), class_loader.Get());
+          soa.Decode<mirror::Object>(dexData).Decode(), class_loader.Get());
       return soa.AddLocalReference<jclass>(result);
     }
   }
diff --git a/runtime/native/dalvik_system_VMDebug.cc b/runtime/native/dalvik_system_VMDebug.cc
index f09c067..73c4664 100644
--- a/runtime/native/dalvik_system_VMDebug.cc
+++ b/runtime/native/dalvik_system_VMDebug.cc
@@ -36,7 +36,7 @@
 #include "mirror/class.h"
 #include "ScopedLocalRef.h"
 #include "ScopedUtfChars.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
 #include "trace.h"
 #include "well_known_classes.h"
 
@@ -259,11 +259,11 @@
   ScopedObjectAccess soa(env);
   gc::Heap* const heap = Runtime::Current()->GetHeap();
   // Caller's responsibility to do GC if desired.
-  mirror::Class* c = soa.Decode<mirror::Class*>(javaClass);
+  ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(javaClass);
   if (c == nullptr) {
     return 0;
   }
-  std::vector<mirror::Class*> classes {c};
+  std::vector<mirror::Class*> classes {c.Decode()};
   uint64_t count = 0;
   heap->CountInstances(classes, countAssignable, &count);
   return count;
@@ -274,7 +274,8 @@
   ScopedObjectAccess soa(env);
   gc::Heap* const heap = Runtime::Current()->GetHeap();
   // Caller's responsibility to do GC if desired.
-  auto* decoded_classes = soa.Decode<mirror::ObjectArray<mirror::Class>*>(javaClasses);
+  ObjPtr<mirror::ObjectArray<mirror::Class>> decoded_classes =
+      soa.Decode<mirror::ObjectArray<mirror::Class>>(javaClasses);
   if (decoded_classes == nullptr) {
     return nullptr;
   }
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index d88c9d4..c7fb44ec 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -46,8 +46,8 @@
 #include "mirror/dex_cache-inl.h"
 #include "mirror/object-inl.h"
 #include "runtime.h"
-#include "scoped_fast_native_object_access.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_fast_native_object_access-inl.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread.h"
 #include "thread_list.h"
 
@@ -74,7 +74,7 @@
     ThrowNegativeArraySizeException(length);
     return nullptr;
   }
-  mirror::Class* element_class = soa.Decode<mirror::Class*>(javaElementClass);
+  mirror::Class* element_class = soa.Decode<mirror::Class>(javaElementClass).Decode();
   if (UNLIKELY(element_class == nullptr)) {
     ThrowNullPointerException("element class == null");
     return nullptr;
@@ -99,7 +99,7 @@
     ThrowNegativeArraySizeException(length);
     return nullptr;
   }
-  mirror::Class* element_class = soa.Decode<mirror::Class*>(javaElementClass);
+  mirror::Class* element_class = soa.Decode<mirror::Class>(javaElementClass).Decode();
   if (UNLIKELY(element_class == nullptr)) {
     ThrowNullPointerException("element class == null");
     return nullptr;
@@ -122,12 +122,12 @@
     return 0;
   }
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Array* array = soa.Decode<mirror::Array*>(javaArray);
+  ObjPtr<mirror::Array> array = soa.Decode<mirror::Array>(javaArray);
   if (!array->IsArrayInstance()) {
     ThrowIllegalArgumentException("not an array");
     return 0;
   }
-  if (Runtime::Current()->GetHeap()->IsMovableObject(array)) {
+  if (Runtime::Current()->GetHeap()->IsMovableObject(array.Decode())) {
     ThrowRuntimeException("Trying to get address of movable array object");
     return 0;
   }
diff --git a/runtime/native/dalvik_system_VMStack.cc b/runtime/native/dalvik_system_VMStack.cc
index 9da40b9..0dd8cdd 100644
--- a/runtime/native/dalvik_system_VMStack.cc
+++ b/runtime/native/dalvik_system_VMStack.cc
@@ -22,8 +22,8 @@
 #include "mirror/class-inl.h"
 #include "mirror/class_loader.h"
 #include "mirror/object-inl.h"
-#include "scoped_fast_native_object_access.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_fast_native_object_access-inl.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread_list.h"
 
 namespace art {
@@ -31,7 +31,7 @@
 static jobject GetThreadStack(const ScopedFastNativeObjectAccess& soa, jobject peer)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   jobject trace = nullptr;
-  if (soa.Decode<mirror::Object*>(peer) == soa.Self()->GetPeer()) {
+  if (soa.Decode<mirror::Object>(peer) == soa.Self()->GetPeer()) {
     trace = soa.Self()->CreateInternalStackTrace<false>(soa);
   } else {
     // Suspend thread to build stack trace.
diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc
index fe3cbe7..a78909b 100644
--- a/runtime/native/dalvik_system_ZygoteHooks.cc
+++ b/runtime/native/dalvik_system_ZygoteHooks.cc
@@ -24,7 +24,7 @@
 #include "jit/jit.h"
 #include "jni_internal.h"
 #include "JNIHelp.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "ScopedUtfChars.h"
 #include "thread-inl.h"
 #include "trace.h"
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
index b6260e9..49eccd8 100644
--- a/runtime/native/java_lang_Class.cc
+++ b/runtime/native/java_lang_Class.cc
@@ -35,8 +35,8 @@
 #include "mirror/string-inl.h"
 #include "obj_ptr-inl.h"
 #include "reflection.h"
-#include "scoped_thread_state_change.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_thread_state_change-inl.h"
+#include "scoped_fast_native_object_access-inl.h"
 #include "ScopedLocalRef.h"
 #include "ScopedUtfChars.h"
 #include "utf.h"
@@ -44,10 +44,10 @@
 
 namespace art {
 
-ALWAYS_INLINE static inline mirror::Class* DecodeClass(
+ALWAYS_INLINE static inline ObjPtr<mirror::Class> DecodeClass(
     const ScopedFastNativeObjectAccess& soa, jobject java_class)
     REQUIRES_SHARED(Locks::mutator_lock_) {
-  mirror::Class* c = soa.Decode<mirror::Class*>(java_class);
+  ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(java_class);
   DCHECK(c != nullptr);
   DCHECK(c->IsClass());
   // TODO: we could EnsureInitialized here, rather than on every reflective get/set or invoke .
@@ -76,16 +76,19 @@
 
   std::string descriptor(DotToDescriptor(name.c_str()));
   StackHandleScope<2> hs(soa.Self());
-  Handle<mirror::ClassLoader> class_loader(hs.NewHandle(soa.Decode<mirror::ClassLoader*>(javaLoader)));
+  Handle<mirror::ClassLoader> class_loader(
+      hs.NewHandle(soa.Decode<mirror::ClassLoader>(javaLoader)));
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   Handle<mirror::Class> c(
       hs.NewHandle(class_linker->FindClass(soa.Self(), descriptor.c_str(), class_loader)));
   if (c.Get() == nullptr) {
     ScopedLocalRef<jthrowable> cause(env, env->ExceptionOccurred());
     env->ExceptionClear();
-    jthrowable cnfe = reinterpret_cast<jthrowable>(env->NewObject(WellKnownClasses::java_lang_ClassNotFoundException,
-                                                                  WellKnownClasses::java_lang_ClassNotFoundException_init,
-                                                                  javaName, cause.get()));
+    jthrowable cnfe = reinterpret_cast<jthrowable>(
+        env->NewObject(WellKnownClasses::java_lang_ClassNotFoundException,
+                       WellKnownClasses::java_lang_ClassNotFoundException_init,
+                       javaName,
+                       cause.get()));
     if (cnfe != nullptr) {
       // Make sure allocation didn't fail with an OOME.
       env->Throw(cnfe);
@@ -101,18 +104,18 @@
 static jstring Class_getNameNative(JNIEnv* env, jobject javaThis) {
   ScopedFastNativeObjectAccess soa(env);
   StackHandleScope<1> hs(soa.Self());
-  mirror::Class* const c = DecodeClass(soa, javaThis);
+  ObjPtr<mirror::Class> c = DecodeClass(soa, javaThis);
   return soa.AddLocalReference<jstring>(mirror::Class::ComputeName(hs.NewHandle(c)));
 }
 
 static jobjectArray Class_getProxyInterfaces(JNIEnv* env, jobject javaThis) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Class* c = DecodeClass(soa, javaThis);
+  ObjPtr<mirror::Class> c = DecodeClass(soa, javaThis);
   return soa.AddLocalReference<jobjectArray>(c->GetInterfaces()->Clone(soa.Self()));
 }
 
 static mirror::ObjectArray<mirror::Field>* GetDeclaredFields(
-    Thread* self, mirror::Class* klass, bool public_only, bool force_resolve)
+    Thread* self, ObjPtr<mirror::Class> klass, bool public_only, bool force_resolve)
       REQUIRES_SHARED(Locks::mutator_lock_) {
   StackHandleScope<1> hs(self);
   IterationRange<StrideIterator<ArtField>> ifields = klass->GetIFields();
@@ -192,8 +195,8 @@
 // Performs a binary search through an array of fields, TODO: Is this fast enough if we don't use
 // the dex cache for lookups? I think CompareModifiedUtf8ToUtf16AsCodePointValues should be fairly
 // fast.
-ALWAYS_INLINE static inline ArtField* FindFieldByName(
-    Thread* self ATTRIBUTE_UNUSED, mirror::String* name, LengthPrefixedArray<ArtField>* fields)
+ALWAYS_INLINE static inline ArtField* FindFieldByName(ObjPtr<mirror::String> name,
+                                                      LengthPrefixedArray<ArtField>* fields)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   if (fields == nullptr) {
     return nullptr;
@@ -237,14 +240,15 @@
   return nullptr;
 }
 
-ALWAYS_INLINE static inline mirror::Field* GetDeclaredField(
-    Thread* self, mirror::Class* c, mirror::String* name)
+ALWAYS_INLINE static inline mirror::Field* GetDeclaredField(Thread* self,
+                                                            ObjPtr<mirror::Class> c,
+                                                            ObjPtr<mirror::String> name)
     REQUIRES_SHARED(Locks::mutator_lock_) {
-  ArtField* art_field = FindFieldByName(self, name, c->GetIFieldsPtr());
+  ArtField* art_field = FindFieldByName(name, c->GetIFieldsPtr());
   if (art_field != nullptr) {
     return mirror::Field::CreateFromArtField<kRuntimePointerSize>(self, art_field, true);
   }
-  art_field = FindFieldByName(self, name, c->GetSFieldsPtr());
+  art_field = FindFieldByName(name, c->GetSFieldsPtr());
   if (art_field != nullptr) {
     return mirror::Field::CreateFromArtField<kRuntimePointerSize>(self, art_field, true);
   }
@@ -252,7 +256,7 @@
 }
 
 static mirror::Field* GetPublicFieldRecursive(
-    Thread* self, mirror::Class* clazz, mirror::String* name)
+    Thread* self, ObjPtr<mirror::Class> clazz, ObjPtr<mirror::String> name)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   DCHECK(clazz != nullptr);
   DCHECK(name != nullptr);
@@ -302,7 +306,7 @@
 
 static jobject Class_getPublicFieldRecursive(JNIEnv* env, jobject javaThis, jstring name) {
   ScopedFastNativeObjectAccess soa(env);
-  auto* name_string = soa.Decode<mirror::String*>(name);
+  auto name_string = soa.Decode<mirror::String>(name);
   if (UNLIKELY(name_string == nullptr)) {
     ThrowNullPointerException("name == null");
     return nullptr;
@@ -313,13 +317,13 @@
 
 static jobject Class_getDeclaredField(JNIEnv* env, jobject javaThis, jstring name) {
   ScopedFastNativeObjectAccess soa(env);
-  auto* name_string = soa.Decode<mirror::String*>(name);
+  auto name_string = soa.Decode<mirror::String>(name);
   if (name_string == nullptr) {
     ThrowNullPointerException("name == null");
     return nullptr;
   }
-  auto* klass = DecodeClass(soa, javaThis);
-  mirror::Field* result = GetDeclaredField(soa.Self(), klass, name_string);
+  ObjPtr<mirror::Class> klass = DecodeClass(soa, javaThis);
+  ObjPtr<mirror::Field> result = GetDeclaredField(soa.Self(), klass, name_string);
   if (result == nullptr) {
     std::string name_str = name_string->ToModifiedUtf8();
     if (name_str == "value" && klass->IsStringClass()) {
@@ -333,7 +337,7 @@
     }
     // We may have a pending exception if we failed to resolve.
     if (!soa.Self()->IsExceptionPending()) {
-      ThrowNoSuchFieldException(DecodeClass(soa, javaThis), name_str.c_str());
+      ThrowNoSuchFieldException(DecodeClass(soa, javaThis).Decode(), name_str.c_str());
     }
     return nullptr;
   }
@@ -345,11 +349,11 @@
   ScopedFastNativeObjectAccess soa(env);
   DCHECK_EQ(Runtime::Current()->GetClassLinker()->GetImagePointerSize(), kRuntimePointerSize);
   DCHECK(!Runtime::Current()->IsActiveTransaction());
-  mirror::Constructor* result = mirror::Class::GetDeclaredConstructorInternal<kRuntimePointerSize,
-                                                                              false>(
+  ObjPtr<mirror::Constructor> result =
+      mirror::Class::GetDeclaredConstructorInternal<kRuntimePointerSize, false>(
       soa.Self(),
-      DecodeClass(soa, javaThis),
-      soa.Decode<mirror::ObjectArray<mirror::Class>*>(args));
+      DecodeClass(soa, javaThis).Decode(),
+      soa.Decode<mirror::ObjectArray<mirror::Class>>(args).Decode());
   return soa.AddLocalReference<jobject>(result);
 }
 
@@ -399,9 +403,9 @@
   DCHECK(!Runtime::Current()->IsActiveTransaction());
   mirror::Method* result = mirror::Class::GetDeclaredMethodInternal<kRuntimePointerSize, false>(
       soa.Self(),
-      DecodeClass(soa, javaThis),
-      soa.Decode<mirror::String*>(name),
-      soa.Decode<mirror::ObjectArray<mirror::Class>*>(args));
+      DecodeClass(soa, javaThis).Decode(),
+      soa.Decode<mirror::String>(name).Decode(),
+      soa.Decode<mirror::ObjectArray<mirror::Class>>(args).Decode());
   return soa.AddLocalReference<jobject>(result);
 }
 
@@ -454,7 +458,7 @@
   if (klass->IsProxyClass() || klass->GetDexCache() == nullptr) {
     return nullptr;
   }
-  Handle<mirror::Class> annotation_class(hs.NewHandle(soa.Decode<mirror::Class*>(annotationClass)));
+  Handle<mirror::Class> annotation_class(hs.NewHandle(soa.Decode<mirror::Class>(annotationClass)));
   return soa.AddLocalReference<jobject>(
       annotations::GetAnnotationForClass(klass, annotation_class));
 }
@@ -465,10 +469,12 @@
   Handle<mirror::Class> klass(hs.NewHandle(DecodeClass(soa, javaThis)));
   if (klass->IsProxyClass() || klass->GetDexCache() == nullptr) {
     // Return an empty array instead of a null pointer.
-    mirror::Class* annotation_array_class =
-        soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_annotation_Annotation__array);
+    ObjPtr<mirror::Class>  annotation_array_class =
+        soa.Decode<mirror::Class>(WellKnownClasses::java_lang_annotation_Annotation__array);
     mirror::ObjectArray<mirror::Object>* empty_array =
-        mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), annotation_array_class, 0);
+        mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(),
+                                                   annotation_array_class.Decode(),
+                                                   0);
     return soa.AddLocalReference<jobjectArray>(empty_array);
   }
   return soa.AddLocalReference<jobjectArray>(annotations::GetAnnotationsForClass(klass));
@@ -520,8 +526,8 @@
   }
   mirror::Object* method = annotations::GetEnclosingMethod(klass);
   if (method != nullptr) {
-    if (method->GetClass() ==
-        soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_reflect_Constructor)) {
+    if (soa.Decode<mirror::Class>(WellKnownClasses::java_lang_reflect_Constructor) ==
+        method->GetClass()) {
       return soa.AddLocalReference<jobject>(method);
     }
   }
@@ -537,8 +543,8 @@
   }
   mirror::Object* method = annotations::GetEnclosingMethod(klass);
   if (method != nullptr) {
-    if (method->GetClass() ==
-        soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_reflect_Method)) {
+    if (soa.Decode<mirror::Class>(WellKnownClasses::java_lang_reflect_Method) ==
+        method->GetClass()) {
       return soa.AddLocalReference<jobject>(method);
     }
   }
@@ -599,7 +605,7 @@
   if (klass->IsProxyClass() || klass->GetDexCache() == nullptr) {
     return false;
   }
-  Handle<mirror::Class> annotation_class(hs.NewHandle(soa.Decode<mirror::Class*>(annotationType)));
+  Handle<mirror::Class> annotation_class(hs.NewHandle(soa.Decode<mirror::Class>(annotationType)));
   return annotations::IsClassAnnotationPresent(klass, annotation_class);
 }
 
diff --git a/runtime/native/java_lang_DexCache.cc b/runtime/native/java_lang_DexCache.cc
index f0140a3..5efafe7 100644
--- a/runtime/native/java_lang_DexCache.cc
+++ b/runtime/native/java_lang_DexCache.cc
@@ -21,14 +21,14 @@
 #include "mirror/class-inl.h"
 #include "mirror/dex_cache-inl.h"
 #include "mirror/object-inl.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
 #include "well_known_classes.h"
 
 namespace art {
 
 static jobject DexCache_getDexNative(JNIEnv* env, jobject javaDexCache) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::DexCache* dex_cache = soa.Decode<mirror::DexCache*>(javaDexCache);
+  ObjPtr<mirror::DexCache> dex_cache = soa.Decode<mirror::DexCache>(javaDexCache);
   // Should only be called while holding the lock on the dex cache.
   DCHECK_EQ(dex_cache->GetLockOwnerThreadId(), soa.Self()->GetThreadId());
   const DexFile* dex_file = dex_cache->GetDexFile();
@@ -51,14 +51,14 @@
 
 static jobject DexCache_getResolvedType(JNIEnv* env, jobject javaDexCache, jint type_index) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::DexCache* dex_cache = soa.Decode<mirror::DexCache*>(javaDexCache);
+  ObjPtr<mirror::DexCache> dex_cache = soa.Decode<mirror::DexCache>(javaDexCache);
   CHECK_LT(static_cast<size_t>(type_index), dex_cache->NumResolvedTypes());
   return soa.AddLocalReference<jobject>(dex_cache->GetResolvedType(type_index));
 }
 
 static jobject DexCache_getResolvedString(JNIEnv* env, jobject javaDexCache, jint string_index) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::DexCache* dex_cache = soa.Decode<mirror::DexCache*>(javaDexCache);
+  ObjPtr<mirror::DexCache> dex_cache = soa.Decode<mirror::DexCache>(javaDexCache);
   CHECK_LT(static_cast<size_t>(string_index), dex_cache->GetDexFile()->NumStringIds());
   return soa.AddLocalReference<jobject>(dex_cache->GetResolvedString(string_index));
 }
@@ -66,17 +66,17 @@
 static void DexCache_setResolvedType(JNIEnv* env, jobject javaDexCache, jint type_index,
                                      jobject type) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::DexCache* dex_cache = soa.Decode<mirror::DexCache*>(javaDexCache);
+  ObjPtr<mirror::DexCache> dex_cache = soa.Decode<mirror::DexCache>(javaDexCache);
   CHECK_LT(static_cast<size_t>(type_index), dex_cache->NumResolvedTypes());
-  dex_cache->SetResolvedType(type_index, soa.Decode<mirror::Class*>(type));
+  dex_cache->SetResolvedType(type_index, soa.Decode<mirror::Class>(type).Decode());
 }
 
 static void DexCache_setResolvedString(JNIEnv* env, jobject javaDexCache, jint string_index,
                                        jobject string) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::DexCache* dex_cache = soa.Decode<mirror::DexCache*>(javaDexCache);
+  ObjPtr<mirror::DexCache> dex_cache = soa.Decode<mirror::DexCache>(javaDexCache);
   CHECK_LT(static_cast<size_t>(string_index), dex_cache->GetDexFile()->NumStringIds());
-  dex_cache->SetResolvedString(string_index, soa.Decode<mirror::String*>(string));
+  dex_cache->SetResolvedString(string_index, soa.Decode<mirror::String>(string).Decode());
 }
 
 static JNINativeMethod gMethods[] = {
diff --git a/runtime/native/java_lang_Object.cc b/runtime/native/java_lang_Object.cc
index 2a36059..6493865 100644
--- a/runtime/native/java_lang_Object.cc
+++ b/runtime/native/java_lang_Object.cc
@@ -18,39 +18,35 @@
 
 #include "jni_internal.h"
 #include "mirror/object-inl.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
 
 
 namespace art {
 
 static jobject Object_internalClone(JNIEnv* env, jobject java_this) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* o = soa.Decode<mirror::Object*>(java_this);
+  ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(java_this);
   return soa.AddLocalReference<jobject>(o->Clone(soa.Self()));
 }
 
 static void Object_notify(JNIEnv* env, jobject java_this) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* o = soa.Decode<mirror::Object*>(java_this);
-  o->Notify(soa.Self());
+  soa.Decode<mirror::Object>(java_this)->Notify(soa.Self());
 }
 
 static void Object_notifyAll(JNIEnv* env, jobject java_this) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* o = soa.Decode<mirror::Object*>(java_this);
-  o->NotifyAll(soa.Self());
+  soa.Decode<mirror::Object>(java_this)->NotifyAll(soa.Self());
 }
 
 static void Object_wait(JNIEnv* env, jobject java_this) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* o = soa.Decode<mirror::Object*>(java_this);
-  o->Wait(soa.Self());
+  soa.Decode<mirror::Object>(java_this)->Wait(soa.Self());
 }
 
 static void Object_waitJI(JNIEnv* env, jobject java_this, jlong ms, jint ns) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* o = soa.Decode<mirror::Object*>(java_this);
-  o->Wait(soa.Self(), ms, ns);
+  soa.Decode<mirror::Object>(java_this)->Wait(soa.Self(), ms, ns);
 }
 
 static JNINativeMethod gMethods[] = {
diff --git a/runtime/native/java_lang_String.cc b/runtime/native/java_lang_String.cc
index aa64b79..b3a967d 100644
--- a/runtime/native/java_lang_String.cc
+++ b/runtime/native/java_lang_String.cc
@@ -22,8 +22,8 @@
 #include "mirror/object-inl.h"
 #include "mirror/string.h"
 #include "mirror/string-inl.h"
-#include "scoped_fast_native_object_access.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_fast_native_object_access-inl.h"
+#include "scoped_thread_state_change-inl.h"
 #include "ScopedLocalRef.h"
 #include "verify_object-inl.h"
 
@@ -31,7 +31,7 @@
 
 static jchar String_charAt(JNIEnv* env, jobject java_this, jint index) {
   ScopedFastNativeObjectAccess soa(env);
-  return soa.Decode<mirror::String*>(java_this)->CharAt(index);
+  return soa.Decode<mirror::String>(java_this)->CharAt(index);
 }
 
 static jint String_compareTo(JNIEnv* env, jobject java_this, jobject java_rhs) {
@@ -40,7 +40,8 @@
     ThrowNullPointerException("rhs == null");
     return -1;
   } else {
-    return soa.Decode<mirror::String*>(java_this)->CompareTo(soa.Decode<mirror::String*>(java_rhs));
+    return soa.Decode<mirror::String>(java_this)->CompareTo(
+        soa.Decode<mirror::String>(java_rhs).Decode());
   }
 }
 
@@ -51,8 +52,8 @@
     return nullptr;
   }
   StackHandleScope<2> hs(soa.Self());
-  Handle<mirror::String> string_this(hs.NewHandle(soa.Decode<mirror::String*>(java_this)));
-  Handle<mirror::String> string_arg(hs.NewHandle(soa.Decode<mirror::String*>(java_string_arg)));
+  Handle<mirror::String> string_this(hs.NewHandle(soa.Decode<mirror::String>(java_this)));
+  Handle<mirror::String> string_arg(hs.NewHandle(soa.Decode<mirror::String>(java_string_arg)));
   int32_t length_this = string_this->GetLength();
   int32_t length_arg = string_arg->GetLength();
   if (length_arg > 0 && length_this > 0) {
@@ -67,13 +68,13 @@
   ScopedFastNativeObjectAccess soa(env);
   // This method does not handle supplementary characters. They're dealt with in managed code.
   DCHECK_LE(ch, 0xffff);
-  return soa.Decode<mirror::String*>(java_this)->FastIndexOf(ch, start);
+  return soa.Decode<mirror::String>(java_this)->FastIndexOf(ch, start);
 }
 
 static jstring String_fastSubstring(JNIEnv* env, jobject java_this, jint start, jint length) {
   ScopedFastNativeObjectAccess soa(env);
   StackHandleScope<1> hs(soa.Self());
-  Handle<mirror::String> string_this(hs.NewHandle(soa.Decode<mirror::String*>(java_this)));
+  Handle<mirror::String> string_this(hs.NewHandle(soa.Decode<mirror::String>(java_this)));
   gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
   mirror::String* result = mirror::String::AllocFromString<true>(soa.Self(), length, string_this,
                                                                  start, allocator_type);
@@ -84,25 +85,24 @@
                                    jcharArray buffer, jint index) {
   ScopedFastNativeObjectAccess soa(env);
   StackHandleScope<1> hs(soa.Self());
-  Handle<mirror::CharArray> char_array(hs.NewHandle(soa.Decode<mirror::CharArray*>(buffer)));
-  soa.Decode<mirror::String*>(java_this)->GetChars(start, end, char_array, index);
+  Handle<mirror::CharArray> char_array(hs.NewHandle(soa.Decode<mirror::CharArray>(buffer)));
+  soa.Decode<mirror::String>(java_this)->GetChars(start, end, char_array, index);
 }
 
 static jstring String_intern(JNIEnv* env, jobject java_this) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::String* s = soa.Decode<mirror::String*>(java_this);
-  mirror::String* result = s->Intern();
+  ObjPtr<mirror::String> result = soa.Decode<mirror::String>(java_this)->Intern();
   return soa.AddLocalReference<jstring>(result);
 }
 
 static void String_setCharAt(JNIEnv* env, jobject java_this, jint index, jchar c) {
   ScopedFastNativeObjectAccess soa(env);
-  soa.Decode<mirror::String*>(java_this)->SetCharAt(index, c);
+  soa.Decode<mirror::String>(java_this)->SetCharAt(index, c);
 }
 
 static jcharArray String_toCharArray(JNIEnv* env, jobject java_this) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::String* s = soa.Decode<mirror::String*>(java_this);
+  ObjPtr<mirror::String> s = soa.Decode<mirror::String>(java_this);
   return soa.AddLocalReference<jcharArray>(s->ToCharArray(soa.Self()));
 }
 
diff --git a/runtime/native/java_lang_StringFactory.cc b/runtime/native/java_lang_StringFactory.cc
index 5a219ef..119f2b8 100644
--- a/runtime/native/java_lang_StringFactory.cc
+++ b/runtime/native/java_lang_StringFactory.cc
@@ -20,8 +20,8 @@
 #include "jni_internal.h"
 #include "mirror/object-inl.h"
 #include "mirror/string.h"
-#include "scoped_fast_native_object_access.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_fast_native_object_access-inl.h"
+#include "scoped_thread_state_change-inl.h"
 #include "ScopedLocalRef.h"
 #include "ScopedPrimitiveArray.h"
 
@@ -35,7 +35,7 @@
     return nullptr;
   }
   StackHandleScope<1> hs(soa.Self());
-  Handle<mirror::ByteArray> byte_array(hs.NewHandle(soa.Decode<mirror::ByteArray*>(java_data)));
+  Handle<mirror::ByteArray> byte_array(hs.NewHandle(soa.Decode<mirror::ByteArray>(java_data)));
   int32_t data_size = byte_array->GetLength();
   if ((offset | byte_count) < 0 || byte_count > data_size - offset) {
     soa.Self()->ThrowNewExceptionF("Ljava/lang/StringIndexOutOfBoundsException;",
@@ -56,7 +56,7 @@
   DCHECK(java_data != nullptr);
   ScopedFastNativeObjectAccess soa(env);
   StackHandleScope<1> hs(soa.Self());
-  Handle<mirror::CharArray> char_array(hs.NewHandle(soa.Decode<mirror::CharArray*>(java_data)));
+  Handle<mirror::CharArray> char_array(hs.NewHandle(soa.Decode<mirror::CharArray>(java_data)));
   gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
   mirror::String* result = mirror::String::AllocFromCharArray<true>(soa.Self(), char_count,
                                                                     char_array, offset,
@@ -71,7 +71,7 @@
     return nullptr;
   }
   StackHandleScope<1> hs(soa.Self());
-  Handle<mirror::String> string(hs.NewHandle(soa.Decode<mirror::String*>(to_copy)));
+  Handle<mirror::String> string(hs.NewHandle(soa.Decode<mirror::String>(to_copy)));
   gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
   mirror::String* result = mirror::String::AllocFromString<true>(soa.Self(), string->GetLength(),
                                                                  string, 0, allocator_type);
diff --git a/runtime/native/java_lang_System.cc b/runtime/native/java_lang_System.cc
index 1b399aa..8b9d0c7 100644
--- a/runtime/native/java_lang_System.cc
+++ b/runtime/native/java_lang_System.cc
@@ -24,7 +24,7 @@
 #include "mirror/class-inl.h"
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
 
 namespace art {
 
@@ -60,14 +60,14 @@
   }
 
   // Make sure source and destination are both arrays.
-  mirror::Object* srcObject = soa.Decode<mirror::Object*>(javaSrc);
+  ObjPtr<mirror::Object> srcObject = soa.Decode<mirror::Object>(javaSrc);
   if (UNLIKELY(!srcObject->IsArrayInstance())) {
-    ThrowArrayStoreException_NotAnArray("source", srcObject);
+    ThrowArrayStoreException_NotAnArray("source", srcObject.Decode());
     return;
   }
-  mirror::Object* dstObject = soa.Decode<mirror::Object*>(javaDst);
+  ObjPtr<mirror::Object> dstObject = soa.Decode<mirror::Object>(javaDst);
   if (UNLIKELY(!dstObject->IsArrayInstance())) {
-    ThrowArrayStoreException_NotAnArray("destination", dstObject);
+    ThrowArrayStoreException_NotAnArray("destination", dstObject.Decode());
     return;
   }
   mirror::Array* srcArray = srcObject->AsArray();
@@ -164,8 +164,8 @@
 inline void System_arraycopyTUnchecked(JNIEnv* env, jobject javaSrc, jint srcPos,
                                        jobject javaDst, jint dstPos, jint count) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* srcObject = soa.Decode<mirror::Object*>(javaSrc);
-  mirror::Object* dstObject = soa.Decode<mirror::Object*>(javaDst);
+  ObjPtr<mirror::Object> srcObject = soa.Decode<mirror::Object>(javaSrc);
+  ObjPtr<mirror::Object> dstObject = soa.Decode<mirror::Object>(javaDst);
   DCHECK(dstObject != nullptr);
   mirror::Array* srcArray = srcObject->AsArray();
   mirror::Array* dstArray = dstObject->AsArray();
@@ -228,7 +228,7 @@
     return 0;
   }
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* o = soa.Decode<mirror::Object*>(javaObject);
+  ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(javaObject);
   return static_cast<jint>(o->IdentityHashCode());
 }
 
diff --git a/runtime/native/java_lang_Thread.cc b/runtime/native/java_lang_Thread.cc
index a742e81..0635261 100644
--- a/runtime/native/java_lang_Thread.cc
+++ b/runtime/native/java_lang_Thread.cc
@@ -20,8 +20,8 @@
 #include "jni_internal.h"
 #include "monitor.h"
 #include "mirror/object.h"
-#include "scoped_fast_native_object_access.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_fast_native_object_access-inl.h"
+#include "scoped_thread_state_change-inl.h"
 #include "ScopedUtfChars.h"
 #include "thread.h"
 #include "thread_list.h"
@@ -109,14 +109,14 @@
 
 static jboolean Thread_nativeHoldsLock(JNIEnv* env, jobject java_thread, jobject java_object) {
   ScopedObjectAccess soa(env);
-  mirror::Object* object = soa.Decode<mirror::Object*>(java_object);
+  ObjPtr<mirror::Object> object = soa.Decode<mirror::Object>(java_object);
   if (object == nullptr) {
     ThrowNullPointerException("object == null");
     return JNI_FALSE;
   }
   MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
   Thread* thread = Thread::FromManagedThread(soa, java_thread);
-  return thread->HoldsLock(object);
+  return thread->HoldsLock(object.Decode());
 }
 
 static void Thread_nativeInterrupt(JNIEnv* env, jobject java_thread) {
@@ -132,7 +132,7 @@
   ScopedUtfChars name(env, java_name);
   {
     ScopedObjectAccess soa(env);
-    if (soa.Decode<mirror::Object*>(peer) == soa.Self()->GetPeer()) {
+    if (soa.Decode<mirror::Object>(peer) == soa.Self()->GetPeer()) {
       soa.Self()->SetThreadName(name.c_str());
       return;
     }
@@ -172,8 +172,8 @@
 
 static void Thread_sleep(JNIEnv* env, jclass, jobject java_lock, jlong ms, jint ns) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* lock = soa.Decode<mirror::Object*>(java_lock);
-  Monitor::Wait(Thread::Current(), lock, ms, ns, true, kSleeping);
+  ObjPtr<mirror::Object> lock = soa.Decode<mirror::Object>(java_lock);
+  Monitor::Wait(Thread::Current(), lock.Decode(), ms, ns, true, kSleeping);
 }
 
 /*
diff --git a/runtime/native/java_lang_Throwable.cc b/runtime/native/java_lang_Throwable.cc
index cb8a869..ff3e044 100644
--- a/runtime/native/java_lang_Throwable.cc
+++ b/runtime/native/java_lang_Throwable.cc
@@ -17,7 +17,7 @@
 #include "java_lang_Throwable.h"
 
 #include "jni_internal.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
 #include "thread.h"
 
 namespace art {
diff --git a/runtime/native/java_lang_VMClassLoader.cc b/runtime/native/java_lang_VMClassLoader.cc
index 6f735aa..0694c4d 100644
--- a/runtime/native/java_lang_VMClassLoader.cc
+++ b/runtime/native/java_lang_VMClassLoader.cc
@@ -20,7 +20,7 @@
 #include "jni_internal.h"
 #include "mirror/class_loader.h"
 #include "mirror/object-inl.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
 #include "ScopedUtfChars.h"
 #include "zip_archive.h"
 
@@ -29,7 +29,7 @@
 static jclass VMClassLoader_findLoadedClass(JNIEnv* env, jclass, jobject javaLoader,
                                             jstring javaName) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::ClassLoader* loader = soa.Decode<mirror::ClassLoader*>(javaLoader);
+  ObjPtr<mirror::ClassLoader> loader = soa.Decode<mirror::ClassLoader>(javaLoader);
   ScopedUtfChars name(env, javaName);
   if (name.c_str() == nullptr) {
     return nullptr;
@@ -37,7 +37,10 @@
   ClassLinker* cl = Runtime::Current()->GetClassLinker();
   std::string descriptor(DotToDescriptor(name.c_str()));
   const size_t descriptor_hash = ComputeModifiedUtf8Hash(descriptor.c_str());
-  mirror::Class* c = cl->LookupClass(soa.Self(), descriptor.c_str(), descriptor_hash, loader);
+  mirror::Class* c = cl->LookupClass(soa.Self(),
+                                     descriptor.c_str(),
+                                     descriptor_hash,
+                                     loader.Decode());
   if (c != nullptr && c->IsResolved()) {
     return soa.AddLocalReference<jclass>(c);
   }
diff --git a/runtime/native/java_lang_ref_FinalizerReference.cc b/runtime/native/java_lang_ref_FinalizerReference.cc
index 0532c35..08bcc38 100644
--- a/runtime/native/java_lang_ref_FinalizerReference.cc
+++ b/runtime/native/java_lang_ref_FinalizerReference.cc
@@ -21,14 +21,15 @@
 #include "jni_internal.h"
 #include "mirror/object-inl.h"
 #include "mirror/reference-inl.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
 
 namespace art {
 
 static jboolean FinalizerReference_makeCircularListIfUnenqueued(JNIEnv* env, jobject javaThis) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::FinalizerReference* const ref = soa.Decode<mirror::FinalizerReference*>(javaThis);
-  return Runtime::Current()->GetHeap()->GetReferenceProcessor()->MakeCircularListIfUnenqueued(ref);
+  ObjPtr<mirror::FinalizerReference> ref = soa.Decode<mirror::FinalizerReference>(javaThis);
+  return Runtime::Current()->GetHeap()->GetReferenceProcessor()->MakeCircularListIfUnenqueued(
+      ref.Decode());
 }
 
 static JNINativeMethod gMethods[] = {
diff --git a/runtime/native/java_lang_ref_Reference.cc b/runtime/native/java_lang_ref_Reference.cc
index d232059..9a088ed 100644
--- a/runtime/native/java_lang_ref_Reference.cc
+++ b/runtime/native/java_lang_ref_Reference.cc
@@ -21,15 +21,15 @@
 #include "jni_internal.h"
 #include "mirror/object-inl.h"
 #include "mirror/reference-inl.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
 
 namespace art {
 
 static jobject Reference_getReferent(JNIEnv* env, jobject javaThis) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Reference* const ref = soa.Decode<mirror::Reference*>(javaThis);
+  ObjPtr<mirror::Reference> ref = soa.Decode<mirror::Reference>(javaThis);
   mirror::Object* const referent =
-      Runtime::Current()->GetHeap()->GetReferenceProcessor()->GetReferent(soa.Self(), ref);
+      Runtime::Current()->GetHeap()->GetReferenceProcessor()->GetReferent(soa.Self(), ref.Decode());
   return soa.AddLocalReference<jobject>(referent);
 }
 
diff --git a/runtime/native/java_lang_reflect_Array.cc b/runtime/native/java_lang_reflect_Array.cc
index beb953b..3718ce8 100644
--- a/runtime/native/java_lang_reflect_Array.cc
+++ b/runtime/native/java_lang_reflect_Array.cc
@@ -22,7 +22,7 @@
 #include "jni_internal.h"
 #include "mirror/class-inl.h"
 #include "mirror/object-inl.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
 #include "handle_scope-inl.h"
 
 namespace art {
@@ -32,15 +32,15 @@
   ScopedFastNativeObjectAccess soa(env);
   DCHECK(javaElementClass != nullptr);
   StackHandleScope<2> hs(soa.Self());
-  Handle<mirror::Class> element_class(hs.NewHandle(soa.Decode<mirror::Class*>(javaElementClass)));
+  Handle<mirror::Class> element_class(hs.NewHandle(soa.Decode<mirror::Class>(javaElementClass)));
   DCHECK(element_class->IsClass());
   DCHECK(javaDimArray != nullptr);
-  mirror::Object* dimensions_obj = soa.Decode<mirror::Object*>(javaDimArray);
+  ObjPtr<mirror::Object> dimensions_obj = soa.Decode<mirror::Object>(javaDimArray);
   DCHECK(dimensions_obj->IsArrayInstance());
   DCHECK_EQ(dimensions_obj->GetClass()->GetComponentType()->GetPrimitiveType(),
             Primitive::kPrimInt);
   Handle<mirror::IntArray> dimensions_array(
-      hs.NewHandle(down_cast<mirror::IntArray*>(dimensions_obj)));
+      hs.NewHandle(down_cast<mirror::IntArray*>(dimensions_obj.Decode())));
   mirror::Array* new_array = mirror::Array::CreateMultiArray(soa.Self(), element_class,
                                                              dimensions_array);
   return soa.AddLocalReference<jobject>(new_array);
@@ -53,7 +53,7 @@
     ThrowNegativeArraySizeException(length);
     return nullptr;
   }
-  mirror::Class* element_class = soa.Decode<mirror::Class*>(javaElementClass);
+  mirror::Class* element_class = soa.Decode<mirror::Class>(javaElementClass).Decode();
   Runtime* runtime = Runtime::Current();
   ClassLinker* class_linker = runtime->GetClassLinker();
   mirror::Class* array_class = class_linker->FindArrayClass(soa.Self(), &element_class);
diff --git a/runtime/native/java_lang_reflect_Constructor.cc b/runtime/native/java_lang_reflect_Constructor.cc
index 47c49d5..7de0147 100644
--- a/runtime/native/java_lang_reflect_Constructor.cc
+++ b/runtime/native/java_lang_reflect_Constructor.cc
@@ -26,7 +26,7 @@
 #include "mirror/method.h"
 #include "mirror/object-inl.h"
 #include "reflection.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
 #include "well_known_classes.h"
 
 namespace art {
@@ -60,7 +60,7 @@
  */
 static jobject Constructor_newInstance0(JNIEnv* env, jobject javaMethod, jobjectArray javaArgs) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Constructor* m = soa.Decode<mirror::Constructor*>(javaMethod);
+  ObjPtr<mirror::Constructor> m = soa.Decode<mirror::Constructor>(javaMethod);
   StackHandleScope<1> hs(soa.Self());
   Handle<mirror::Class> c(hs.NewHandle(m->GetDeclaringClass()));
   if (UNLIKELY(c->IsAbstract())) {
diff --git a/runtime/native/java_lang_reflect_Executable.cc b/runtime/native/java_lang_reflect_Executable.cc
index f345c09..c7c8008 100644
--- a/runtime/native/java_lang_reflect_Executable.cc
+++ b/runtime/native/java_lang_reflect_Executable.cc
@@ -25,7 +25,7 @@
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
 #include "reflection.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
 #include "well_known_classes.h"
 
 namespace art {
@@ -35,10 +35,10 @@
   ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod);
   if (method->GetDeclaringClass()->IsProxyClass()) {
     // Return an empty array instead of a null pointer.
-    mirror::Class* annotation_array_class =
-        soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_annotation_Annotation__array);
-    mirror::ObjectArray<mirror::Object>* empty_array =
-        mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), annotation_array_class, 0);
+    ObjPtr<mirror::Class> annotation_array_class =
+        soa.Decode<mirror::Class>(WellKnownClasses::java_lang_annotation_Annotation__array);
+    ObjPtr<mirror::ObjectArray<mirror::Object>> empty_array =
+        mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), annotation_array_class.Decode(), 0);
     return soa.AddLocalReference<jobjectArray>(empty_array);
   }
   return soa.AddLocalReference<jobjectArray>(annotations::GetAnnotationsForMethod(method));
@@ -53,7 +53,7 @@
   if (method->IsProxyMethod()) {
     return nullptr;
   } else {
-    Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class*>(annotationType)));
+    Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class>(annotationType)));
     return soa.AddLocalReference<jobject>(annotations::GetAnnotationForMethod(method, klass));
   }
 }
@@ -84,7 +84,7 @@
   Thread* self = soa.Self();
   StackHandleScope<8> hs(self);
 
-  Handle<mirror::Method> executable = hs.NewHandle(soa.Decode<mirror::Method*>(javaMethod));
+  Handle<mirror::Method> executable = hs.NewHandle(soa.Decode<mirror::Method>(javaMethod));
   ArtMethod* art_method = executable.Get()->GetArtMethod();
   if (art_method->GetDeclaringClass()->IsProxyClass()) {
     return nullptr;
@@ -122,7 +122,7 @@
   // Instantiate a Parameter[] to hold the result.
   Handle<mirror::Class> parameter_array_class =
       hs.NewHandle(
-          soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_reflect_Parameter__array));
+          soa.Decode<mirror::Class>(WellKnownClasses::java_lang_reflect_Parameter__array));
   Handle<mirror::ObjectArray<mirror::Object>> parameter_array =
       hs.NewHandle(
           mirror::ObjectArray<mirror::Object>::Alloc(self,
@@ -134,7 +134,7 @@
   }
 
   Handle<mirror::Class> parameter_class =
-      hs.NewHandle(soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_reflect_Parameter));
+      hs.NewHandle(soa.Decode<mirror::Class>(WellKnownClasses::java_lang_reflect_Parameter));
   ArtMethod* parameter_init =
       soa.DecodeMethod(WellKnownClasses::java_lang_reflect_Parameter_init);
 
@@ -186,7 +186,7 @@
     return false;
   }
   StackHandleScope<1> hs(soa.Self());
-  Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class*>(annotationType)));
+  Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class>(annotationType)));
   return annotations::IsMethodAnnotationPresent(method, klass);
 }
 
diff --git a/runtime/native/java_lang_reflect_Field.cc b/runtime/native/java_lang_reflect_Field.cc
index dab510d..2519225 100644
--- a/runtime/native/java_lang_reflect_Field.cc
+++ b/runtime/native/java_lang_reflect_Field.cc
@@ -25,7 +25,7 @@
 #include "mirror/class-inl.h"
 #include "mirror/field.h"
 #include "reflection-inl.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
 #include "utils.h"
 
 namespace art {
@@ -127,7 +127,7 @@
     *class_or_rcvr = declaringClass;
     return true;
   }
-  *class_or_rcvr = soa.Decode<mirror::Object*>(j_rcvr);
+  *class_or_rcvr = soa.Decode<mirror::Object>(j_rcvr).Decode();
   if (!VerifyObjectIsClass(MakeObjPtr(*class_or_rcvr), MakeObjPtr(declaringClass))) {
     DCHECK(soa.Self()->IsExceptionPending());
     return false;
@@ -137,7 +137,7 @@
 
 static jobject Field_get(JNIEnv* env, jobject javaField, jobject javaObj) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Field* f = soa.Decode<mirror::Field*>(javaField);
+  mirror::Field* f = soa.Decode<mirror::Field>(javaField).Decode();
   mirror::Object* o = nullptr;
   if (!CheckReceiver(soa, javaObj, &f, &o)) {
     DCHECK(soa.Self()->IsExceptionPending());
@@ -163,7 +163,7 @@
 ALWAYS_INLINE inline static JValue GetPrimitiveField(JNIEnv* env, jobject javaField,
                                                      jobject javaObj) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Field* f = soa.Decode<mirror::Field*>(javaField);
+  mirror::Field* f = soa.Decode<mirror::Field>(javaField).Decode();
   mirror::Object* o = nullptr;
   if (!CheckReceiver(soa, javaObj, &f, &o)) {
     DCHECK(soa.Self()->IsExceptionPending());
@@ -307,7 +307,7 @@
 
 static void Field_set(JNIEnv* env, jobject javaField, jobject javaObj, jobject javaValue) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Field* f = soa.Decode<mirror::Field*>(javaField);
+  mirror::Field* f = soa.Decode<mirror::Field>(javaField).Decode();
   // Check that the receiver is non-null and an instance of the field's declaring class.
   mirror::Object* o = nullptr;
   if (!CheckReceiver(soa, javaObj, &f, &o)) {
@@ -325,9 +325,9 @@
   }
   // We now don't expect suspension unless an exception is thrown.
   // Unbox the value, if necessary.
-  mirror::Object* boxed_value = soa.Decode<mirror::Object*>(javaValue);
+  ObjPtr<mirror::Object> boxed_value = soa.Decode<mirror::Object>(javaValue);
   JValue unboxed_value;
-  if (!UnboxPrimitiveForField(MakeObjPtr(boxed_value),
+  if (!UnboxPrimitiveForField(boxed_value,
                               MakeObjPtr(field_type),
                               f->GetArtField(),
                               &unboxed_value)) {
@@ -346,7 +346,7 @@
 static void SetPrimitiveField(JNIEnv* env, jobject javaField, jobject javaObj,
                               const JValue& new_value) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Field* f = soa.Decode<mirror::Field*>(javaField);
+  mirror::Field* f = soa.Decode<mirror::Field>(javaField).Decode();
   mirror::Object* o = nullptr;
   if (!CheckReceiver(soa, javaObj, &f, &o)) {
     return;
@@ -426,21 +426,22 @@
 static jobject Field_getAnnotationNative(JNIEnv* env, jobject javaField, jclass annotationType) {
   ScopedFastNativeObjectAccess soa(env);
   StackHandleScope<1> hs(soa.Self());
-  ArtField* field = soa.Decode<mirror::Field*>(javaField)->GetArtField();
+  ArtField* field = soa.Decode<mirror::Field>(javaField)->GetArtField();
   if (field->GetDeclaringClass()->IsProxyClass()) {
     return nullptr;
   }
-  Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class*>(annotationType)));
+  Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class>(annotationType)));
   return soa.AddLocalReference<jobject>(annotations::GetAnnotationForField(field, klass));
 }
 
 static jobjectArray Field_getDeclaredAnnotations(JNIEnv* env, jobject javaField) {
   ScopedFastNativeObjectAccess soa(env);
-  ArtField* field = soa.Decode<mirror::Field*>(javaField)->GetArtField();
+  ArtField* field = soa.Decode<mirror::Field>(javaField)->GetArtField();
   if (field->GetDeclaringClass()->IsProxyClass()) {
     // Return an empty array instead of a null pointer.
     mirror::Class* annotation_array_class =
-        soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_annotation_Annotation__array);
+        soa.Decode<mirror::Class>(
+            WellKnownClasses::java_lang_annotation_Annotation__array).Decode();
     mirror::ObjectArray<mirror::Object>* empty_array =
         mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), annotation_array_class, 0);
     return soa.AddLocalReference<jobjectArray>(empty_array);
@@ -450,7 +451,7 @@
 
 static jobjectArray Field_getSignatureAnnotation(JNIEnv* env, jobject javaField) {
   ScopedFastNativeObjectAccess soa(env);
-  ArtField* field = soa.Decode<mirror::Field*>(javaField)->GetArtField();
+  ArtField* field = soa.Decode<mirror::Field>(javaField)->GetArtField();
   if (field->GetDeclaringClass()->IsProxyClass()) {
     return nullptr;
   }
@@ -461,11 +462,11 @@
                                                 jclass annotationType) {
   ScopedFastNativeObjectAccess soa(env);
   StackHandleScope<1> hs(soa.Self());
-  ArtField* field = soa.Decode<mirror::Field*>(javaField)->GetArtField();
+  ArtField* field = soa.Decode<mirror::Field>(javaField)->GetArtField();
   if (field->GetDeclaringClass()->IsProxyClass()) {
     return false;
   }
-  Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class*>(annotationType)));
+  Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class>(annotationType)));
   return annotations::IsFieldAnnotationPresent(field, klass);
 }
 
diff --git a/runtime/native/java_lang_reflect_Method.cc b/runtime/native/java_lang_reflect_Method.cc
index b8efb14..b5f2f7c 100644
--- a/runtime/native/java_lang_reflect_Method.cc
+++ b/runtime/native/java_lang_reflect_Method.cc
@@ -26,7 +26,7 @@
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
 #include "reflection.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
 #include "well_known_classes.h"
 
 namespace art {
diff --git a/runtime/native/java_lang_reflect_Parameter.cc b/runtime/native/java_lang_reflect_Parameter.cc
index c2a803c..6060b8a 100644
--- a/runtime/native/java_lang_reflect_Parameter.cc
+++ b/runtime/native/java_lang_reflect_Parameter.cc
@@ -21,7 +21,7 @@
 #include "dex_file-inl.h"
 #include "dex_file_annotations.h"
 #include "jni_internal.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
 #include "utils.h"
 
 namespace art {
@@ -53,7 +53,7 @@
   }
 
   StackHandleScope<1> hs(soa.Self());
-  Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class*>(annotationType)));
+  Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class>(annotationType)));
   return soa.AddLocalReference<jobject>(
       annotations::GetAnnotationForMethodParameter(method, parameterIndex, klass));
 }
diff --git a/runtime/native/java_lang_reflect_Proxy.cc b/runtime/native/java_lang_reflect_Proxy.cc
index 4a6ab40..ece0338 100644
--- a/runtime/native/java_lang_reflect_Proxy.cc
+++ b/runtime/native/java_lang_reflect_Proxy.cc
@@ -21,7 +21,7 @@
 #include "mirror/class_loader.h"
 #include "mirror/object_array.h"
 #include "mirror/string.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
 #include "verify_object-inl.h"
 
 namespace art {
diff --git a/runtime/native/libcore_util_CharsetUtils.cc b/runtime/native/libcore_util_CharsetUtils.cc
index 64d56f6..2590452 100644
--- a/runtime/native/libcore_util_CharsetUtils.cc
+++ b/runtime/native/libcore_util_CharsetUtils.cc
@@ -18,7 +18,7 @@
 #include "mirror/string.h"
 #include "mirror/string-inl.h"
 #include "native/libcore_util_CharsetUtils.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
 #include "ScopedPrimitiveArray.h"
 #include "unicode/utf16.h"
 
@@ -154,7 +154,7 @@
                                jchar maxValidChar) {
   ScopedObjectAccess soa(env);
   StackHandleScope<1> hs(soa.Self());
-  Handle<mirror::String> string(hs.NewHandle(soa.Decode<mirror::String*>(java_string)));
+  Handle<mirror::String> string(hs.NewHandle(soa.Decode<mirror::String>(java_string)));
   if (string.Get() == nullptr) {
     return nullptr;
   }
@@ -191,7 +191,7 @@
                                            jint length) {
   ScopedObjectAccess soa(env);
   StackHandleScope<1> hs(soa.Self());
-  Handle<mirror::String> string(hs.NewHandle(soa.Decode<mirror::String*>(java_string)));
+  Handle<mirror::String> string(hs.NewHandle(soa.Decode<mirror::String>(java_string)));
   if (string.Get() == nullptr) {
     return nullptr;
   }
diff --git a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc
index 0ab2979..5356498 100644
--- a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc
+++ b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc
@@ -19,7 +19,7 @@
 #include "base/logging.h"
 #include "debugger.h"
 #include "jni_internal.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
 #include "ScopedPrimitiveArray.h"
 
 namespace art {
diff --git a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
index 9ed0e7e..ca17c26 100644
--- a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
+++ b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
@@ -20,7 +20,7 @@
 #include "base/mutex.h"
 #include "debugger.h"
 #include "jni_internal.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
 #include "ScopedLocalRef.h"
 #include "ScopedPrimitiveArray.h"
 #include "thread_list.h"
diff --git a/runtime/native/scoped_fast_native_object_access-inl.h b/runtime/native/scoped_fast_native_object_access-inl.h
new file mode 100644
index 0000000..1d73813
--- /dev/null
+++ b/runtime/native/scoped_fast_native_object_access-inl.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_NATIVE_SCOPED_FAST_NATIVE_OBJECT_ACCESS_INL_H_
+#define ART_RUNTIME_NATIVE_SCOPED_FAST_NATIVE_OBJECT_ACCESS_INL_H_
+
+#include "scoped_fast_native_object_access.h"
+
+#include "art_method-inl.h"
+#include "scoped_thread_state_change-inl.h"
+
+namespace art {
+
+inline ScopedFastNativeObjectAccess::ScopedFastNativeObjectAccess(JNIEnv* env)
+    : ScopedObjectAccessAlreadyRunnable(env) {
+  Locks::mutator_lock_->AssertSharedHeld(Self());
+  DCHECK((*Self()->GetManagedStack()->GetTopQuickFrame())->IsFastNative());
+  // Don't work with raw objects in non-runnable states.
+  DCHECK_EQ(Self()->GetState(), kRunnable);
+}
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_NATIVE_SCOPED_FAST_NATIVE_OBJECT_ACCESS_INL_H_
diff --git a/runtime/native/scoped_fast_native_object_access.h b/runtime/native/scoped_fast_native_object_access.h
index c4a33df..6a9365d 100644
--- a/runtime/native/scoped_fast_native_object_access.h
+++ b/runtime/native/scoped_fast_native_object_access.h
@@ -17,7 +17,8 @@
 #ifndef ART_RUNTIME_NATIVE_SCOPED_FAST_NATIVE_OBJECT_ACCESS_H_
 #define ART_RUNTIME_NATIVE_SCOPED_FAST_NATIVE_OBJECT_ACCESS_H_
 
-#include "art_method-inl.h"
+#include <jni.h>
+
 #include "scoped_thread_state_change.h"
 
 namespace art {
@@ -26,18 +27,11 @@
 // JNI methods.
 class ScopedFastNativeObjectAccess : public ScopedObjectAccessAlreadyRunnable {
  public:
-  explicit ScopedFastNativeObjectAccess(JNIEnv* env)
+  ALWAYS_INLINE explicit ScopedFastNativeObjectAccess(JNIEnv* env)
     REQUIRES(!Locks::thread_suspend_count_lock_)
-    SHARED_LOCK_FUNCTION(Locks::mutator_lock_) ALWAYS_INLINE
-     : ScopedObjectAccessAlreadyRunnable(env) {
-    Locks::mutator_lock_->AssertSharedHeld(Self());
-    DCHECK((*Self()->GetManagedStack()->GetTopQuickFrame())->IsFastNative());
-    // Don't work with raw objects in non-runnable states.
-    DCHECK_EQ(Self()->GetState(), kRunnable);
-  }
+    SHARED_LOCK_FUNCTION(Locks::mutator_lock_);
 
-  ~ScopedFastNativeObjectAccess() UNLOCK_FUNCTION(Locks::mutator_lock_) ALWAYS_INLINE {
-  }
+  ALWAYS_INLINE ~ScopedFastNativeObjectAccess() UNLOCK_FUNCTION(Locks::mutator_lock_) {}
 
  private:
   DISALLOW_COPY_AND_ASSIGN(ScopedFastNativeObjectAccess);
diff --git a/runtime/native/sun_misc_Unsafe.cc b/runtime/native/sun_misc_Unsafe.cc
index 472340c..2fae3cc 100644
--- a/runtime/native/sun_misc_Unsafe.cc
+++ b/runtime/native/sun_misc_Unsafe.cc
@@ -21,7 +21,7 @@
 #include "mirror/array.h"
 #include "mirror/class-inl.h"
 #include "mirror/object-inl.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
 
 #include <unistd.h>
 #include <stdlib.h>
@@ -33,61 +33,64 @@
 static jboolean Unsafe_compareAndSwapInt(JNIEnv* env, jobject, jobject javaObj, jlong offset,
                                          jint expectedValue, jint newValue) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
   // JNI must use non transactional mode.
   bool success = obj->CasFieldStrongSequentiallyConsistent32<false>(MemberOffset(offset),
-                                                                    expectedValue, newValue);
+                                                                    expectedValue,
+                                                                    newValue);
   return success ? JNI_TRUE : JNI_FALSE;
 }
 
 static jboolean Unsafe_compareAndSwapLong(JNIEnv* env, jobject, jobject javaObj, jlong offset,
                                           jlong expectedValue, jlong newValue) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
   // JNI must use non transactional mode.
   bool success = obj->CasFieldStrongSequentiallyConsistent64<false>(MemberOffset(offset),
-                                                                    expectedValue, newValue);
+                                                                    expectedValue,
+                                                                    newValue);
   return success ? JNI_TRUE : JNI_FALSE;
 }
 
 static jboolean Unsafe_compareAndSwapObject(JNIEnv* env, jobject, jobject javaObj, jlong offset,
                                             jobject javaExpectedValue, jobject javaNewValue) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
-  mirror::Object* expectedValue = soa.Decode<mirror::Object*>(javaExpectedValue);
-  mirror::Object* newValue = soa.Decode<mirror::Object*>(javaNewValue);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
+  ObjPtr<mirror::Object> expectedValue = soa.Decode<mirror::Object>(javaExpectedValue);
+  ObjPtr<mirror::Object> newValue = soa.Decode<mirror::Object>(javaNewValue);
   // JNI must use non transactional mode.
   if (kUseReadBarrier) {
     // Need to make sure the reference stored in the field is a to-space one before attempting the
     // CAS or the CAS could fail incorrectly.
     mirror::HeapReference<mirror::Object>* field_addr =
         reinterpret_cast<mirror::HeapReference<mirror::Object>*>(
-            reinterpret_cast<uint8_t*>(obj) + static_cast<size_t>(offset));
+            reinterpret_cast<uint8_t*>(obj.Decode()) + static_cast<size_t>(offset));
     ReadBarrier::Barrier<mirror::Object, kWithReadBarrier, /*kAlwaysUpdateField*/true>(
-        obj,
+        obj.Decode(),
         MemberOffset(offset),
         field_addr);
   }
   bool success = obj->CasFieldStrongSequentiallyConsistentObject<false>(MemberOffset(offset),
-                                                                        expectedValue, newValue);
+                                                                        expectedValue.Decode(),
+                                                                        newValue.Decode());
   return success ? JNI_TRUE : JNI_FALSE;
 }
 
 static jint Unsafe_getInt(JNIEnv* env, jobject, jobject javaObj, jlong offset) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
   return obj->GetField32(MemberOffset(offset));
 }
 
 static jint Unsafe_getIntVolatile(JNIEnv* env, jobject, jobject javaObj, jlong offset) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
   return obj->GetField32Volatile(MemberOffset(offset));
 }
 
 static void Unsafe_putInt(JNIEnv* env, jobject, jobject javaObj, jlong offset, jint newValue) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
   // JNI must use non transactional mode.
   obj->SetField32<false>(MemberOffset(offset), newValue);
 }
@@ -95,7 +98,7 @@
 static void Unsafe_putIntVolatile(JNIEnv* env, jobject, jobject javaObj, jlong offset,
                                   jint newValue) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
   // JNI must use non transactional mode.
   obj->SetField32Volatile<false>(MemberOffset(offset), newValue);
 }
@@ -103,7 +106,7 @@
 static void Unsafe_putOrderedInt(JNIEnv* env, jobject, jobject javaObj, jlong offset,
                                  jint newValue) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
   QuasiAtomic::ThreadFenceRelease();
   // JNI must use non transactional mode.
   obj->SetField32<false>(MemberOffset(offset), newValue);
@@ -111,19 +114,19 @@
 
 static jlong Unsafe_getLong(JNIEnv* env, jobject, jobject javaObj, jlong offset) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
   return obj->GetField64(MemberOffset(offset));
 }
 
 static jlong Unsafe_getLongVolatile(JNIEnv* env, jobject, jobject javaObj, jlong offset) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
   return obj->GetField64Volatile(MemberOffset(offset));
 }
 
 static void Unsafe_putLong(JNIEnv* env, jobject, jobject javaObj, jlong offset, jlong newValue) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
   // JNI must use non transactional mode.
   obj->SetField64<false>(MemberOffset(offset), newValue);
 }
@@ -131,7 +134,7 @@
 static void Unsafe_putLongVolatile(JNIEnv* env, jobject, jobject javaObj, jlong offset,
                                    jlong newValue) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
   // JNI must use non transactional mode.
   obj->SetField64Volatile<false>(MemberOffset(offset), newValue);
 }
@@ -139,7 +142,7 @@
 static void Unsafe_putOrderedLong(JNIEnv* env, jobject, jobject javaObj, jlong offset,
                                   jlong newValue) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
   QuasiAtomic::ThreadFenceRelease();
   // JNI must use non transactional mode.
   obj->SetField64<false>(MemberOffset(offset), newValue);
@@ -147,56 +150,56 @@
 
 static jobject Unsafe_getObjectVolatile(JNIEnv* env, jobject, jobject javaObj, jlong offset) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
-  mirror::Object* value = obj->GetFieldObjectVolatile<mirror::Object>(MemberOffset(offset));
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
+  ObjPtr<mirror::Object> value = obj->GetFieldObjectVolatile<mirror::Object>(MemberOffset(offset));
   return soa.AddLocalReference<jobject>(value);
 }
 
 static jobject Unsafe_getObject(JNIEnv* env, jobject, jobject javaObj, jlong offset) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
-  mirror::Object* value = obj->GetFieldObject<mirror::Object>(MemberOffset(offset));
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
+  ObjPtr<mirror::Object> value = obj->GetFieldObject<mirror::Object>(MemberOffset(offset));
   return soa.AddLocalReference<jobject>(value);
 }
 
 static void Unsafe_putObject(JNIEnv* env, jobject, jobject javaObj, jlong offset,
                              jobject javaNewValue) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
-  mirror::Object* newValue = soa.Decode<mirror::Object*>(javaNewValue);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
+  ObjPtr<mirror::Object> newValue = soa.Decode<mirror::Object>(javaNewValue);
   // JNI must use non transactional mode.
-  obj->SetFieldObject<false>(MemberOffset(offset), newValue);
+  obj->SetFieldObject<false>(MemberOffset(offset), newValue.Decode());
 }
 
 static void Unsafe_putObjectVolatile(JNIEnv* env, jobject, jobject javaObj, jlong offset,
                                      jobject javaNewValue) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
-  mirror::Object* newValue = soa.Decode<mirror::Object*>(javaNewValue);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
+  ObjPtr<mirror::Object> newValue = soa.Decode<mirror::Object>(javaNewValue);
   // JNI must use non transactional mode.
-  obj->SetFieldObjectVolatile<false>(MemberOffset(offset), newValue);
+  obj->SetFieldObjectVolatile<false>(MemberOffset(offset), newValue.Decode());
 }
 
 static void Unsafe_putOrderedObject(JNIEnv* env, jobject, jobject javaObj, jlong offset,
                                     jobject javaNewValue) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
-  mirror::Object* newValue = soa.Decode<mirror::Object*>(javaNewValue);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
+  ObjPtr<mirror::Object> newValue = soa.Decode<mirror::Object>(javaNewValue);
   QuasiAtomic::ThreadFenceRelease();
   // JNI must use non transactional mode.
-  obj->SetFieldObject<false>(MemberOffset(offset), newValue);
+  obj->SetFieldObject<false>(MemberOffset(offset), newValue.Decode());
 }
 
 static jint Unsafe_getArrayBaseOffsetForComponentType(JNIEnv* env, jclass, jobject component_class) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Class* component = soa.Decode<mirror::Class*>(component_class);
+  ObjPtr<mirror::Class> component = soa.Decode<mirror::Class>(component_class);
   Primitive::Type primitive_type = component->GetPrimitiveType();
   return mirror::Array::DataOffset(Primitive::ComponentSize(primitive_type)).Int32Value();
 }
 
 static jint Unsafe_getArrayIndexScaleForComponentType(JNIEnv* env, jclass, jobject component_class) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Class* component = soa.Decode<mirror::Class*>(component_class);
+  ObjPtr<mirror::Class> component = soa.Decode<mirror::Class>(component_class);
   Primitive::Type primitive_type = component->GetPrimitiveType();
   return Primitive::ComponentSize(primitive_type);
 }
@@ -289,16 +292,16 @@
 
 static void Unsafe_copyMemory(JNIEnv *env, jobject unsafe ATTRIBUTE_UNUSED, jlong src,
                               jlong dst, jlong size) {
-    if (size == 0) {
-        return;
-    }
-    // size is nonnegative and fits into size_t
-    if (size < 0 || size != (jlong)(size_t) size) {
-        ScopedFastNativeObjectAccess soa(env);
-        ThrowIllegalAccessException("wrong number of bytes");
-    }
-    size_t sz = (size_t)size;
-    memcpy(reinterpret_cast<void *>(dst), reinterpret_cast<void *>(src), sz);
+  if (size == 0) {
+    return;
+  }
+  // size is nonnegative and fits into size_t
+  if (size < 0 || size != (jlong)(size_t) size) {
+    ScopedFastNativeObjectAccess soa(env);
+    ThrowIllegalAccessException("wrong number of bytes");
+  }
+  size_t sz = (size_t)size;
+  memcpy(reinterpret_cast<void *>(dst), reinterpret_cast<void *>(src), sz);
 }
 
 template<typename T>
@@ -306,12 +309,12 @@
                         size_t array_offset,
                         size_t size)
         REQUIRES_SHARED(Locks::mutator_lock_) {
-    const T* src = reinterpret_cast<T*>(srcAddr);
-    size_t sz = size / sizeof(T);
-    size_t of = array_offset / sizeof(T);
-    for (size_t i = 0; i < sz; ++i) {
-        array->Set(i + of, *(src + i));
-    }
+  const T* src = reinterpret_cast<T*>(srcAddr);
+  size_t sz = size / sizeof(T);
+  size_t of = array_offset / sizeof(T);
+  for (size_t i = 0; i < sz; ++i) {
+    array->Set(i + of, *(src + i));
+  }
 }
 
 template<typename T>
@@ -319,12 +322,12 @@
                           size_t array_offset,
                           size_t size)
         REQUIRES_SHARED(Locks::mutator_lock_) {
-    T* dst = reinterpret_cast<T*>(dstAddr);
-    size_t sz = size / sizeof(T);
-    size_t of = array_offset / sizeof(T);
-    for (size_t i = 0; i < sz; ++i) {
-        *(dst + i) = array->Get(i + of);
-    }
+  T* dst = reinterpret_cast<T*>(dstAddr);
+  size_t sz = size / sizeof(T);
+  size_t of = array_offset / sizeof(T);
+  for (size_t i = 0; i < sz; ++i) {
+    *(dst + i) = array->Get(i + of);
+  }
 }
 
 static void Unsafe_copyMemoryToPrimitiveArray(JNIEnv *env,
@@ -333,29 +336,29 @@
                                               jobject dstObj,
                                               jlong dstOffset,
                                               jlong size) {
-    ScopedObjectAccess soa(env);
-    if (size == 0) {
-        return;
-    }
-    // size is nonnegative and fits into size_t
-    if (size < 0 || size != (jlong)(size_t) size) {
-        ThrowIllegalAccessException("wrong number of bytes");
-    }
-    size_t sz = (size_t)size;
-    size_t dst_offset = (size_t)dstOffset;
-    mirror::Object* dst = soa.Decode<mirror::Object*>(dstObj);
-    mirror::Class* component_type = dst->GetClass()->GetComponentType();
-    if (component_type->IsPrimitiveByte() || component_type->IsPrimitiveBoolean()) {
-        copyToArray(srcAddr, dst->AsByteSizedArray(), dst_offset, sz);
-    } else if (component_type->IsPrimitiveShort() || component_type->IsPrimitiveChar()) {
-        copyToArray(srcAddr, dst->AsShortSizedArray(), dst_offset, sz);
-    } else if (component_type->IsPrimitiveInt() || component_type->IsPrimitiveFloat()) {
-        copyToArray(srcAddr, dst->AsIntArray(), dst_offset, sz);
-    } else if (component_type->IsPrimitiveLong() || component_type->IsPrimitiveDouble()) {
-        copyToArray(srcAddr, dst->AsLongArray(), dst_offset, sz);
-    } else {
-        ThrowIllegalAccessException("not a primitive array");
-    }
+  ScopedObjectAccess soa(env);
+  if (size == 0) {
+    return;
+  }
+  // size is nonnegative and fits into size_t
+  if (size < 0 || size != (jlong)(size_t) size) {
+    ThrowIllegalAccessException("wrong number of bytes");
+  }
+  size_t sz = (size_t)size;
+  size_t dst_offset = (size_t)dstOffset;
+  ObjPtr<mirror::Object> dst = soa.Decode<mirror::Object>(dstObj);
+  mirror::Class* component_type = dst->GetClass()->GetComponentType();
+  if (component_type->IsPrimitiveByte() || component_type->IsPrimitiveBoolean()) {
+    copyToArray(srcAddr, dst->AsByteSizedArray(), dst_offset, sz);
+  } else if (component_type->IsPrimitiveShort() || component_type->IsPrimitiveChar()) {
+    copyToArray(srcAddr, dst->AsShortSizedArray(), dst_offset, sz);
+  } else if (component_type->IsPrimitiveInt() || component_type->IsPrimitiveFloat()) {
+    copyToArray(srcAddr, dst->AsIntArray(), dst_offset, sz);
+  } else if (component_type->IsPrimitiveLong() || component_type->IsPrimitiveDouble()) {
+    copyToArray(srcAddr, dst->AsLongArray(), dst_offset, sz);
+  } else {
+    ThrowIllegalAccessException("not a primitive array");
+  }
 }
 
 static void Unsafe_copyMemoryFromPrimitiveArray(JNIEnv *env,
@@ -364,85 +367,85 @@
                                                 jlong srcOffset,
                                                 jlong dstAddr,
                                                 jlong size) {
-    ScopedObjectAccess soa(env);
-    if (size == 0) {
-        return;
-    }
-    // size is nonnegative and fits into size_t
-    if (size < 0 || size != (jlong)(size_t) size) {
-        ThrowIllegalAccessException("wrong number of bytes");
-    }
-    size_t sz = (size_t)size;
-    size_t src_offset = (size_t)srcOffset;
-    mirror::Object* src = soa.Decode<mirror::Object*>(srcObj);
-    mirror::Class* component_type = src->GetClass()->GetComponentType();
-    if (component_type->IsPrimitiveByte() || component_type->IsPrimitiveBoolean()) {
-        copyFromArray(dstAddr, src->AsByteSizedArray(), src_offset, sz);
-    } else if (component_type->IsPrimitiveShort() || component_type->IsPrimitiveChar()) {
-        copyFromArray(dstAddr, src->AsShortSizedArray(), src_offset, sz);
-    } else if (component_type->IsPrimitiveInt() || component_type->IsPrimitiveFloat()) {
-        copyFromArray(dstAddr, src->AsIntArray(), src_offset, sz);
-    } else if (component_type->IsPrimitiveLong() || component_type->IsPrimitiveDouble()) {
-        copyFromArray(dstAddr, src->AsLongArray(), src_offset, sz);
-    } else {
-        ThrowIllegalAccessException("not a primitive array");
-    }
+  ScopedObjectAccess soa(env);
+  if (size == 0) {
+    return;
+  }
+  // size is nonnegative and fits into size_t
+  if (size < 0 || size != (jlong)(size_t) size) {
+    ThrowIllegalAccessException("wrong number of bytes");
+  }
+  size_t sz = (size_t)size;
+  size_t src_offset = (size_t)srcOffset;
+  ObjPtr<mirror::Object> src = soa.Decode<mirror::Object>(srcObj);
+  mirror::Class* component_type = src->GetClass()->GetComponentType();
+  if (component_type->IsPrimitiveByte() || component_type->IsPrimitiveBoolean()) {
+    copyFromArray(dstAddr, src->AsByteSizedArray(), src_offset, sz);
+  } else if (component_type->IsPrimitiveShort() || component_type->IsPrimitiveChar()) {
+    copyFromArray(dstAddr, src->AsShortSizedArray(), src_offset, sz);
+  } else if (component_type->IsPrimitiveInt() || component_type->IsPrimitiveFloat()) {
+    copyFromArray(dstAddr, src->AsIntArray(), src_offset, sz);
+  } else if (component_type->IsPrimitiveLong() || component_type->IsPrimitiveDouble()) {
+    copyFromArray(dstAddr, src->AsLongArray(), src_offset, sz);
+  } else {
+    ThrowIllegalAccessException("not a primitive array");
+  }
 }
 static jboolean Unsafe_getBoolean(JNIEnv* env, jobject, jobject javaObj, jlong offset) {
-    ScopedFastNativeObjectAccess soa(env);
-    mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
-    return obj->GetFieldBoolean(MemberOffset(offset));
+  ScopedFastNativeObjectAccess soa(env);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
+  return obj->GetFieldBoolean(MemberOffset(offset));
 }
 
 static void Unsafe_putBoolean(JNIEnv* env, jobject, jobject javaObj, jlong offset, jboolean newValue) {
-    ScopedFastNativeObjectAccess soa(env);
-    mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
-    // JNI must use non transactional mode (SetField8 is non-transactional).
-    obj->SetFieldBoolean<false>(MemberOffset(offset), newValue);
+  ScopedFastNativeObjectAccess soa(env);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
+  // JNI must use non transactional mode (SetField8 is non-transactional).
+  obj->SetFieldBoolean<false>(MemberOffset(offset), newValue);
 }
 
 static jbyte Unsafe_getByte(JNIEnv* env, jobject, jobject javaObj, jlong offset) {
-    ScopedFastNativeObjectAccess soa(env);
-    mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
-    return obj->GetFieldByte(MemberOffset(offset));
+  ScopedFastNativeObjectAccess soa(env);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
+  return obj->GetFieldByte(MemberOffset(offset));
 }
 
 static void Unsafe_putByte(JNIEnv* env, jobject, jobject javaObj, jlong offset, jbyte newValue) {
-    ScopedFastNativeObjectAccess soa(env);
-    mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
-    // JNI must use non transactional mode.
-    obj->SetFieldByte<false>(MemberOffset(offset), newValue);
+  ScopedFastNativeObjectAccess soa(env);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
+  // JNI must use non transactional mode.
+  obj->SetFieldByte<false>(MemberOffset(offset), newValue);
 }
 
 static jchar Unsafe_getChar(JNIEnv* env, jobject, jobject javaObj, jlong offset) {
-    ScopedFastNativeObjectAccess soa(env);
-    mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
-    return obj->GetFieldChar(MemberOffset(offset));
+  ScopedFastNativeObjectAccess soa(env);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
+  return obj->GetFieldChar(MemberOffset(offset));
 }
 
 static void Unsafe_putChar(JNIEnv* env, jobject, jobject javaObj, jlong offset, jchar newValue) {
-    ScopedFastNativeObjectAccess soa(env);
-    mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
-    // JNI must use non transactional mode.
-    obj->SetFieldChar<false>(MemberOffset(offset), newValue);
+  ScopedFastNativeObjectAccess soa(env);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
+  // JNI must use non transactional mode.
+  obj->SetFieldChar<false>(MemberOffset(offset), newValue);
 }
 
 static jshort Unsafe_getShort(JNIEnv* env, jobject, jobject javaObj, jlong offset) {
-    ScopedFastNativeObjectAccess soa(env);
-    mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
-    return obj->GetFieldShort(MemberOffset(offset));
+  ScopedFastNativeObjectAccess soa(env);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
+  return obj->GetFieldShort(MemberOffset(offset));
 }
 
 static void Unsafe_putShort(JNIEnv* env, jobject, jobject javaObj, jlong offset, jshort newValue) {
-    ScopedFastNativeObjectAccess soa(env);
-    mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
-    // JNI must use non transactional mode.
-    obj->SetFieldShort<false>(MemberOffset(offset), newValue);
+  ScopedFastNativeObjectAccess soa(env);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
+  // JNI must use non transactional mode.
+  obj->SetFieldShort<false>(MemberOffset(offset), newValue);
 }
 
 static jfloat Unsafe_getFloat(JNIEnv* env, jobject, jobject javaObj, jlong offset) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
   union {int32_t val; jfloat converted;} conv;
   conv.val = obj->GetField32(MemberOffset(offset));
   return conv.converted;
@@ -450,7 +453,7 @@
 
 static void Unsafe_putFloat(JNIEnv* env, jobject, jobject javaObj, jlong offset, jfloat newValue) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
   union {int32_t converted; jfloat val;} conv;
   conv.val = newValue;
   // JNI must use non transactional mode.
@@ -459,7 +462,7 @@
 
 static jdouble Unsafe_getDouble(JNIEnv* env, jobject, jobject javaObj, jlong offset) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
   union {int64_t val; jdouble converted;} conv;
   conv.val = obj->GetField64(MemberOffset(offset));
   return conv.converted;
@@ -467,7 +470,7 @@
 
 static void Unsafe_putDouble(JNIEnv* env, jobject, jobject javaObj, jlong offset, jdouble newValue) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+  ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
   union {int64_t converted; jdouble val;} conv;
   conv.val = newValue;
   // JNI must use non transactional mode.
diff --git a/runtime/native_bridge_art_interface.cc b/runtime/native_bridge_art_interface.cc
index 155c008..059dc5a 100644
--- a/runtime/native_bridge_art_interface.cc
+++ b/runtime/native_bridge_art_interface.cc
@@ -26,7 +26,7 @@
 #include "base/macros.h"
 #include "dex_file-inl.h"
 #include "mirror/class-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "sigchain.h"
 
 namespace art {
@@ -43,7 +43,7 @@
   }
 
   ScopedObjectAccess soa(env);
-  mirror::Class* c = soa.Decode<mirror::Class*>(clazz);
+  ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(clazz);
 
   uint32_t native_method_count = 0;
   for (auto& m : c->GetMethods(kRuntimePointerSize)) {
@@ -58,7 +58,7 @@
     return 0;
   }
   ScopedObjectAccess soa(env);
-  mirror::Class* c = soa.Decode<mirror::Class*>(clazz);
+  ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(clazz);
 
   uint32_t count = 0;
   for (auto& m : c->GetMethods(kRuntimePointerSize)) {
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index 415f991..ff00451 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -27,7 +27,7 @@
 #include "oat.h"
 #include "os.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "utils.h"
 
 namespace art {
diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc
index 6ec5e55..d18e946 100644
--- a/runtime/oat_file_assistant_test.cc
+++ b/runtime/oat_file_assistant_test.cc
@@ -33,7 +33,7 @@
 #include "oat_file_assistant.h"
 #include "oat_file_manager.h"
 #include "os.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 #include "utils.h"
 
diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc
index 6d4b2f6..acad2a9 100644
--- a/runtime/oat_file_manager.cc
+++ b/runtime/oat_file_manager.cc
@@ -30,7 +30,7 @@
 #include "handle_scope-inl.h"
 #include "mirror/class_loader.h"
 #include "oat_file_assistant.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 #include "thread_list.h"
 
@@ -294,8 +294,8 @@
   }
 
   // Unsupported class-loader?
-  if (class_loader->GetClass() !=
-      soa.Decode<mirror::Class*>(WellKnownClasses::dalvik_system_PathClassLoader)) {
+  if (soa.Decode<mirror::Class>(WellKnownClasses::dalvik_system_PathClassLoader) !=
+      class_loader->GetClass()) {
     VLOG(class_linker) << "Unsupported class-loader " << PrettyClass(class_loader->GetClass());
     return false;
   }
@@ -338,10 +338,10 @@
   ArtField* const cookie_field = soa.DecodeField(WellKnownClasses::dalvik_system_DexFile_cookie);
   ArtField* const dex_file_field =
       soa.DecodeField(WellKnownClasses::dalvik_system_DexPathList__Element_dexFile);
-  const mirror::Class* const element_class = soa.Decode<mirror::Class*>(
+  ObjPtr<mirror::Class> const element_class = soa.Decode<mirror::Class>(
       WellKnownClasses::dalvik_system_DexPathList__Element);
-  const mirror::Class* const dexfile_class = soa.Decode<mirror::Class*>(
-        WellKnownClasses::dalvik_system_DexFile);
+  ObjPtr<mirror::Class> const dexfile_class = soa.Decode<mirror::Class>(
+      WellKnownClasses::dalvik_system_DexFile);
 
   // Collect all the dex files.
   auto GetDexFilesFn = [&] (const DexFile* cp_dex_file)
@@ -361,9 +361,9 @@
     // We support this being dalvik.system.DexPathList$Element and dalvik.system.DexFile.
 
     mirror::Object* dex_file;
-    if (element->GetClass() == element_class) {
+    if (element_class == element->GetClass()) {
       dex_file = dex_file_field->GetObject(element);
-    } else if (element->GetClass() == dexfile_class) {
+    } else if (dexfile_class == element->GetClass()) {
       dex_file = element;
     } else {
       LOG(WARNING) << "Unsupported element in dex_elements: " << PrettyClass(element->GetClass());
@@ -442,9 +442,9 @@
     ScopedObjectAccess soa(Thread::Current());
     StackHandleScope<2> hs(Thread::Current());
     Handle<mirror::ClassLoader> h_class_loader =
-        hs.NewHandle(soa.Decode<mirror::ClassLoader*>(class_loader));
+        hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader));
     Handle<mirror::ObjectArray<mirror::Object>> h_dex_elements =
-        hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Object>*>(dex_elements));
+        hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Object>>(dex_elements));
     if (h_class_loader.Get() != nullptr &&
         GetDexFilesFromClassLoader(soa, h_class_loader.Get(), &queue)) {
       class_loader_ok = true;
@@ -638,7 +638,7 @@
         ScopedObjectAccess soa(self);
         StackHandleScope<1> hs(self);
         Handle<mirror::ClassLoader> h_loader(
-            hs.NewHandle(soa.Decode<mirror::ClassLoader*>(class_loader)));
+            hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader)));
         // Can not load app image without class loader.
         if (h_loader.Get() != nullptr) {
           std::string temp_error_msg;
diff --git a/runtime/oat_file_test.cc b/runtime/oat_file_test.cc
index a88553c..b416b9d 100644
--- a/runtime/oat_file_test.cc
+++ b/runtime/oat_file_test.cc
@@ -21,7 +21,7 @@
 #include <gtest/gtest.h>
 
 #include "common_runtime_test.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 
diff --git a/runtime/oat_quick_method_header.cc b/runtime/oat_quick_method_header.cc
index 0ab2bfe..a68d9f8 100644
--- a/runtime/oat_quick_method_header.cc
+++ b/runtime/oat_quick_method_header.cc
@@ -17,7 +17,7 @@
 #include "oat_quick_method_header.h"
 
 #include "art_method.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread.h"
 
 namespace art {
diff --git a/runtime/obj_ptr-inl.h b/runtime/obj_ptr-inl.h
index 3dfcf9e..1c698b5 100644
--- a/runtime/obj_ptr-inl.h
+++ b/runtime/obj_ptr-inl.h
@@ -41,6 +41,7 @@
 template<class MirrorType, bool kPoison>
 inline uintptr_t ObjPtr<MirrorType, kPoison>::Encode(MirrorType* ptr) {
   uintptr_t ref = reinterpret_cast<uintptr_t>(ptr);
+  DCHECK_ALIGNED(ref, kObjectAlignment);
   if (kPoison && ref != 0) {
     DCHECK_LE(ref, 0xFFFFFFFFU);
     ref >>= kObjectAlignmentShift;
@@ -52,6 +53,12 @@
   return ref;
 }
 
+template<class MirrorType, bool kPoison>
+inline std::ostream& operator<<(std::ostream& os, ObjPtr<MirrorType, kPoison> ptr) {
+  // May be used for dumping bad pointers, do not use the checked version.
+  return os << ptr.DecodeUnchecked();
+}
+
 }  // namespace art
 
 #endif  // ART_RUNTIME_OBJ_PTR_INL_H_
diff --git a/runtime/obj_ptr.h b/runtime/obj_ptr.h
index d4076be..d5ac33d 100644
--- a/runtime/obj_ptr.h
+++ b/runtime/obj_ptr.h
@@ -17,6 +17,8 @@
 #ifndef ART_RUNTIME_OBJ_PTR_H_
 #define ART_RUNTIME_OBJ_PTR_H_
 
+#include <ostream>
+
 #include "base/mutex.h"  // For Locks::mutator_lock_.
 #include "globals.h"
 #include "mirror/object_reference.h"
@@ -45,10 +47,13 @@
   ALWAYS_INLINE ObjPtr(Type* ptr) REQUIRES_SHARED(Locks::mutator_lock_)
       : reference_(Encode(static_cast<MirrorType*>(ptr))) {}
 
-  ALWAYS_INLINE ObjPtr(const ObjPtr& other) REQUIRES_SHARED(Locks::mutator_lock_) = default;
+  template <typename Type>
+  ALWAYS_INLINE ObjPtr(const ObjPtr<Type>& other) REQUIRES_SHARED(Locks::mutator_lock_)
+      : reference_(Encode(static_cast<MirrorType*>(other.Decode()))) {}
 
+  template <typename Type>
   ALWAYS_INLINE ObjPtr& operator=(const ObjPtr& other) {
-    reference_ = other.reference_;
+    reference_ = Encode(static_cast<MirrorType*>(other.Decode()));
     return *this;
   }
 
@@ -65,7 +70,6 @@
     return Decode();
   }
 
-
   ALWAYS_INLINE bool IsNull() const {
     return reference_ == 0;
   }
@@ -104,6 +108,16 @@
     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_) {
+    if (kPoison) {
+      return reinterpret_cast<MirrorType*>(
+          static_cast<uintptr_t>(static_cast<uint32_t>(reference_ << kObjectAlignmentShift)));
+    } else {
+      return reinterpret_cast<MirrorType*>(reference_);
+    }
+  }
+
  private:
   // Trim off high bits of thread local cookie.
   ALWAYS_INLINE static uintptr_t TrimCookie(uintptr_t cookie) {
@@ -114,16 +128,6 @@
     return reference_ >> kCookieShift;
   }
 
-  // Decode makes sure that the object pointer is valid.
-  ALWAYS_INLINE MirrorType* DecodeUnchecked() const REQUIRES_SHARED(Locks::mutator_lock_) {
-    if (kPoison) {
-      return reinterpret_cast<MirrorType*>(
-          static_cast<uintptr_t>(static_cast<uint32_t>(reference_ << kObjectAlignmentShift)));
-    } else {
-      return reinterpret_cast<MirrorType*>(reference_);
-    }
-  }
-
   ALWAYS_INLINE static uintptr_t Encode(MirrorType* ptr) REQUIRES_SHARED(Locks::mutator_lock_);
   // The encoded reference and cookie.
   uintptr_t reference_;
@@ -134,6 +138,10 @@
   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_);
+
 }  // namespace art
 
 #endif  // ART_RUNTIME_OBJ_PTR_H_
diff --git a/runtime/openjdkjvm/OpenjdkJvm.cc b/runtime/openjdkjvm/OpenjdkJvm.cc
index 4a62ecd..d46d78c 100644
--- a/runtime/openjdkjvm/OpenjdkJvm.cc
+++ b/runtime/openjdkjvm/OpenjdkJvm.cc
@@ -43,7 +43,7 @@
 #include "thread_list.h"
 #include "runtime.h"
 #include "handle_scope-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "ScopedUtfChars.h"
 #include "mirror/class_loader.h"
 #include "verify_object-inl.h"
@@ -52,7 +52,7 @@
 #include "../../libcore/ojluni/src/main/native/jvm.h"  // TODO(narayan): fix it
 #include "jni_internal.h"
 #include "mirror/string-inl.h"
-#include "native/scoped_fast_native_object_access.h"
+#include "native/scoped_fast_native_object_access-inl.h"
 #include "ScopedLocalRef.h"
 #include <sys/time.h>
 #include <sys/socket.h>
@@ -286,9 +286,8 @@
 
 JNIEXPORT jstring JVM_InternString(JNIEnv* env, jstring jstr) {
   art::ScopedFastNativeObjectAccess soa(env);
-  art::mirror::String* s = soa.Decode<art::mirror::String*>(jstr);
-  art::mirror::String* result = s->Intern();
-  return soa.AddLocalReference<jstring>(result);
+  art::ObjPtr<art::mirror::String> s = soa.Decode<art::mirror::String>(jstr);
+  return soa.AddLocalReference<jstring>(s->Intern());
 }
 
 JNIEXPORT jlong JVM_FreeMemory(void) {
@@ -364,8 +363,8 @@
 JNIEXPORT void JVM_Sleep(JNIEnv* env, jclass threadClass ATTRIBUTE_UNUSED,
                          jobject java_lock, jlong millis) {
   art::ScopedFastNativeObjectAccess soa(env);
-  art::mirror::Object* lock = soa.Decode<art::mirror::Object*>(java_lock);
-  art::Monitor::Wait(art::Thread::Current(), lock, millis, 0, true, art::kSleeping);
+  art::ObjPtr<art::mirror::Object> lock = soa.Decode<art::mirror::Object>(java_lock);
+  art::Monitor::Wait(art::Thread::Current(), lock.Decode(), millis, 0, true, art::kSleeping);
 }
 
 JNIEXPORT jobject JVM_CurrentThread(JNIEnv* env, jclass unused ATTRIBUTE_UNUSED) {
@@ -395,19 +394,19 @@
 
 JNIEXPORT jboolean JVM_HoldsLock(JNIEnv* env, jclass unused ATTRIBUTE_UNUSED, jobject jobj) {
   art::ScopedObjectAccess soa(env);
-  art::mirror::Object* object = soa.Decode<art::mirror::Object*>(jobj);
-  if (object == NULL) {
+  art::ObjPtr<art::mirror::Object> object = soa.Decode<art::mirror::Object>(jobj);
+  if (object == nullptr) {
     art::ThrowNullPointerException("object == null");
     return JNI_FALSE;
   }
-  return soa.Self()->HoldsLock(object);
+  return soa.Self()->HoldsLock(object.Decode());
 }
 
 JNIEXPORT void JVM_SetNativeThreadName(JNIEnv* env, jobject jthread, jstring java_name) {
   ScopedUtfChars name(env, java_name);
   {
     art::ScopedObjectAccess soa(env);
-    if (soa.Decode<art::mirror::Object*>(jthread) == soa.Self()->GetPeer()) {
+    if (soa.Decode<art::mirror::Object>(jthread) == soa.Self()->GetPeer()) {
       soa.Self()->SetThreadName(name.c_str());
       return;
     }
diff --git a/runtime/openjdkjvmti/transform.cc b/runtime/openjdkjvmti/transform.cc
index b5622b5..ac348e7 100644
--- a/runtime/openjdkjvmti/transform.cc
+++ b/runtime/openjdkjvmti/transform.cc
@@ -43,7 +43,7 @@
 #include "mirror/class-inl.h"
 #include "mirror/class_loader-inl.h"
 #include "mirror/string-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread_list.h"
 #include "transform.h"
 #include "utf.h"
@@ -259,7 +259,7 @@
   JNIEnv* jni_env = *jni_env_ptr;
   art::ScopedObjectAccess soa(jni_env);
   art::StackHandleScope<3> hs(art::Thread::Current());
-  art::Handle<art::mirror::Class> hs_klass(hs.NewHandle(soa.Decode<art::mirror::Class*>(klass)));
+  art::Handle<art::mirror::Class> hs_klass(hs.NewHandle(soa.Decode<art::mirror::Class>(klass)));
   *loader = soa.AddLocalReference<jobject>(hs_klass->GetClassLoader());
   *name = art::mirror::Class::ComputeName(hs_klass)->ToModifiedUtf8();
   // TODO is this always null?
diff --git a/runtime/proxy_test.cc b/runtime/proxy_test.cc
index e3f92c7..43b0b3d 100644
--- a/runtime/proxy_test.cc
+++ b/runtime/proxy_test.cc
@@ -23,7 +23,7 @@
 #include "common_compiler_test.h"
 #include "mirror/field-inl.h"
 #include "mirror/method.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 
@@ -108,7 +108,7 @@
   jobject jclass_loader = LoadDex("Interfaces");
   StackHandleScope<4> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader(
-      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+      hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader)));
 
   Handle<mirror::Class> I(hs.NewHandle(
       class_linker_->FindClass(soa.Self(), "LInterfaces$I;", class_loader)));
@@ -142,7 +142,7 @@
   jobject jclass_loader = LoadDex("Interfaces");
   StackHandleScope<9> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader(
-      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+      hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader)));
 
   Handle<mirror::Class> I(hs.NewHandle(
       class_linker_->FindClass(soa.Self(), "LInterfaces$I;", class_loader)));
@@ -200,7 +200,7 @@
   jobject jclass_loader = LoadDex("Interfaces");
   StackHandleScope<7> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader(
-      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+      hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader)));
 
   Handle<mirror::Class> proxyClass0;
   Handle<mirror::Class> proxyClass1;
diff --git a/runtime/reference_table_test.cc b/runtime/reference_table_test.cc
index 819e17a..489db9a 100644
--- a/runtime/reference_table_test.cc
+++ b/runtime/reference_table_test.cc
@@ -25,7 +25,7 @@
 #include "mirror/string.h"
 #include "primitive.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 
 namespace art {
diff --git a/runtime/reflection.cc b/runtime/reflection.cc
index 7c0f2b5..b663b4c 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -28,7 +28,7 @@
 #include "mirror/executable.h"
 #include "mirror/object_array-inl.h"
 #include "nth_caller_visitor.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "stack_reference.h"
 #include "well_known_classes.h"
 
@@ -115,7 +115,7 @@
           AppendFloat(va_arg(ap, jdouble));
           break;
         case 'L':
-          Append(soa.Decode<mirror::Object*>(va_arg(ap, jobject)));
+          Append(soa.Decode<mirror::Object>(va_arg(ap, jobject)));
           break;
         case 'D':
           AppendDouble(va_arg(ap, jdouble));
@@ -157,7 +157,7 @@
           Append(args[args_offset].i);
           break;
         case 'L':
-          Append(soa.Decode<mirror::Object*>(args[args_offset].l));
+          Append(soa.Decode<mirror::Object>(args[args_offset].l));
           break;
         case 'D':
         case 'J':
@@ -459,7 +459,7 @@
     // Replace calls to String.<init> with equivalent StringFactory call.
     method = WellKnownClasses::StringInitToStringFactory(method);
   }
-  ObjPtr<mirror::Object> receiver = method->IsStatic() ? nullptr : soa.Decode<mirror::Object*>(obj);
+  ObjPtr<mirror::Object> receiver = method->IsStatic() ? nullptr : soa.Decode<mirror::Object>(obj);
   uint32_t shorty_len = 0;
   const char* shorty =
       method->GetInterfaceMethodIfProxy(kRuntimePointerSize)->GetShorty(&shorty_len);
@@ -490,7 +490,7 @@
     // Replace calls to String.<init> with equivalent StringFactory call.
     method = WellKnownClasses::StringInitToStringFactory(method);
   }
-  ObjPtr<mirror::Object> receiver = method->IsStatic() ? nullptr : soa.Decode<mirror::Object*>(obj);
+  ObjPtr<mirror::Object> receiver = method->IsStatic() ? nullptr : soa.Decode<mirror::Object>(obj);
   uint32_t shorty_len = 0;
   const char* shorty =
       method->GetInterfaceMethodIfProxy(kRuntimePointerSize)->GetShorty(&shorty_len);
@@ -515,7 +515,7 @@
     return JValue();
   }
 
-  ObjPtr<mirror::Object> receiver = soa.Decode<mirror::Object*>(obj);
+  ObjPtr<mirror::Object> receiver = soa.Decode<mirror::Object>(obj);
   ArtMethod* method = FindVirtualMethod(receiver, soa.DecodeMethod(mid));
   bool is_string_init = method->GetDeclaringClass()->IsStringClass() && method->IsConstructor();
   if (is_string_init) {
@@ -547,7 +547,7 @@
     return JValue();
   }
 
-  ObjPtr<mirror::Object> receiver = soa.Decode<mirror::Object*>(obj);
+  ObjPtr<mirror::Object> receiver = soa.Decode<mirror::Object>(obj);
   ArtMethod* method = FindVirtualMethod(receiver, soa.DecodeMethod(mid));
   bool is_string_init = method->GetDeclaringClass()->IsStringClass() && method->IsConstructor();
   if (is_string_init) {
@@ -580,18 +580,17 @@
     return nullptr;
   }
 
-  ObjPtr<mirror::Executable> executable = soa.Decode<mirror::Executable*>(javaMethod);
+  ObjPtr<mirror::Executable> executable = soa.Decode<mirror::Executable>(javaMethod);
   const bool accessible = executable->IsAccessible();
   ArtMethod* m = executable->GetArtMethod();
 
   ObjPtr<mirror::Class> declaring_class = m->GetDeclaringClass();
   if (UNLIKELY(!declaring_class->IsInitialized())) {
     StackHandleScope<1> hs(soa.Self());
-    Handle<mirror::Class> h_class(hs.NewHandle(declaring_class.Decode()));
+    HandleWrapperObjPtr<mirror::Class> h_class(hs.NewHandleWrapper(&declaring_class));
     if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(soa.Self(), h_class, true, true)) {
       return nullptr;
     }
-    declaring_class = h_class.Get();
   }
 
   ObjPtr<mirror::Object> receiver;
@@ -602,7 +601,7 @@
       CHECK(javaReceiver == nullptr);
     } else {
       // Check that the receiver is non-null and an instance of the field's declaring class.
-      receiver = soa.Decode<mirror::Object*>(javaReceiver);
+      receiver = soa.Decode<mirror::Object>(javaReceiver);
       if (!VerifyObjectIsClass(receiver, declaring_class)) {
         return nullptr;
       }
@@ -613,7 +612,8 @@
   }
 
   // Get our arrays of arguments and their types, and check they're the same size.
-  auto* objects = soa.Decode<mirror::ObjectArray<mirror::Object>*>(javaArgs);
+  ObjPtr<mirror::ObjectArray<mirror::Object>> objects =
+      soa.Decode<mirror::ObjectArray<mirror::Object>>(javaArgs);
   auto* np_method = m->GetInterfaceMethodIfProxy(kRuntimePointerSize);
   const DexFile::TypeList* classes = np_method->GetParameterTypeList();
   uint32_t classes_size = (classes == nullptr) ? 0 : classes->Size();
@@ -682,7 +682,7 @@
 
 ObjPtr<mirror::Object> BoxPrimitive(Primitive::Type src_class, const JValue& value) {
   if (src_class == Primitive::kPrimNot) {
-    return value.GetL();
+    return MakeObjPtr(value.GetL());
   }
   if (src_class == Primitive::kPrimVoid) {
     // There's no such thing as a void field, and void methods invoked via reflection return null.
diff --git a/runtime/reflection_test.cc b/runtime/reflection_test.cc
index 4876ff0..189ed03 100644
--- a/runtime/reflection_test.cc
+++ b/runtime/reflection_test.cc
@@ -23,7 +23,7 @@
 #include "art_method-inl.h"
 #include "base/enums.h"
 #include "common_compiler_test.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 
@@ -93,16 +93,12 @@
     StackHandleScope<2> hs(self);
     Handle<mirror::ClassLoader> class_loader(
         hs.NewHandle(
-            ScopedObjectAccessUnchecked(self).Decode<mirror::ClassLoader*>(jclass_loader)));
-    if (is_static) {
-      MakeExecutable(ScopedObjectAccessUnchecked(self).Decode<mirror::ClassLoader*>(jclass_loader),
-                     class_name);
-    } else {
+            ScopedObjectAccessUnchecked(self).Decode<mirror::ClassLoader>(jclass_loader)));
+    if (!is_static) {
       MakeExecutable(nullptr, "java.lang.Class");
       MakeExecutable(nullptr, "java.lang.Object");
-      MakeExecutable(ScopedObjectAccessUnchecked(self).Decode<mirror::ClassLoader*>(jclass_loader),
-                     class_name);
     }
+    MakeExecutable(class_loader.Get(), class_name);
 
     mirror::Class* c = class_linker_->FindClass(self, DotToDescriptor(class_name).c_str(),
                                                 class_loader);
@@ -512,7 +508,7 @@
   jobject jclass_loader = LoadDex("Main");
   StackHandleScope<1> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader(
-      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+      hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader)));
   CompileDirectMethod(class_loader, "Main", "main", "([Ljava/lang/String;)V");
 
   mirror::Class* klass = class_linker_->FindClass(soa.Self(), "LMain;", class_loader);
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 65b894f..df0dca0 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -133,7 +133,7 @@
 #include "reflection.h"
 #include "runtime_options.h"
 #include "ScopedLocalRef.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "sigchain.h"
 #include "signal_catcher.h"
 #include "signal_set.h"
@@ -530,7 +530,7 @@
 
   StackHandleScope<2> hs(soa.Self());
   Handle<mirror::Class> class_loader_class(
-      hs.NewHandle(soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_ClassLoader)));
+      hs.NewHandle(soa.Decode<mirror::Class>(WellKnownClasses::java_lang_ClassLoader)));
   CHECK(cl->EnsureInitialized(soa.Self(), class_loader_class, true, true));
 
   ArtMethod* getSystemClassLoader = class_loader_class->FindDirectMethod(
@@ -545,7 +545,7 @@
   soa.Self()->SetClassLoaderOverride(system_class_loader.get());
 
   Handle<mirror::Class> thread_class(
-      hs.NewHandle(soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_Thread)));
+      hs.NewHandle(soa.Decode<mirror::Class>(WellKnownClasses::java_lang_Thread)));
   CHECK(cl->EnsureInitialized(soa.Self(), thread_class, true, true));
 
   ArtField* contextClassLoader =
@@ -553,8 +553,9 @@
   CHECK(contextClassLoader != nullptr);
 
   // We can't run in a transaction yet.
-  contextClassLoader->SetObject<false>(soa.Self()->GetPeer(),
-                                       soa.Decode<mirror::ClassLoader*>(system_class_loader.get()));
+  contextClassLoader->SetObject<false>(
+      soa.Self()->GetPeer(),
+      soa.Decode<mirror::ClassLoader>(system_class_loader.get()).Decode());
 
   return env->NewGlobalRef(system_class_loader.get());
 }
diff --git a/runtime/scoped_thread_state_change-inl.h b/runtime/scoped_thread_state_change-inl.h
new file mode 100644
index 0000000..cf020d0
--- /dev/null
+++ b/runtime/scoped_thread_state_change-inl.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_SCOPED_THREAD_STATE_CHANGE_INL_H_
+#define ART_RUNTIME_SCOPED_THREAD_STATE_CHANGE_INL_H_
+
+#include "scoped_thread_state_change.h"
+
+#include "jni_env_ext-inl.h"
+#include "obj_ptr-inl.h"
+#include "thread-inl.h"
+
+namespace art {
+
+inline ScopedThreadStateChange::ScopedThreadStateChange(Thread* self, ThreadState new_thread_state)
+    : self_(self), thread_state_(new_thread_state), expected_has_no_thread_(false) {
+  if (UNLIKELY(self_ == nullptr)) {
+    // Value chosen arbitrarily and won't be used in the destructor since thread_ == null.
+    old_thread_state_ = kTerminated;
+    Runtime* runtime = Runtime::Current();
+    CHECK(runtime == nullptr || !runtime->IsStarted() || runtime->IsShuttingDown(self_));
+  } else {
+    DCHECK_EQ(self, Thread::Current());
+    // Read state without locks, ok as state is effectively thread local and we're not interested
+    // in the suspend count (this will be handled in the runnable transitions).
+    old_thread_state_ = self->GetState();
+    if (old_thread_state_ != new_thread_state) {
+      if (new_thread_state == kRunnable) {
+        self_->TransitionFromSuspendedToRunnable();
+      } else if (old_thread_state_ == kRunnable) {
+        self_->TransitionFromRunnableToSuspended(new_thread_state);
+      } else {
+        // A suspended transition to another effectively suspended transition, ok to use Unsafe.
+        self_->SetState(new_thread_state);
+      }
+    }
+  }
+}
+
+inline ScopedThreadStateChange::~ScopedThreadStateChange() {
+  if (UNLIKELY(self_ == nullptr)) {
+    if (!expected_has_no_thread_) {
+      Runtime* runtime = Runtime::Current();
+      bool shutting_down = (runtime == nullptr) || runtime->IsShuttingDown(nullptr);
+      CHECK(shutting_down);
+    }
+  } else {
+    if (old_thread_state_ != thread_state_) {
+      if (old_thread_state_ == kRunnable) {
+        self_->TransitionFromSuspendedToRunnable();
+      } else if (thread_state_ == kRunnable) {
+        self_->TransitionFromRunnableToSuspended(old_thread_state_);
+      } else {
+        // A suspended transition to another effectively suspended transition, ok to use Unsafe.
+        self_->SetState(old_thread_state_);
+      }
+    }
+  }
+}
+
+template<typename T>
+inline T ScopedObjectAccessAlreadyRunnable::AddLocalReference(mirror::Object* obj) const {
+  Locks::mutator_lock_->AssertSharedHeld(Self());
+  DCHECK(IsRunnable());  // Don't work with raw objects in non-runnable states.
+  DCHECK_NE(obj, Runtime::Current()->GetClearedJniWeakGlobal());
+  return obj == nullptr ? nullptr : Env()->AddLocalReference<T>(obj);
+}
+
+template<typename T, typename MirrorType, bool kPoison>
+inline T ScopedObjectAccessAlreadyRunnable::AddLocalReference(
+    ObjPtr<MirrorType, kPoison> obj) const {
+  return AddLocalReference<T>(obj.Decode());
+}
+
+template<typename T, bool kPoison>
+inline ObjPtr<T, kPoison> ScopedObjectAccessAlreadyRunnable::Decode(jobject obj) const {
+  Locks::mutator_lock_->AssertSharedHeld(Self());
+  DCHECK(IsRunnable());  // Don't work with raw objects in non-runnable states.
+  return down_cast<T*>(Self()->DecodeJObject(obj));
+}
+
+inline ArtField* ScopedObjectAccessAlreadyRunnable::DecodeField(jfieldID fid) const {
+  Locks::mutator_lock_->AssertSharedHeld(Self());
+  DCHECK(IsRunnable());  // Don't work with raw objects in non-runnable states.
+  return reinterpret_cast<ArtField*>(fid);
+}
+
+inline jfieldID ScopedObjectAccessAlreadyRunnable::EncodeField(ArtField* field) const {
+  Locks::mutator_lock_->AssertSharedHeld(Self());
+  DCHECK(IsRunnable());  // Don't work with raw objects in non-runnable states.
+  return reinterpret_cast<jfieldID>(field);
+}
+
+inline ArtMethod* ScopedObjectAccessAlreadyRunnable::DecodeMethod(jmethodID mid) const {
+  Locks::mutator_lock_->AssertSharedHeld(Self());
+  DCHECK(IsRunnable());  // Don't work with raw objects in non-runnable states.
+  return reinterpret_cast<ArtMethod*>(mid);
+}
+
+inline jmethodID ScopedObjectAccessAlreadyRunnable::EncodeMethod(ArtMethod* method) const {
+  Locks::mutator_lock_->AssertSharedHeld(Self());
+  DCHECK(IsRunnable());  // Don't work with raw objects in non-runnable states.
+  return reinterpret_cast<jmethodID>(method);
+}
+
+inline bool ScopedObjectAccessAlreadyRunnable::IsRunnable() const {
+  return self_->GetState() == kRunnable;
+}
+
+inline ScopedObjectAccessAlreadyRunnable::ScopedObjectAccessAlreadyRunnable(JNIEnv* env)
+    : self_(ThreadForEnv(env)), env_(down_cast<JNIEnvExt*>(env)), vm_(env_->vm) {}
+
+inline ScopedObjectAccessAlreadyRunnable::ScopedObjectAccessAlreadyRunnable(Thread* self)
+    : self_(self),
+      env_(down_cast<JNIEnvExt*>(self->GetJniEnv())),
+      vm_(env_ != nullptr ? env_->vm : nullptr) {}
+
+inline ScopedObjectAccessUnchecked::ScopedObjectAccessUnchecked(JNIEnv* env)
+    : ScopedObjectAccessAlreadyRunnable(env), tsc_(Self(), kRunnable) {
+  Self()->VerifyStack();
+  Locks::mutator_lock_->AssertSharedHeld(Self());
+}
+
+inline ScopedObjectAccessUnchecked::ScopedObjectAccessUnchecked(Thread* self)
+    : ScopedObjectAccessAlreadyRunnable(self), tsc_(self, kRunnable) {
+  Self()->VerifyStack();
+  Locks::mutator_lock_->AssertSharedHeld(Self());
+}
+
+inline ScopedThreadSuspension::ScopedThreadSuspension(Thread* self, ThreadState suspended_state)
+    : self_(self), suspended_state_(suspended_state) {
+  DCHECK(self_ != nullptr);
+  self_->TransitionFromRunnableToSuspended(suspended_state);
+}
+
+inline ScopedThreadSuspension::~ScopedThreadSuspension() {
+  DCHECK_EQ(self_->GetState(), suspended_state_);
+  self_->TransitionFromSuspendedToRunnable();
+}
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_SCOPED_THREAD_STATE_CHANGE_INL_H_
diff --git a/runtime/scoped_thread_state_change.h b/runtime/scoped_thread_state_change.h
index 8a1aca5..175bec5 100644
--- a/runtime/scoped_thread_state_change.h
+++ b/runtime/scoped_thread_state_change.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2016 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -17,85 +17,43 @@
 #ifndef ART_RUNTIME_SCOPED_THREAD_STATE_CHANGE_H_
 #define ART_RUNTIME_SCOPED_THREAD_STATE_CHANGE_H_
 
-#include "base/casts.h"
-#include "java_vm_ext.h"
-#include "jni_env_ext-inl.h"
 #include "art_field.h"
-#include "read_barrier.h"
-#include "thread-inl.h"
+#include "base/casts.h"
+#include "base/value_object.h"
+#include "java_vm_ext.h"
+#include "thread_state.h"
 #include "verify_object.h"
 
 namespace art {
 
+struct JNIEnvExt;
+template<class MirrorType, bool kPoison> class ObjPtr;
+
 // Scoped change into and out of a particular state. Handles Runnable transitions that require
 // more complicated suspension checking. The subclasses ScopedObjectAccessUnchecked and
 // ScopedObjectAccess are used to handle the change into Runnable to Get direct access to objects,
 // the unchecked variant doesn't aid annotalysis.
 class ScopedThreadStateChange : public ValueObject {
  public:
-  ScopedThreadStateChange(Thread* self, ThreadState new_thread_state)
-      REQUIRES(!Locks::thread_suspend_count_lock_) ALWAYS_INLINE
-      : self_(self), thread_state_(new_thread_state), expected_has_no_thread_(false) {
-    if (UNLIKELY(self_ == nullptr)) {
-      // Value chosen arbitrarily and won't be used in the destructor since thread_ == null.
-      old_thread_state_ = kTerminated;
-      Runtime* runtime = Runtime::Current();
-      CHECK(runtime == nullptr || !runtime->IsStarted() || runtime->IsShuttingDown(self_));
-    } else {
-      DCHECK_EQ(self, Thread::Current());
-      // Read state without locks, ok as state is effectively thread local and we're not interested
-      // in the suspend count (this will be handled in the runnable transitions).
-      old_thread_state_ = self->GetState();
-      if (old_thread_state_ != new_thread_state) {
-        if (new_thread_state == kRunnable) {
-          self_->TransitionFromSuspendedToRunnable();
-        } else if (old_thread_state_ == kRunnable) {
-          self_->TransitionFromRunnableToSuspended(new_thread_state);
-        } else {
-          // A suspended transition to another effectively suspended transition, ok to use Unsafe.
-          self_->SetState(new_thread_state);
-        }
-      }
-    }
-  }
+  ALWAYS_INLINE ScopedThreadStateChange(Thread* self, ThreadState new_thread_state)
+      REQUIRES(!Locks::thread_suspend_count_lock_);
 
-  ~ScopedThreadStateChange() REQUIRES(!Locks::thread_suspend_count_lock_) ALWAYS_INLINE {
-    if (UNLIKELY(self_ == nullptr)) {
-      if (!expected_has_no_thread_) {
-        Runtime* runtime = Runtime::Current();
-        bool shutting_down = (runtime == nullptr) || runtime->IsShuttingDown(nullptr);
-        CHECK(shutting_down);
-      }
-    } else {
-      if (old_thread_state_ != thread_state_) {
-        if (old_thread_state_ == kRunnable) {
-          self_->TransitionFromSuspendedToRunnable();
-        } else if (thread_state_ == kRunnable) {
-          self_->TransitionFromRunnableToSuspended(old_thread_state_);
-        } else {
-          // A suspended transition to another effectively suspended transition, ok to use Unsafe.
-          self_->SetState(old_thread_state_);
-        }
-      }
-    }
-  }
+  ALWAYS_INLINE ~ScopedThreadStateChange() REQUIRES(!Locks::thread_suspend_count_lock_);
 
-  Thread* Self() const {
+  ALWAYS_INLINE Thread* Self() const {
     return self_;
   }
 
  protected:
   // Constructor used by ScopedJniThreadState for an unattached thread that has access to the VM*.
-  ScopedThreadStateChange()
-      : self_(nullptr), thread_state_(kTerminated), old_thread_state_(kTerminated),
-        expected_has_no_thread_(true) {}
+  ScopedThreadStateChange() {}
 
-  Thread* const self_;
-  const ThreadState thread_state_;
+  Thread* const self_ = nullptr;
+  const ThreadState thread_state_ = kTerminated;
 
  private:
-  ThreadState old_thread_state_;
-  const bool expected_has_no_thread_;
+  ThreadState old_thread_state_ = kTerminated;
+  const bool expected_has_no_thread_ = true;
 
   friend class ScopedObjectAccessUnchecked;
   DISALLOW_COPY_AND_ASSIGN(ScopedThreadStateChange);
@@ -129,62 +87,34 @@
    * This will be called on otherwise unreferenced objects. We cannot do GC allocations here, and
    * it's best if we don't grab a mutex.
    */
+  template<typename T, typename MirrorType, bool kPoison = kIsDebugBuild>
+  T AddLocalReference(ObjPtr<MirrorType, kPoison> obj) const
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
+  // TODO: Delete
   template<typename T>
-  T AddLocalReference(mirror::Object* obj) const REQUIRES_SHARED(Locks::mutator_lock_) {
-    Locks::mutator_lock_->AssertSharedHeld(Self());
-    DCHECK(IsRunnable());  // Don't work with raw objects in non-runnable states.
-    DCHECK_NE(obj, Runtime::Current()->GetClearedJniWeakGlobal());
-    return obj == nullptr ? nullptr : Env()->AddLocalReference<T>(obj);
-  }
+  T AddLocalReference(mirror::Object* obj) const
+      REQUIRES_SHARED(Locks::mutator_lock_);
 
-  template<typename T>
-  T Decode(jobject obj) const
-      REQUIRES_SHARED(Locks::mutator_lock_) {
-    Locks::mutator_lock_->AssertSharedHeld(Self());
-    DCHECK(IsRunnable());  // Don't work with raw objects in non-runnable states.
-    return down_cast<T>(Self()->DecodeJObject(obj));
-  }
+  template<typename T, bool kPoison = kIsDebugBuild>
+  ObjPtr<T, kPoison> Decode(jobject obj) const REQUIRES_SHARED(Locks::mutator_lock_);
 
-  ArtField* DecodeField(jfieldID fid) const
-      REQUIRES_SHARED(Locks::mutator_lock_) {
-    Locks::mutator_lock_->AssertSharedHeld(Self());
-    DCHECK(IsRunnable());  // Don't work with raw objects in non-runnable states.
-    return reinterpret_cast<ArtField*>(fid);
-  }
+  ArtField* DecodeField(jfieldID fid) const REQUIRES_SHARED(Locks::mutator_lock_);
 
-  jfieldID EncodeField(ArtField* field) const REQUIRES_SHARED(Locks::mutator_lock_) {
-    Locks::mutator_lock_->AssertSharedHeld(Self());
-    DCHECK(IsRunnable());  // Don't work with raw objects in non-runnable states.
-    return reinterpret_cast<jfieldID>(field);
-  }
+  jfieldID EncodeField(ArtField* field) const REQUIRES_SHARED(Locks::mutator_lock_);
 
-  ArtMethod* DecodeMethod(jmethodID mid) const REQUIRES_SHARED(Locks::mutator_lock_) {
-    Locks::mutator_lock_->AssertSharedHeld(Self());
-    DCHECK(IsRunnable());  // Don't work with raw objects in non-runnable states.
-    return reinterpret_cast<ArtMethod*>(mid);
-  }
+  ArtMethod* DecodeMethod(jmethodID mid) const REQUIRES_SHARED(Locks::mutator_lock_);
 
-  jmethodID EncodeMethod(ArtMethod* method) const REQUIRES_SHARED(Locks::mutator_lock_) {
-    Locks::mutator_lock_->AssertSharedHeld(Self());
-    DCHECK(IsRunnable());  // Don't work with raw objects in non-runnable states.
-    return reinterpret_cast<jmethodID>(method);
-  }
+  jmethodID EncodeMethod(ArtMethod* method) const REQUIRES_SHARED(Locks::mutator_lock_);
 
-  bool IsRunnable() const {
-    return self_->GetState() == kRunnable;
-  }
+  ALWAYS_INLINE bool IsRunnable() const;
 
  protected:
-  explicit ScopedObjectAccessAlreadyRunnable(JNIEnv* env)
-      REQUIRES(!Locks::thread_suspend_count_lock_) ALWAYS_INLINE
-      : self_(ThreadForEnv(env)), env_(down_cast<JNIEnvExt*>(env)), vm_(env_->vm) {
-  }
+  ALWAYS_INLINE explicit ScopedObjectAccessAlreadyRunnable(JNIEnv* env)
+      REQUIRES(!Locks::thread_suspend_count_lock_);
 
-  explicit ScopedObjectAccessAlreadyRunnable(Thread* self)
-      REQUIRES(!Locks::thread_suspend_count_lock_) ALWAYS_INLINE
-      : self_(self), env_(down_cast<JNIEnvExt*>(self->GetJniEnv())),
-        vm_(env_ != nullptr ? env_->vm : nullptr) {
-  }
+  ALWAYS_INLINE explicit ScopedObjectAccessAlreadyRunnable(Thread* self)
+      REQUIRES(!Locks::thread_suspend_count_lock_);
 
   // Used when we want a scoped JNI thread state but have no thread/JNIEnv. Consequently doesn't
   // change into Runnable or acquire a share on the mutator_lock_.
@@ -192,8 +122,7 @@
       : self_(nullptr), env_(nullptr), vm_(down_cast<JavaVMExt*>(vm)) {}
 
   // Here purely to force inlining.
-  ~ScopedObjectAccessAlreadyRunnable() ALWAYS_INLINE {
-  }
+  ALWAYS_INLINE ~ScopedObjectAccessAlreadyRunnable() {}
 
   // Self thread, can be null.
   Thread* const self_;
@@ -219,19 +148,11 @@
 // the mutator_lock_ will be acquired on construction.
 class ScopedObjectAccessUnchecked : public ScopedObjectAccessAlreadyRunnable {
  public:
-  explicit ScopedObjectAccessUnchecked(JNIEnv* env)
-      REQUIRES(!Locks::thread_suspend_count_lock_) ALWAYS_INLINE
-      : ScopedObjectAccessAlreadyRunnable(env), tsc_(Self(), kRunnable) {
-    Self()->VerifyStack();
-    Locks::mutator_lock_->AssertSharedHeld(Self());
-  }
+  ALWAYS_INLINE explicit ScopedObjectAccessUnchecked(JNIEnv* env)
+      REQUIRES(!Locks::thread_suspend_count_lock_);
 
-  explicit ScopedObjectAccessUnchecked(Thread* self)
-      REQUIRES(!Locks::thread_suspend_count_lock_) ALWAYS_INLINE
-      : ScopedObjectAccessAlreadyRunnable(self), tsc_(self, kRunnable) {
-    Self()->VerifyStack();
-    Locks::mutator_lock_->AssertSharedHeld(Self());
-  }
+  ALWAYS_INLINE explicit ScopedObjectAccessUnchecked(Thread* self)
+      REQUIRES(!Locks::thread_suspend_count_lock_);
 
   // Used when we want a scoped JNI thread state but have no thread/JNIEnv. Consequently doesn't
   // change into Runnable or acquire a share on the mutator_lock_.
@@ -249,28 +170,24 @@
 // Annotalysis helping variant of the above.
 class ScopedObjectAccess : public ScopedObjectAccessUnchecked {
  public:
-  explicit ScopedObjectAccess(JNIEnv* env)
+  ALWAYS_INLINE explicit ScopedObjectAccess(JNIEnv* env)
       REQUIRES(!Locks::thread_suspend_count_lock_)
-      SHARED_LOCK_FUNCTION(Locks::mutator_lock_) ALWAYS_INLINE
-      : ScopedObjectAccessUnchecked(env) {
-  }
+      SHARED_LOCK_FUNCTION(Locks::mutator_lock_)
+      : ScopedObjectAccessUnchecked(env) {}
 
-  explicit ScopedObjectAccess(Thread* self)
+  ALWAYS_INLINE explicit ScopedObjectAccess(Thread* self)
       REQUIRES(!Locks::thread_suspend_count_lock_)
-      SHARED_LOCK_FUNCTION(Locks::mutator_lock_) ALWAYS_INLINE
-      : ScopedObjectAccessUnchecked(self) {
-  }
+      SHARED_LOCK_FUNCTION(Locks::mutator_lock_)
+      : ScopedObjectAccessUnchecked(self) {}
 
-  ~ScopedObjectAccess() UNLOCK_FUNCTION(Locks::mutator_lock_) ALWAYS_INLINE {
-    // Base class will release share of lock. Invoked after this destructor.
-  }
+  // Base class will release share of lock. Invoked after this destructor.
+  ~ScopedObjectAccess() UNLOCK_FUNCTION(Locks::mutator_lock_) ALWAYS_INLINE {}
 
  private:
   // TODO: remove this constructor. It is used by check JNI's ScopedCheck to make it believe that
   //       routines operating with just a VM are sound, they are not, but when you have just a VM
   //       you cannot call the unsound routines.
-  explicit ScopedObjectAccess(JavaVM* vm)
-      SHARED_LOCK_FUNCTION(Locks::mutator_lock_)
+  explicit ScopedObjectAccess(JavaVM* vm) SHARED_LOCK_FUNCTION(Locks::mutator_lock_)
       : ScopedObjectAccessUnchecked(vm) {}
 
   friend class ScopedCheck;
@@ -280,19 +197,11 @@
 // Annotalysis helper for going to a suspended state from runnable.
 class ScopedThreadSuspension : public ValueObject {
  public:
-  explicit ScopedThreadSuspension(Thread* self, ThreadState suspended_state)
+  ALWAYS_INLINE explicit ScopedThreadSuspension(Thread* self, ThreadState suspended_state)
       REQUIRES(!Locks::thread_suspend_count_lock_, !Roles::uninterruptible_)
-      UNLOCK_FUNCTION(Locks::mutator_lock_)
-      ALWAYS_INLINE
-      : self_(self), suspended_state_(suspended_state) {
-    DCHECK(self_ != nullptr);
-    self_->TransitionFromRunnableToSuspended(suspended_state);
-  }
+      UNLOCK_FUNCTION(Locks::mutator_lock_);
 
-  ~ScopedThreadSuspension() SHARED_LOCK_FUNCTION(Locks::mutator_lock_) ALWAYS_INLINE {
-    DCHECK_EQ(self_->GetState(), suspended_state_);
-    self_->TransitionFromSuspendedToRunnable();
-  }
+  ALWAYS_INLINE ~ScopedThreadSuspension() SHARED_LOCK_FUNCTION(Locks::mutator_lock_);
 
  private:
   Thread* const self_;
diff --git a/runtime/signal_catcher.cc b/runtime/signal_catcher.cc
index 848c0e3..674459d 100644
--- a/runtime/signal_catcher.cc
+++ b/runtime/signal_catcher.cc
@@ -34,7 +34,7 @@
 #include "gc/heap.h"
 #include "os.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "signal_set.h"
 #include "thread.h"
 #include "thread_list.h"
diff --git a/runtime/thread.cc b/runtime/thread.cc
index d0ea2d7..ec1bb3f 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -59,12 +59,13 @@
 #include "native_stack_dump.h"
 #include "nth_caller_visitor.h"
 #include "oat_quick_method_header.h"
+#include "obj_ptr-inl.h"
 #include "object_lock.h"
 #include "quick_exception_handler.h"
 #include "quick/quick_method_frame_info.h"
 #include "reflection.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "ScopedLocalRef.h"
 #include "ScopedUtfChars.h"
 #include "stack.h"
@@ -406,7 +407,7 @@
 
     // Copy peer into self, deleting global reference when done.
     CHECK(self->tlsPtr_.jpeer != nullptr);
-    self->tlsPtr_.opeer = soa.Decode<mirror::Object*>(self->tlsPtr_.jpeer);
+    self->tlsPtr_.opeer = soa.Decode<mirror::Object>(self->tlsPtr_.jpeer).Decode();
     self->GetJniEnv()->DeleteGlobalRef(self->tlsPtr_.jpeer);
     self->tlsPtr_.jpeer = nullptr;
     self->SetThreadName(self->GetThreadName(soa)->ToModifiedUtf8().c_str());
@@ -444,7 +445,7 @@
 
 Thread* Thread::FromManagedThread(const ScopedObjectAccessAlreadyRunnable& soa,
                                   jobject java_thread) {
-  return FromManagedThread(soa, soa.Decode<mirror::Object*>(java_thread));
+  return FromManagedThread(soa, soa.Decode<mirror::Object>(java_thread).Decode());
 }
 
 static size_t FixStackSize(size_t stack_size) {
@@ -563,7 +564,7 @@
 
     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)));
+        soa.Decode<mirror::Object>(java_peer).Decode()));
     std::string thread_name;
     if (java_name != nullptr) {
       thread_name = java_name->ToModifiedUtf8();
@@ -802,7 +803,7 @@
   }
   {
     ScopedObjectAccess soa(this);
-    tlsPtr_.opeer = soa.Decode<mirror::Object*>(peer.get());
+    tlsPtr_.opeer = soa.Decode<mirror::Object>(peer.get()).Decode();
   }
   env->CallNonvirtualVoidMethod(peer.get(),
                                 WellKnownClasses::java_lang_Thread,
@@ -844,9 +845,11 @@
   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));
+      SetObject<kTransactionActive>(tlsPtr_.opeer,
+                                    soa.Decode<mirror::Object>(thread_group).Decode());
   soa.DecodeField(WellKnownClasses::java_lang_Thread_name)->
-      SetObject<kTransactionActive>(tlsPtr_.opeer, soa.Decode<mirror::Object*>(thread_name));
+      SetObject<kTransactionActive>(tlsPtr_.opeer,
+                                    soa.Decode<mirror::Object>(thread_name).Decode());
   soa.DecodeField(WellKnownClasses::java_lang_Thread_priority)->
       SetInt<kTransactionActive>(tlsPtr_.opeer, thread_priority);
 }
@@ -2123,7 +2126,7 @@
     int* stack_depth) {
   // Decode the internal stack trace into the depth, method trace and PC trace.
   // Subtract one for the methods and PC trace.
-  int32_t depth = soa.Decode<mirror::Array*>(internal)->GetLength() - 1;
+  int32_t depth = soa.Decode<mirror::Array>(internal)->GetLength() - 1;
   DCHECK_GE(depth, 0);
 
   ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
@@ -2135,7 +2138,7 @@
     result = output_array;
     // ...adjusting the number of frames we'll write to not exceed the array length.
     const int32_t traces_length =
-        soa.Decode<mirror::ObjectArray<mirror::StackTraceElement>*>(result)->GetLength();
+        soa.Decode<mirror::ObjectArray<mirror::StackTraceElement>>(result)->GetLength();
     depth = std::min(depth, traces_length);
   } else {
     // Create java_trace array and place in local reference table
@@ -2153,7 +2156,7 @@
 
   for (int32_t i = 0; i < depth; ++i) {
     mirror::ObjectArray<mirror::Object>* decoded_traces =
-        soa.Decode<mirror::Object*>(internal)->AsObjectArray<mirror::Object>();
+        soa.Decode<mirror::Object>(internal)->AsObjectArray<mirror::Object>();
     // Methods and dex PC trace is element 0.
     DCHECK(decoded_traces->Get(0)->IsIntArray() || decoded_traces->Get(0)->IsLongArray());
     mirror::PointerArray* const method_trace =
@@ -2205,7 +2208,7 @@
       return nullptr;
     }
     // We are called from native: use non-transactional mode.
-    soa.Decode<mirror::ObjectArray<mirror::StackTraceElement>*>(result)->Set<false>(i, obj);
+    soa.Decode<mirror::ObjectArray<mirror::StackTraceElement>>(result)->Set<false>(i, obj);
   }
   return result;
 }
@@ -3044,11 +3047,10 @@
   interpreter::EnterInterpreterFromDeoptimize(this, shadow_frame, from_code, result);
 }
 
-void Thread::SetException(mirror::Throwable* new_exception) {
+void Thread::SetException(ObjPtr<mirror::Throwable> new_exception) {
   CHECK(new_exception != nullptr);
   // TODO: DCHECK(!IsExceptionPending());
-  tlsPtr_.exception = new_exception;
-  // LOG(ERROR) << new_exception->Dump();
+  tlsPtr_.exception = new_exception.Decode();
 }
 
 }  // namespace art
diff --git a/runtime/thread.h b/runtime/thread.h
index 55f1489..f2c22d1 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -366,7 +366,7 @@
   void AssertNoPendingException() const;
   void AssertNoPendingExceptionForNewException(const char* msg) const;
 
-  void SetException(mirror::Throwable* new_exception) REQUIRES_SHARED(Locks::mutator_lock_);
+  void SetException(ObjPtr<mirror::Throwable> new_exception) REQUIRES_SHARED(Locks::mutator_lock_);
 
   void ClearException() REQUIRES_SHARED(Locks::mutator_lock_) {
     tlsPtr_.exception = nullptr;
@@ -902,7 +902,9 @@
 
   // Returns the fake exception used to activate deoptimization.
   static mirror::Throwable* GetDeoptimizationException() {
-    return reinterpret_cast<mirror::Throwable*>(-1);
+    // Note that the mirror::Throwable must be aligned to kObjectAlignment or else it cannot be
+    // represented by ObjPtr.
+    return reinterpret_cast<mirror::Throwable*>(0x100);
   }
 
   // Currently deoptimization invokes verifier which can trigger class loading
diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc
index 17c6c2e..e2aca6a 100644
--- a/runtime/thread_list.cc
+++ b/runtime/thread_list.cc
@@ -36,7 +36,7 @@
 #include "lock_word.h"
 #include "monitor.h"
 #include "native_stack_dump.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread.h"
 #include "trace.h"
 #include "well_known_classes.h"
diff --git a/runtime/trace.cc b/runtime/trace.cc
index 23591c2..f8467467 100644
--- a/runtime/trace.cc
+++ b/runtime/trace.cc
@@ -37,7 +37,7 @@
 #include "mirror/object_array-inl.h"
 #include "mirror/object-inl.h"
 #include "os.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "ScopedLocalRef.h"
 #include "thread.h"
 #include "thread_list.h"
diff --git a/runtime/transaction_test.cc b/runtime/transaction_test.cc
index 82e529c..77c2b76 100644
--- a/runtime/transaction_test.cc
+++ b/runtime/transaction_test.cc
@@ -22,7 +22,7 @@
 #include "common_runtime_test.h"
 #include "dex_file.h"
 #include "mirror/array-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 
@@ -36,7 +36,7 @@
     jobject jclass_loader = LoadDex("Transaction");
     StackHandleScope<2> hs(soa.Self());
     Handle<mirror::ClassLoader> class_loader(
-        hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+        hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader)));
     ASSERT_TRUE(class_loader.Get() != nullptr);
 
     // Load and initialize java.lang.ExceptionInInitializerError and the exception class used
@@ -173,7 +173,7 @@
   ScopedObjectAccess soa(Thread::Current());
   StackHandleScope<4> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader(
-      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Transaction"))));
+      hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("Transaction"))));
   ASSERT_TRUE(class_loader.Get() != nullptr);
 
   Handle<mirror::Class> h_klass(
@@ -271,7 +271,7 @@
   ScopedObjectAccess soa(Thread::Current());
   StackHandleScope<5> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader(
-      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Transaction"))));
+      hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("Transaction"))));
   ASSERT_TRUE(class_loader.Get() != nullptr);
 
   Handle<mirror::Class> h_klass(
@@ -373,7 +373,7 @@
   ScopedObjectAccess soa(Thread::Current());
   StackHandleScope<4> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader(
-      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Transaction"))));
+      hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("Transaction"))));
   ASSERT_TRUE(class_loader.Get() != nullptr);
 
   Handle<mirror::Class> h_klass(
@@ -490,7 +490,7 @@
   ScopedObjectAccess soa(Thread::Current());
   StackHandleScope<3> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader(
-      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Transaction"))));
+      hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("Transaction"))));
   ASSERT_TRUE(class_loader.Get() != nullptr);
 
   Handle<mirror::Class> h_klass(
@@ -539,7 +539,7 @@
   ScopedObjectAccess soa(Thread::Current());
   StackHandleScope<2> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader(
-      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Transaction"))));
+      hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("Transaction"))));
   ASSERT_TRUE(class_loader.Get() != nullptr);
 
   Handle<mirror::Class> h_klass(
@@ -563,7 +563,7 @@
   ScopedObjectAccess soa(Thread::Current());
   StackHandleScope<2> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader(
-      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Transaction"))));
+      hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("Transaction"))));
   ASSERT_TRUE(class_loader.Get() != nullptr);
 
   Handle<mirror::Class> h_klass(
diff --git a/runtime/type_lookup_table_test.cc b/runtime/type_lookup_table_test.cc
index ea4d8b5..ec38b41 100644
--- a/runtime/type_lookup_table_test.cc
+++ b/runtime/type_lookup_table_test.cc
@@ -19,7 +19,7 @@
 
 #include "common_runtime_test.h"
 #include "dex_file-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "type_lookup_table.h"
 #include "utf-inl.h"
 
diff --git a/runtime/utils.cc b/runtime/utils.cc
index 0803ca7..a40e313 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -39,7 +39,7 @@
 #include "oat_quick_method_header.h"
 #include "obj_ptr-inl.h"
 #include "os.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "utf-inl.h"
 
 #if defined(__APPLE__)
diff --git a/runtime/utils_test.cc b/runtime/utils_test.cc
index 3ba20a4..ef42222 100644
--- a/runtime/utils_test.cc
+++ b/runtime/utils_test.cc
@@ -26,7 +26,7 @@
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
 #include "mirror/string.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "handle_scope-inl.h"
 
 #include "base/memory_tool.h"
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 13ef043..87b6dc3 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -46,7 +46,7 @@
 #include "reg_type-inl.h"
 #include "register_line-inl.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "utils.h"
 #include "verifier_deps.h"
 #include "handle_scope-inl.h"
diff --git a/runtime/verifier/method_verifier_test.cc b/runtime/verifier/method_verifier_test.cc
index 646987a..837ee2d 100644
--- a/runtime/verifier/method_verifier_test.cc
+++ b/runtime/verifier/method_verifier_test.cc
@@ -22,7 +22,7 @@
 #include "class_linker-inl.h"
 #include "common_runtime_test.h"
 #include "dex_file.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "verifier_log_mode.h"
 
 namespace art {
diff --git a/runtime/verifier/reg_type.cc b/runtime/verifier/reg_type.cc
index 3bc2acc..a84668b 100644
--- a/runtime/verifier/reg_type.cc
+++ b/runtime/verifier/reg_type.cc
@@ -27,7 +27,7 @@
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
 #include "reg_type_cache-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 #include <limits>
 #include <sstream>
diff --git a/runtime/verifier/reg_type_test.cc b/runtime/verifier/reg_type_test.cc
index f2411b5..49dac26 100644
--- a/runtime/verifier/reg_type_test.cc
+++ b/runtime/verifier/reg_type_test.cc
@@ -24,7 +24,7 @@
 #include "common_runtime_test.h"
 #include "reg_type_cache-inl.h"
 #include "reg_type-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 
 namespace art {
diff --git a/runtime/verifier/verifier_deps_test.cc b/runtime/verifier/verifier_deps_test.cc
index bbaf59f..4533464 100644
--- a/runtime/verifier/verifier_deps_test.cc
+++ b/runtime/verifier/verifier_deps_test.cc
@@ -25,7 +25,7 @@
 #include "mirror/class_loader.h"
 #include "runtime.h"
 #include "thread.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 namespace verifier {
@@ -58,7 +58,7 @@
       REQUIRES_SHARED(Locks::mutator_lock_) {
     StackHandleScope<1> hs(Thread::Current());
     Handle<mirror::ClassLoader> class_loader_handle(
-        hs.NewHandle(soa->Decode<mirror::ClassLoader*>(class_loader_)));
+        hs.NewHandle(soa->Decode<mirror::ClassLoader>(class_loader_)));
     mirror::Class* klass = class_linker_->FindClass(Thread::Current(),
                                                     name.c_str(),
                                                     class_loader_handle);
@@ -84,8 +84,8 @@
 
     SetVerifierDeps(dex_files);
 
-    mirror::ClassLoader* loader = soa->Decode<mirror::ClassLoader*>(class_loader_);
-    class_linker_->RegisterDexFile(*dex_file_, loader);
+    ObjPtr<mirror::ClassLoader> loader = soa->Decode<mirror::ClassLoader>(class_loader_);
+    class_linker_->RegisterDexFile(*dex_file_, loader.Decode());
 
     klass_Main_ = FindClassByName("LMain;", soa);
     CHECK(klass_Main_ != nullptr);
@@ -97,7 +97,7 @@
 
     StackHandleScope<2> hs(Thread::Current());
     Handle<mirror::ClassLoader> class_loader_handle(
-        hs.NewHandle(soa.Decode<mirror::ClassLoader*>(class_loader_)));
+        hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader_)));
     Handle<mirror::DexCache> dex_cache_handle(hs.NewHandle(klass_Main_->GetDexCache()));
 
     const DexFile::ClassDef* class_def = klass_Main_->GetClassDef();
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index e5216fb..4dcf58f 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -25,7 +25,7 @@
 #include "mirror/class.h"
 #include "mirror/throwable.h"
 #include "ScopedLocalRef.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 
 namespace art {
diff --git a/test/004-ThreadStress/thread_stress.cc b/test/004-ThreadStress/thread_stress.cc
index 573c352..8ae3dfb 100644
--- a/test/004-ThreadStress/thread_stress.cc
+++ b/test/004-ThreadStress/thread_stress.cc
@@ -19,18 +19,18 @@
 #include "jni.h"
 #include "mirror/string.h"
 #include "mirror/throwable.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 
 extern "C" JNIEXPORT void JNICALL Java_Main_printString(JNIEnv*, jclass, jstring s) {
   ScopedObjectAccess soa(Thread::Current());
-  std::cout << soa.Decode<mirror::String*>(s)->ToModifiedUtf8();
+  std::cout << soa.Decode<mirror::String>(s)->ToModifiedUtf8();
 }
 
 extern "C" JNIEXPORT void JNICALL Java_Main_printThrowable(JNIEnv*, jclass, jthrowable t) {
   ScopedObjectAccess soa(Thread::Current());
-  std::cout << soa.Decode<mirror::Throwable*>(t)->Dump();
+  std::cout << soa.Decode<mirror::Throwable>(t)->Dump();
 }
 
 }  // namespace art
diff --git a/test/004-UnsafeTest/unsafe_test.cc b/test/004-UnsafeTest/unsafe_test.cc
index 3b0cf23..4f6ae5a 100644
--- a/test/004-UnsafeTest/unsafe_test.cc
+++ b/test/004-UnsafeTest/unsafe_test.cc
@@ -20,20 +20,20 @@
 #include "mirror/class.h"
 #include "mirror/class-inl.h"
 #include "mirror/object-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 
 extern "C" JNIEXPORT jint JNICALL Java_Main_vmArrayBaseOffset(JNIEnv* env, jclass, jobject classObj) {
   ScopedObjectAccess soa(env);
-  mirror::Class* klass = soa.Decode<mirror::Class*>(classObj);
+  ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(classObj);
   return mirror::Array::DataOffset(
       Primitive::ComponentSize(klass->GetComponentType()->GetPrimitiveType())).Int32Value();
 }
 
 extern "C" JNIEXPORT jint JNICALL Java_Main_vmArrayIndexScale(JNIEnv* env, jclass, jobject classObj) {
   ScopedObjectAccess soa(env);
-  mirror::Class* klass = soa.Decode<mirror::Class*>(classObj);
+  ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(classObj);
   return Primitive::ComponentSize(klass->GetComponentType()->GetPrimitiveType());
 }
 
diff --git a/test/117-nopatchoat/nopatchoat.cc b/test/117-nopatchoat/nopatchoat.cc
index c6a2e9a..56c0dcd 100644
--- a/test/117-nopatchoat/nopatchoat.cc
+++ b/test/117-nopatchoat/nopatchoat.cc
@@ -20,7 +20,7 @@
 #include "gc/space/image_space.h"
 #include "mirror/class-inl.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread.h"
 
 namespace art {
@@ -29,7 +29,7 @@
  public:
   static const OatFile::OatDexFile* getOatDexFile(jclass cls) {
     ScopedObjectAccess soa(Thread::Current());
-    mirror::Class* klass = soa.Decode<mirror::Class*>(cls);
+    ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(cls);
     const DexFile& dex_file = klass->GetDexFile();
     return dex_file.GetOatDexFile();
   }
diff --git a/test/1337-gc-coverage/gc_coverage.cc b/test/1337-gc-coverage/gc_coverage.cc
index 7cf30bd..1e60bd9 100644
--- a/test/1337-gc-coverage/gc_coverage.cc
+++ b/test/1337-gc-coverage/gc_coverage.cc
@@ -17,7 +17,7 @@
 #include "gc/heap.h"
 #include "jni.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 
 namespace art {
@@ -43,7 +43,7 @@
 
 extern "C" JNIEXPORT jlong JNICALL Java_Main_objectAddress(JNIEnv* env, jclass, jobject object) {
   ScopedObjectAccess soa(env);
-  return reinterpret_cast<jlong>(soa.Decode<mirror::Object*>(object));
+  return reinterpret_cast<jlong>(soa.Decode<mirror::Object>(object).Decode());
 }
 
 extern "C" JNIEXPORT jboolean JNICALL Java_Main_supportCollectorTransition(JNIEnv*, jclass) {
diff --git a/test/148-multithread-gc-annotations/gc_coverage.cc b/test/148-multithread-gc-annotations/gc_coverage.cc
index 263eefd..cb12df4 100644
--- a/test/148-multithread-gc-annotations/gc_coverage.cc
+++ b/test/148-multithread-gc-annotations/gc_coverage.cc
@@ -17,7 +17,7 @@
 #include "gc/heap.h"
 #include "jni.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 
 namespace art {
@@ -35,7 +35,7 @@
 
 extern "C" JNIEXPORT jlong JNICALL Java_MovingGCThread_objectAddress(JNIEnv* env, jclass, jobject object) {
   ScopedObjectAccess soa(env);
-  return reinterpret_cast<jlong>(soa.Decode<mirror::Object*>(object));
+  return reinterpret_cast<jlong>(soa.Decode<mirror::Object>(object).Decode());
 }
 
 }  // namespace
diff --git a/test/454-get-vreg/get_vreg_jni.cc b/test/454-get-vreg/get_vreg_jni.cc
index 5762754..9058af4 100644
--- a/test/454-get-vreg/get_vreg_jni.cc
+++ b/test/454-get-vreg/get_vreg_jni.cc
@@ -18,7 +18,7 @@
 #include "art_method-inl.h"
 #include "jni.h"
 #include "oat_quick_method_header.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "stack.h"
 #include "thread.h"
 
@@ -123,7 +123,7 @@
 extern "C" JNIEXPORT jint JNICALL Java_Main_doNativeCall(JNIEnv*, jobject value) {
   ScopedObjectAccess soa(Thread::Current());
   std::unique_ptr<Context> context(Context::Create());
-  TestVisitor visitor(soa.Self(), context.get(), soa.Decode<mirror::Object*>(value));
+  TestVisitor visitor(soa.Self(), context.get(), soa.Decode<mirror::Object>(value).Decode());
   visitor.WalkStack();
   return visitor.found_method_index_;
 }
diff --git a/test/457-regs/regs_jni.cc b/test/457-regs/regs_jni.cc
index 08db775..f62a77d 100644
--- a/test/457-regs/regs_jni.cc
+++ b/test/457-regs/regs_jni.cc
@@ -18,7 +18,7 @@
 #include "art_method-inl.h"
 #include "jni.h"
 #include "oat_quick_method_header.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "stack.h"
 #include "thread.h"
 
@@ -139,7 +139,7 @@
     JNIEnv*, jclass value ATTRIBUTE_UNUSED, jobject main, jint int_value, jfloat float_value) {
   ScopedObjectAccess soa(Thread::Current());
   std::unique_ptr<Context> context(Context::Create());
-  CHECK(soa.Decode<mirror::Object*>(main) == nullptr);
+  CHECK(soa.Decode<mirror::Object>(main) == nullptr);
   CHECK_EQ(int_value, 0);
   int32_t cast = bit_cast<int32_t, float>(float_value);
   CHECK_EQ(cast, 0);
diff --git a/test/461-get-reference-vreg/get_reference_vreg_jni.cc b/test/461-get-reference-vreg/get_reference_vreg_jni.cc
index 8122c6d..7b1ab9c 100644
--- a/test/461-get-reference-vreg/get_reference_vreg_jni.cc
+++ b/test/461-get-reference-vreg/get_reference_vreg_jni.cc
@@ -17,7 +17,7 @@
 #include "arch/context.h"
 #include "art_method-inl.h"
 #include "jni.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "stack.h"
 #include "thread.h"
 
@@ -70,7 +70,7 @@
 extern "C" JNIEXPORT jint JNICALL Java_Main_doNativeCallRef(JNIEnv*, jobject value) {
   ScopedObjectAccess soa(Thread::Current());
   std::unique_ptr<Context> context(Context::Create());
-  TestVisitor visitor(soa.Self(), context.get(), soa.Decode<mirror::Object*>(value));
+  TestVisitor visitor(soa.Self(), context.get(), soa.Decode<mirror::Object>(value).Decode());
   visitor.WalkStack();
   return visitor.found_method_index_;
 }
diff --git a/test/466-get-live-vreg/get_live_vreg_jni.cc b/test/466-get-live-vreg/get_live_vreg_jni.cc
index 3618b4f..d3a033b 100644
--- a/test/466-get-live-vreg/get_live_vreg_jni.cc
+++ b/test/466-get-live-vreg/get_live_vreg_jni.cc
@@ -18,7 +18,7 @@
 #include "art_method-inl.h"
 #include "jni.h"
 #include "oat_quick_method_header.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "stack.h"
 #include "thread.h"
 
diff --git a/test/497-inlining-and-class-loader/clear_dex_cache.cc b/test/497-inlining-and-class-loader/clear_dex_cache.cc
index 1597c4a..3f2df29 100644
--- a/test/497-inlining-and-class-loader/clear_dex_cache.cc
+++ b/test/497-inlining-and-class-loader/clear_dex_cache.cc
@@ -17,7 +17,7 @@
 #include "art_method-inl.h"
 #include "base/enums.h"
 #include "jni.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "stack.h"
 #include "thread.h"
 
@@ -29,7 +29,7 @@
                                                                     jclass,
                                                                     jclass cls) {
   ScopedObjectAccess soa(Thread::Current());
-  mirror::DexCache* dex_cache = soa.Decode<mirror::Class*>(cls)->GetDexCache();
+  mirror::DexCache* dex_cache = soa.Decode<mirror::Class>(cls)->GetDexCache();
   size_t num_methods = dex_cache->NumResolvedMethods();
   ArtMethod** methods = dex_cache->GetResolvedMethods();
   CHECK_EQ(num_methods != 0u, methods != nullptr);
@@ -43,7 +43,7 @@
     array = env->NewLongArray(num_methods);
   }
   CHECK(array != nullptr);
-  mirror::PointerArray* pointer_array = soa.Decode<mirror::PointerArray*>(array);
+  mirror::PointerArray* pointer_array = soa.Decode<mirror::PointerArray>(array).Decode();
   for (size_t i = 0; i != num_methods; ++i) {
     ArtMethod* method = mirror::DexCache::GetElementPtrSize(methods, i, kRuntimePointerSize);
     pointer_array->SetElementPtrSize(i, method, kRuntimePointerSize);
@@ -54,11 +54,11 @@
 extern "C" JNIEXPORT void JNICALL Java_Main_restoreResolvedMethods(
     JNIEnv*, jclass, jclass cls, jobject old_cache) {
   ScopedObjectAccess soa(Thread::Current());
-  mirror::DexCache* dex_cache = soa.Decode<mirror::Class*>(cls)->GetDexCache();
+  mirror::DexCache* dex_cache = soa.Decode<mirror::Class>(cls)->GetDexCache();
   size_t num_methods = dex_cache->NumResolvedMethods();
-  ArtMethod** methods = soa.Decode<mirror::Class*>(cls)->GetDexCache()->GetResolvedMethods();
+  ArtMethod** methods = soa.Decode<mirror::Class>(cls)->GetDexCache()->GetResolvedMethods();
   CHECK_EQ(num_methods != 0u, methods != nullptr);
-  mirror::PointerArray* old = soa.Decode<mirror::PointerArray*>(old_cache);
+  ObjPtr<mirror::PointerArray> old = soa.Decode<mirror::PointerArray>(old_cache);
   CHECK_EQ(methods != nullptr, old != nullptr);
   CHECK_EQ(num_methods, static_cast<size_t>(old->GetLength()));
   for (size_t i = 0; i != num_methods; ++i) {
diff --git a/test/543-env-long-ref/env_long_ref.cc b/test/543-env-long-ref/env_long_ref.cc
index 557def6..cd127ef 100644
--- a/test/543-env-long-ref/env_long_ref.cc
+++ b/test/543-env-long-ref/env_long_ref.cc
@@ -17,7 +17,7 @@
 #include "arch/context.h"
 #include "art_method-inl.h"
 #include "jni.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "stack.h"
 #include "thread.h"
 
@@ -43,7 +43,7 @@
       uint32_t value = 0;
       CHECK(GetVReg(m, 1, kReferenceVReg, &value));
       CHECK_EQ(reinterpret_cast<mirror::Object*>(value),
-               soa_.Decode<mirror::Object*>(expected_value_));
+               soa_.Decode<mirror::Object>(expected_value_).Decode());
     }
     return true;
   }
diff --git a/test/566-polymorphic-inlining/polymorphic_inline.cc b/test/566-polymorphic-inlining/polymorphic_inline.cc
index 89293cc..00c1b02 100644
--- a/test/566-polymorphic-inlining/polymorphic_inline.cc
+++ b/test/566-polymorphic-inlining/polymorphic_inline.cc
@@ -20,14 +20,14 @@
 #include "jit/jit_code_cache.h"
 #include "jit/profiling_info.h"
 #include "oat_quick_method_header.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "stack_map.h"
 
 namespace art {
 
 static void do_checks(jclass cls, const char* method_name) {
   ScopedObjectAccess soa(Thread::Current());
-  mirror::Class* klass = soa.Decode<mirror::Class*>(cls);
+  ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(cls);
   jit::Jit* jit = Runtime::Current()->GetJit();
   jit::JitCodeCache* code_cache = jit->GetCodeCache();
   ArtMethod* method = klass->FindDeclaredDirectMethodByName(method_name, kRuntimePointerSize);
@@ -53,7 +53,7 @@
 
 static void allocate_profiling_info(jclass cls, const char* method_name) {
   ScopedObjectAccess soa(Thread::Current());
-  mirror::Class* klass = soa.Decode<mirror::Class*>(cls);
+  ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(cls);
   ArtMethod* method = klass->FindDeclaredDirectMethodByName(method_name, kRuntimePointerSize);
   ProfilingInfo::Create(soa.Self(), method, /* retry_allocation */ true);
 }
diff --git a/test/570-checker-osr/osr.cc b/test/570-checker-osr/osr.cc
index adda3cc..50e8382 100644
--- a/test/570-checker-osr/osr.cc
+++ b/test/570-checker-osr/osr.cc
@@ -19,7 +19,7 @@
 #include "jit/jit_code_cache.h"
 #include "jit/profiling_info.h"
 #include "oat_quick_method_header.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "ScopedUtfChars.h"
 #include "stack_map.h"
 
diff --git a/test/595-profile-saving/profile-saving.cc b/test/595-profile-saving/profile-saving.cc
index a265dce..bf3d812 100644
--- a/test/595-profile-saving/profile-saving.cc
+++ b/test/595-profile-saving/profile-saving.cc
@@ -24,7 +24,7 @@
 #include "mirror/class-inl.h"
 #include "oat_file_assistant.h"
 #include "oat_file_manager.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "ScopedUtfChars.h"
 #include "thread.h"
 
@@ -74,7 +74,7 @@
   ScopedUtfChars filename_chars(env, filename);
   CHECK(filename_chars.c_str() != nullptr);
   ScopedObjectAccess soa(Thread::Current());
-  const DexFile* dex_file = soa.Decode<mirror::Class*>(cls)->GetDexCache()->GetDexFile();
+  const DexFile* dex_file = soa.Decode<mirror::Class>(cls)->GetDexCache()->GetDexFile();
   return ProfileSaver::HasSeenMethod(std::string(filename_chars.c_str()),
                                      dex_file,
                                      static_cast<uint16_t>(method_index));
diff --git a/test/596-app-images/app_images.cc b/test/596-app-images/app_images.cc
index a5bbf5f..78cc3fd 100644
--- a/test/596-app-images/app_images.cc
+++ b/test/596-app-images/app_images.cc
@@ -26,7 +26,7 @@
 #include "jni.h"
 #include "mirror/class.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 
@@ -48,13 +48,13 @@
 
 extern "C" JNIEXPORT jboolean JNICALL Java_Main_checkAppImageContains(JNIEnv*, jclass, jclass c) {
   ScopedObjectAccess soa(Thread::Current());
-  mirror::Class* klass_ptr = soa.Decode<mirror::Class*>(c);
+  ObjPtr<mirror::Class> klass_ptr = soa.Decode<mirror::Class>(c);
   for (auto* space : Runtime::Current()->GetHeap()->GetContinuousSpaces()) {
     if (space->IsImageSpace()) {
       auto* image_space = space->AsImageSpace();
       const auto& image_header = image_space->GetImageHeader();
       if (image_header.IsAppImage()) {
-        if (image_space->HasAddress(klass_ptr)) {
+        if (image_space->HasAddress(klass_ptr.Decode())) {
           return JNI_TRUE;
         }
       }
diff --git a/test/common/runtime_state.cc b/test/common/runtime_state.cc
index fd1ba02..4248148 100644
--- a/test/common/runtime_state.cc
+++ b/test/common/runtime_state.cc
@@ -24,7 +24,7 @@
 #include "mirror/class-inl.h"
 #include "oat_quick_method_header.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "ScopedUtfChars.h"
 #include "thread-inl.h"
 
@@ -35,7 +35,7 @@
 extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasOatFile(JNIEnv* env, jclass cls) {
   ScopedObjectAccess soa(env);
 
-  mirror::Class* klass = soa.Decode<mirror::Class*>(cls);
+  ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(cls);
   const DexFile& dex_file = klass->GetDexFile();
   const OatFile::OatDexFile* oat_dex_file = dex_file.GetOatDexFile();
   return (oat_dex_file != nullptr) ? JNI_TRUE : JNI_FALSE;
@@ -75,7 +75,7 @@
 extern "C" JNIEXPORT jboolean JNICALL Java_Main_compiledWithOptimizing(JNIEnv* env, jclass cls) {
   ScopedObjectAccess soa(env);
 
-  mirror::Class* klass = soa.Decode<mirror::Class*>(cls);
+  ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(cls);
   const DexFile& dex_file = klass->GetDexFile();
   const OatFile::OatDexFile* oat_dex_file = dex_file.GetOatDexFile();
   if (oat_dex_file == nullptr) {
@@ -134,7 +134,7 @@
 
     ScopedUtfChars chars(env, method_name);
     CHECK(chars.c_str() != nullptr);
-    method = soa.Decode<mirror::Class*>(cls)->FindDeclaredDirectMethodByName(
+    method = soa.Decode<mirror::Class>(cls)->FindDeclaredDirectMethodByName(
         chars.c_str(), kRuntimePointerSize);
   }
 
diff --git a/test/common/stack_inspect.cc b/test/common/stack_inspect.cc
index 85ea1c8..d2aacf0 100644
--- a/test/common/stack_inspect.cc
+++ b/test/common/stack_inspect.cc
@@ -21,7 +21,7 @@
 #include "mirror/class-inl.h"
 #include "nth_caller_visitor.h"
 #include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
 #include "stack.h"
 #include "thread-inl.h"
 
@@ -62,7 +62,7 @@
 static jboolean IsManaged(JNIEnv* env, jclass cls, size_t level) {
   ScopedObjectAccess soa(env);
 
-  mirror::Class* klass = soa.Decode<mirror::Class*>(cls);
+  ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(cls);
   const DexFile& dex_file = klass->GetDexFile();
   const OatFile::OatDexFile* oat_dex_file = dex_file.GetOatDexFile();
   if (oat_dex_file == nullptr) {