Merge "Combine JDWP location events"
diff --git a/Android.mk b/Android.mk
index fe631d9..2196d59 100644
--- a/Android.mk
+++ b/Android.mk
@@ -150,9 +150,22 @@
 ########################################################################
 # host test targets
 
+.PHONY: test-art-host-vixl
+ifneq ($(BUILD_HOST_64bit),)
+test-art-host-vixl: $(ANDROID_HOST_OUT)/bin/cctest_vixl
+	$(ANDROID_HOST_OUT)/bin/cctest_vixl --run_all
+	@echo vixl PASSED
+
+else
+# vixl test needs 64b host.
+test-art-host-vixl:
+	@echo vixl test only runnable with 64b host build.
+
+endif
+
 # "mm test-art-host" to build and run all host tests
 .PHONY: test-art-host
-test-art-host: test-art-host-gtest test-art-host-oat test-art-host-run-test
+test-art-host: test-art-host-gtest test-art-host-oat test-art-host-run-test test-art-host-vixl
 	@echo test-art-host PASSED
 
 .PHONY: test-art-host-interpreter
diff --git a/build/Android.common.mk b/build/Android.common.mk
index 6135571..188ddb5 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -110,6 +110,12 @@
 DALVIKVM_FLAGS := -Xcompiler-option --compiler-backend=Optimizing
 endif
 
+#
+# Used to change the default GC. Valid values are CMS, SS, GSS. The default is CMS.
+#
+ART_DEFAULT_GC_TYPE ?= CMS
+ART_DEFAULT_GC_TYPE_CFLAGS := -DART_DEFAULT_GC_TYPE_IS_$(ART_DEFAULT_GC_TYPE)
+
 LLVM_ROOT_PATH := external/llvm
 # Don't fail a dalvik minimal host build.
 -include $(LLVM_ROOT_PATH)/llvm.mk
@@ -237,6 +243,7 @@
 
 ART_HOST_CFLAGS := $(art_cflags) -DANDROID_SMP=1 -DART_BASE_ADDRESS=$(LIBART_IMG_HOST_BASE_ADDRESS)
 ART_HOST_CFLAGS += -DART_DEFAULT_INSTRUCTION_SET_FEATURES=default
+ART_HOST_CFLAGS += $(ART_DEFAULT_GC_TYPE_CFLAGS)
 
 ART_TARGET_CFLAGS := $(art_cflags) -DART_TARGET -DART_BASE_ADDRESS=$(LIBART_IMG_TARGET_BASE_ADDRESS)
 ifeq ($(TARGET_CPU_SMP),true)
@@ -244,6 +251,7 @@
 else
   ART_TARGET_CFLAGS += -DANDROID_SMP=0
 endif
+ART_TARGET_CFLAGS += $(ART_DEFAULT_GC_TYPE_CFLAGS)
 
 # DEX2OAT_TARGET_INSTRUCTION_SET_FEATURES is set in ../build/core/dex_preopt.mk based on
 # the TARGET_CPU_VARIANT
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index d4e2cbb..406c2a1 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -47,6 +47,7 @@
 	runtime/gc/space/rosalloc_space_random_test.cc \
 	runtime/gc/space/large_object_space_test.cc \
 	runtime/gtest_test.cc \
+	runtime/handle_scope_test.cc \
 	runtime/indenter_test.cc \
 	runtime/indirect_reference_table_test.cc \
 	runtime/instruction_set_test.cc \
@@ -62,8 +63,7 @@
 	runtime/utils_test.cc \
 	runtime/verifier/method_verifier_test.cc \
 	runtime/verifier/reg_type_test.cc \
-	runtime/zip_archive_test.cc \
-	runtime/stack_indirect_reference_table_test.cc
+	runtime/zip_archive_test.cc
 
 COMPILER_GTEST_COMMON_SRC_FILES := \
 	runtime/jni_internal_test.cc \
@@ -78,6 +78,7 @@
 	compiler/oat_test.cc \
 	compiler/optimizing/codegen_test.cc \
 	compiler/optimizing/dominator_test.cc \
+	compiler/optimizing/find_loops_test.cc \
 	compiler/optimizing/liveness_test.cc \
 	compiler/optimizing/pretty_printer_test.cc \
 	compiler/optimizing/ssa_test.cc \
diff --git a/compiler/Android.mk b/compiler/Android.mk
index 1b70d59..8592aaa 100644
--- a/compiler/Android.mk
+++ b/compiler/Android.mk
@@ -82,6 +82,7 @@
 	optimizing/code_generator.cc \
 	optimizing/code_generator_arm.cc \
 	optimizing/code_generator_x86.cc \
+	optimizing/graph_visualizer.cc \
 	optimizing/nodes.cc \
 	optimizing/optimizing_compiler.cc \
 	optimizing/ssa_builder.cc \
diff --git a/compiler/common_compiler_test.h b/compiler/common_compiler_test.h
index 8bba84a..586c442 100644
--- a/compiler/common_compiler_test.h
+++ b/compiler/common_compiler_test.h
@@ -134,9 +134,6 @@
  public:
   // Create an OatMethod based on pointers (for unit tests).
   OatFile::OatMethod CreateOatMethod(const void* code,
-                                     const size_t frame_size_in_bytes,
-                                     const uint32_t core_spill_mask,
-                                     const uint32_t fp_spill_mask,
                                      const uint8_t* gc_map) {
     CHECK(code != nullptr);
     const byte* base;
@@ -154,9 +151,6 @@
     }
     return OatFile::OatMethod(base,
                               code_offset,
-                              frame_size_in_bytes,
-                              core_spill_mask,
-                              fp_spill_mask,
                               gc_map_offset);
   }
 
@@ -179,11 +173,14 @@
         CHECK_NE(0u, code_size);
         const std::vector<uint8_t>& vmap_table = compiled_method->GetVmapTable();
         uint32_t vmap_table_offset = vmap_table.empty() ? 0u
-            : sizeof(OatMethodHeader) + vmap_table.size();
+            : sizeof(OatQuickMethodHeader) + vmap_table.size();
         const std::vector<uint8_t>& mapping_table = compiled_method->GetMappingTable();
         uint32_t mapping_table_offset = mapping_table.empty() ? 0u
-            : sizeof(OatMethodHeader) + vmap_table.size() + mapping_table.size();
-        OatMethodHeader method_header(vmap_table_offset, mapping_table_offset, code_size);
+            : sizeof(OatQuickMethodHeader) + vmap_table.size() + mapping_table.size();
+        OatQuickMethodHeader method_header(mapping_table_offset, vmap_table_offset,
+                                           compiled_method->GetFrameSizeInBytes(),
+                                           compiled_method->GetCoreSpillMask(),
+                                           compiled_method->GetFpSpillMask(), code_size);
 
         header_code_and_maps_chunks_.push_back(std::vector<uint8_t>());
         std::vector<uint8_t>* chunk = &header_code_and_maps_chunks_.back();
@@ -207,11 +204,7 @@
       const void* method_code = CompiledMethod::CodePointer(code_ptr,
                                                             compiled_method->GetInstructionSet());
       LOG(INFO) << "MakeExecutable " << PrettyMethod(method) << " code=" << method_code;
-      OatFile::OatMethod oat_method = CreateOatMethod(method_code,
-                                                      compiled_method->GetFrameSizeInBytes(),
-                                                      compiled_method->GetCoreSpillMask(),
-                                                      compiled_method->GetFpSpillMask(),
-                                                      nullptr);
+      OatFile::OatMethod oat_method = CreateOatMethod(method_code, nullptr);
       oat_method.LinkMethod(method);
       method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
     } else {
@@ -220,28 +213,13 @@
       if (!method->IsNative()) {
         const void* method_code = kUsePortableCompiler ? GetPortableToInterpreterBridge()
                                                        : GetQuickToInterpreterBridge();
-        OatFile::OatMethod oat_method = CreateOatMethod(method_code,
-                                                        kStackAlignment,
-                                                        0,
-                                                        0,
-                                                        nullptr);
+        OatFile::OatMethod oat_method = CreateOatMethod(method_code, nullptr);
         oat_method.LinkMethod(method);
         method->SetEntryPointFromInterpreter(interpreter::artInterpreterToInterpreterBridge);
       } else {
         const void* method_code = GetQuickGenericJniTrampoline();
-        mirror::ArtMethod* callee_save_method = runtime_->GetCalleeSaveMethod(Runtime::kRefsAndArgs);
 
-        // Compute Sirt size, as Sirt goes into frame
-        MethodHelper mh(method);
-        uint32_t sirt_refs = mh.GetNumberOfReferenceArgsWithoutReceiver() + 1;
-        uint32_t sirt_size = StackIndirectReferenceTable::SizeOf(sirt_refs);
-
-        OatFile::OatMethod oat_method = CreateOatMethod(method_code,
-                                                        callee_save_method->GetFrameSizeInBytes() +
-                                                            sirt_size,
-                                                        callee_save_method->GetCoreSpillMask(),
-                                                        callee_save_method->GetFpSpillMask(),
-                                                        nullptr);
+        OatFile::OatMethod oat_method = CreateOatMethod(method_code, nullptr);
         oat_method.LinkMethod(method);
         method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
       }
@@ -279,7 +257,8 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     std::string class_descriptor(DotToDescriptor(class_name));
     Thread* self = Thread::Current();
-    SirtRef<mirror::ClassLoader> loader(self, class_loader);
+    StackHandleScope<1> hs(self);
+    Handle<mirror::ClassLoader> loader(hs.NewHandle(class_loader));
     mirror::Class* klass = class_linker_->FindClass(self, class_descriptor.c_str(), loader);
     CHECK(klass != nullptr) << "Class not found " << class_name;
     for (size_t i = 0; i < klass->NumDirectMethods(); i++) {
@@ -323,11 +302,12 @@
       compiler_options_->SetCompilerFilter(CompilerOptions::kInterpretOnly);
 #endif
 
+      runtime_->SetInstructionSet(instruction_set);
       for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
         Runtime::CalleeSaveType type = Runtime::CalleeSaveType(i);
         if (!runtime_->HasCalleeSaveMethod(type)) {
           runtime_->SetCalleeSaveMethod(
-              runtime_->CreateCalleeSaveMethod(instruction_set, type), type);
+              runtime_->CreateCalleeSaveMethod(type), type);
         }
       }
 
@@ -373,7 +353,8 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     std::string class_descriptor(DotToDescriptor(class_name));
     Thread* self = Thread::Current();
-    SirtRef<mirror::ClassLoader> loader(self, class_loader);
+    StackHandleScope<1> hs(self);
+    Handle<mirror::ClassLoader> loader(hs.NewHandle(class_loader));
     mirror::Class* klass = class_linker_->FindClass(self, class_descriptor.c_str(), loader);
     CHECK(klass != nullptr) << "Class not found " << class_name;
     for (size_t i = 0; i < klass->NumDirectMethods(); i++) {
@@ -393,7 +374,7 @@
     timings.EndSplit();
   }
 
-  void CompileDirectMethod(SirtRef<mirror::ClassLoader>& class_loader, const char* class_name,
+  void CompileDirectMethod(Handle<mirror::ClassLoader>& class_loader, const char* class_name,
                            const char* method_name, const char* signature)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     std::string class_descriptor(DotToDescriptor(class_name));
@@ -406,7 +387,7 @@
     CompileMethod(method);
   }
 
-  void CompileVirtualMethod(SirtRef<mirror::ClassLoader>& class_loader, const char* class_name,
+  void CompileVirtualMethod(Handle<mirror::ClassLoader>& class_loader, const char* class_name,
                             const char* method_name, const char* signature)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     std::string class_descriptor(DotToDescriptor(class_name));
diff --git a/compiler/compilers.h b/compiler/compilers.h
index 3ca78c9..e523d64 100644
--- a/compiler/compilers.h
+++ b/compiler/compilers.h
@@ -73,7 +73,7 @@
 
 class OptimizingCompiler FINAL : public QuickCompiler {
  public:
-  explicit OptimizingCompiler(CompilerDriver* driver) : QuickCompiler(driver) { }
+  explicit OptimizingCompiler(CompilerDriver* driver);
 
   CompiledMethod* Compile(const DexFile::CodeItem* code_item,
                           uint32_t access_flags,
@@ -92,6 +92,8 @@
                              const DexFile& dex_file) const;
 
  private:
+  UniquePtr<std::ostream> visualizer_output_;
+
   DISALLOW_COPY_AND_ASSIGN(OptimizingCompiler);
 };
 
diff --git a/compiler/dex/mir_field_info.cc b/compiler/dex/mir_field_info.cc
index 7c630e8..98866d9 100644
--- a/compiler/dex/mir_field_info.cc
+++ b/compiler/dex/mir_field_info.cc
@@ -21,10 +21,10 @@
 #include "base/logging.h"
 #include "driver/compiler_driver.h"
 #include "driver/compiler_driver-inl.h"
-#include "mirror/class_loader.h"  // Only to allow casts in SirtRef<ClassLoader>.
-#include "mirror/dex_cache.h"     // Only to allow casts in SirtRef<DexCache>.
+#include "mirror/class_loader.h"  // Only to allow casts in Handle<ClassLoader>.
+#include "mirror/dex_cache.h"     // Only to allow casts in Handle<DexCache>.
 #include "scoped_thread_state_change.h"
-#include "sirt_ref-inl.h"
+#include "handle_scope-inl.h"
 
 namespace art {
 
@@ -43,11 +43,12 @@
   // We're going to resolve fields and check access in a tight loop. It's better to hold
   // the lock and needed references once than re-acquiring them again and again.
   ScopedObjectAccess soa(Thread::Current());
-  SirtRef<mirror::DexCache> dex_cache(soa.Self(), compiler_driver->GetDexCache(mUnit));
-  SirtRef<mirror::ClassLoader> class_loader(soa.Self(),
-      compiler_driver->GetClassLoader(soa, mUnit));
-  SirtRef<mirror::Class> referrer_class(soa.Self(),
-      compiler_driver->ResolveCompilingMethodsClass(soa, dex_cache, class_loader, mUnit));
+  StackHandleScope<3> hs(soa.Self());
+  Handle<mirror::DexCache> dex_cache(hs.NewHandle(compiler_driver->GetDexCache(mUnit)));
+  Handle<mirror::ClassLoader> class_loader(
+      hs.NewHandle(compiler_driver->GetClassLoader(soa, mUnit)));
+  Handle<mirror::Class> referrer_class(hs.NewHandle(
+      compiler_driver->ResolveCompilingMethodsClass(soa, dex_cache, class_loader, mUnit)));
   // Even if the referrer class is unresolved (i.e. we're compiling a method without class
   // definition) we still want to resolve fields and record all available info.
 
@@ -63,7 +64,7 @@
     bool is_volatile = compiler_driver->IsFieldVolatile(resolved_field);
 
     std::pair<bool, bool> fast_path = compiler_driver->IsFastInstanceField(
-        dex_cache.get(), referrer_class.get(), resolved_field, field_idx, &it->field_offset_);
+        dex_cache.Get(), referrer_class.Get(), resolved_field, field_idx, &it->field_offset_);
     it->flags_ = 0u |  // Without kFlagIsStatic.
         (is_volatile ? kFlagIsVolatile : 0u) |
         (fast_path.first ? kFlagFastGet : 0u) |
@@ -89,11 +90,12 @@
   // We're going to resolve fields and check access in a tight loop. It's better to hold
   // the lock and needed references once than re-acquiring them again and again.
   ScopedObjectAccess soa(Thread::Current());
-  SirtRef<mirror::DexCache> dex_cache(soa.Self(), compiler_driver->GetDexCache(mUnit));
-  SirtRef<mirror::ClassLoader> class_loader(soa.Self(),
-      compiler_driver->GetClassLoader(soa, mUnit));
-  SirtRef<mirror::Class> referrer_class(soa.Self(),
-      compiler_driver->ResolveCompilingMethodsClass(soa, dex_cache, class_loader, mUnit));
+  StackHandleScope<3> hs(soa.Self());
+  Handle<mirror::DexCache> dex_cache(hs.NewHandle(compiler_driver->GetDexCache(mUnit)));
+  Handle<mirror::ClassLoader> class_loader(
+      hs.NewHandle(compiler_driver->GetClassLoader(soa, mUnit)));
+  Handle<mirror::Class> referrer_class(hs.NewHandle(
+      compiler_driver->ResolveCompilingMethodsClass(soa, dex_cache, class_loader, mUnit)));
   // Even if the referrer class is unresolved (i.e. we're compiling a method without class
   // definition) we still want to resolve fields and record all available info.
 
@@ -110,7 +112,7 @@
 
     bool is_referrers_class, is_initialized;
     std::pair<bool, bool> fast_path = compiler_driver->IsFastStaticField(
-        dex_cache.get(), referrer_class.get(), resolved_field, field_idx, &it->field_offset_,
+        dex_cache.Get(), referrer_class.Get(), resolved_field, field_idx, &it->field_offset_,
         &it->storage_index_, &is_referrers_class, &is_initialized);
     it->flags_ = kFlagIsStatic |
         (is_volatile ? kFlagIsVolatile : 0u) |
diff --git a/compiler/dex/mir_method_info.cc b/compiler/dex/mir_method_info.cc
index 2c33ef1..cc2bd95 100644
--- a/compiler/dex/mir_method_info.cc
+++ b/compiler/dex/mir_method_info.cc
@@ -19,10 +19,10 @@
 #include "driver/compiler_driver.h"
 #include "driver/dex_compilation_unit.h"
 #include "driver/compiler_driver-inl.h"
-#include "mirror/class_loader.h"  // Only to allow casts in SirtRef<ClassLoader>.
-#include "mirror/dex_cache.h"     // Only to allow casts in SirtRef<DexCache>.
+#include "mirror/class_loader.h"  // Only to allow casts in Handle<ClassLoader>.
+#include "mirror/dex_cache.h"     // Only to allow casts in Handle<DexCache>.
 #include "scoped_thread_state_change.h"
-#include "sirt_ref.h"
+#include "handle_scope-inl.h"
 
 namespace art {
 
@@ -45,11 +45,12 @@
   // We're going to resolve methods and check access in a tight loop. It's better to hold
   // the lock and needed references once than re-acquiring them again and again.
   ScopedObjectAccess soa(Thread::Current());
-  SirtRef<mirror::DexCache> dex_cache(soa.Self(), compiler_driver->GetDexCache(mUnit));
-  SirtRef<mirror::ClassLoader> class_loader(soa.Self(),
-      compiler_driver->GetClassLoader(soa, mUnit));
-  SirtRef<mirror::Class> referrer_class(soa.Self(),
-      compiler_driver->ResolveCompilingMethodsClass(soa, dex_cache, class_loader, mUnit));
+  StackHandleScope<3> hs(soa.Self());
+  Handle<mirror::DexCache> dex_cache(hs.NewHandle(compiler_driver->GetDexCache(mUnit)));
+  Handle<mirror::ClassLoader> class_loader(
+      hs.NewHandle(compiler_driver->GetClassLoader(soa, mUnit)));
+  Handle<mirror::Class> referrer_class(hs.NewHandle(
+      compiler_driver->ResolveCompilingMethodsClass(soa, dex_cache, class_loader, mUnit)));
   // Even if the referrer class is unresolved (i.e. we're compiling a method without class
   // definition) we still want to resolve methods and record all available info.
 
@@ -73,10 +74,10 @@
 
     MethodReference target_method(mUnit->GetDexFile(), it->MethodIndex());
     int fast_path_flags = compiler_driver->IsFastInvoke(
-        soa, dex_cache, class_loader, mUnit, referrer_class.get(), resolved_method, &invoke_type,
+        soa, dex_cache, class_loader, mUnit, referrer_class.Get(), resolved_method, &invoke_type,
         &target_method, devirt_target, &it->direct_code_, &it->direct_method_);
     bool needs_clinit =
-        compiler_driver->NeedsClassInitialization(referrer_class.get(), resolved_method);
+        compiler_driver->NeedsClassInitialization(referrer_class.Get(), resolved_method);
     uint16_t other_flags = it->flags_ &
         ~(kFlagFastPath | kFlagNeedsClassInitialization | (kInvokeTypeMask << kBitSharpTypeBegin));
     it->flags_ = other_flags |
diff --git a/compiler/dex/quick/arm/call_arm.cc b/compiler/dex/quick/arm/call_arm.cc
index d3477c9..435242a 100644
--- a/compiler/dex/quick/arm/call_arm.cc
+++ b/compiler/dex/quick/arm/call_arm.cc
@@ -268,6 +268,7 @@
     MarkPossibleNullPointerException(opt_flags);
     LoadConstantNoClobber(rs_r3, 0);
     LIR* slow_unlock_branch = OpCmpBranch(kCondNe, rs_r1, rs_r2, NULL);
+    GenMemBarrier(kStoreLoad);
     Store32Disp(rs_r0, mirror::Object::MonitorOffset().Int32Value(), rs_r3);
     LIR* unlock_success_branch = OpUnconditionalBranch(NULL);
 
@@ -285,7 +286,6 @@
 
     LIR* success_target = NewLIR0(kPseudoTargetLabel);
     unlock_success_branch->target = success_target;
-    GenMemBarrier(kStoreLoad);
   } else {
     // Explicit null-check as slow-path is entered using an IT.
     GenNullCheck(rs_r0, opt_flags);
@@ -295,7 +295,8 @@
     LoadConstantNoClobber(rs_r3, 0);
     // Is lock unheld on lock or held by us (==thread_id) on unlock?
     OpRegReg(kOpCmp, rs_r1, rs_r2);
-    LIR* it = OpIT(kCondEq, "EE");
+    LIR* it = OpIT(kCondEq, "TEE");
+    GenMemBarrier(kStoreLoad);
     Store32Disp/*eq*/(rs_r0, mirror::Object::MonitorOffset().Int32Value(), rs_r3);
     // Go expensive route - UnlockObjectFromCode(obj);
     LoadWordDisp/*ne*/(rs_rARM_SELF, QUICK_ENTRYPOINT_OFFSET(4, pUnlockObject).Int32Value(),
@@ -304,7 +305,6 @@
     LIR* call_inst = OpReg(kOpBlx/*ne*/, rs_rARM_LR);
     OpEndIT(it);
     MarkSafepointPC(call_inst);
-    GenMemBarrier(kStoreLoad);
   }
 }
 
diff --git a/compiler/dex/quick/arm/codegen_arm.h b/compiler/dex/quick/arm/codegen_arm.h
index 56f4830..6696cf7 100644
--- a/compiler/dex/quick/arm/codegen_arm.h
+++ b/compiler/dex/quick/arm/codegen_arm.h
@@ -31,7 +31,8 @@
                             RegLocation rl_dest, int lit);
     bool EasyMultiply(RegLocation rl_src, RegLocation rl_dest, int lit) OVERRIDE;
     LIR* CheckSuspendUsingLoad() OVERRIDE;
-    RegStorage LoadHelper(ThreadOffset<4> offset);
+    RegStorage LoadHelper(ThreadOffset<4> offset) OVERRIDE;
+    RegStorage LoadHelper(ThreadOffset<8> offset) OVERRIDE;
     LIR* LoadBaseDispVolatile(RegStorage r_base, int displacement, RegStorage r_dest,
                               OpSize size) OVERRIDE;
     LIR* LoadBaseDisp(RegStorage r_base, int displacement, RegStorage r_dest,
@@ -174,12 +175,14 @@
     LIR* OpRegRegImm(OpKind op, RegStorage r_dest, RegStorage r_src1, int value);
     LIR* OpRegRegReg(OpKind op, RegStorage r_dest, RegStorage r_src1, RegStorage r_src2);
     LIR* OpTestSuspend(LIR* target);
-    LIR* OpThreadMem(OpKind op, ThreadOffset<4> thread_offset);
+    LIR* OpThreadMem(OpKind op, ThreadOffset<4> thread_offset) OVERRIDE;
+    LIR* OpThreadMem(OpKind op, ThreadOffset<8> thread_offset) OVERRIDE;
     LIR* OpVldm(RegStorage r_base, int count);
     LIR* OpVstm(RegStorage r_base, int count);
     void OpLea(RegStorage r_base, RegStorage reg1, RegStorage reg2, int scale, int offset);
     void OpRegCopyWide(RegStorage dest, RegStorage src);
-    void OpTlsCmp(ThreadOffset<4> offset, int val);
+    void OpTlsCmp(ThreadOffset<4> offset, int val) OVERRIDE;
+    void OpTlsCmp(ThreadOffset<8> offset, int val) OVERRIDE;
 
     LIR* LoadBaseDispBody(RegStorage r_base, int displacement, RegStorage r_dest, OpSize size);
     LIR* StoreBaseDispBody(RegStorage r_base, int displacement, RegStorage r_src, OpSize size);
diff --git a/compiler/dex/quick/arm/int_arm.cc b/compiler/dex/quick/arm/int_arm.cc
index 0948ce3..2e0e559 100644
--- a/compiler/dex/quick/arm/int_arm.cc
+++ b/compiler/dex/quick/arm/int_arm.cc
@@ -725,6 +725,10 @@
   LOG(FATAL) << "Unexpected use of OpTlsCmp for Arm";
 }
 
+void ArmMir2Lir::OpTlsCmp(ThreadOffset<8> offset, int val) {
+  UNIMPLEMENTED(FATAL) << "Should not be called.";
+}
+
 bool ArmMir2Lir::GenInlinedCas(CallInfo* info, bool is_long, bool is_object) {
   DCHECK_EQ(cu_->instruction_set, kThumb2);
   // Unused - RegLocation rl_src_unsafe = info->args[0];
diff --git a/compiler/dex/quick/arm/target_arm.cc b/compiler/dex/quick/arm/target_arm.cc
index d0c81d5..8cf1f86 100644
--- a/compiler/dex/quick/arm/target_arm.cc
+++ b/compiler/dex/quick/arm/target_arm.cc
@@ -738,6 +738,11 @@
   return rs_rARM_LR;
 }
 
+RegStorage ArmMir2Lir::LoadHelper(ThreadOffset<8> offset) {
+  UNIMPLEMENTED(FATAL) << "Should not be called.";
+  return RegStorage::InvalidReg();
+}
+
 LIR* ArmMir2Lir::CheckSuspendUsingLoad() {
   RegStorage tmp = rs_r0;
   Load32Disp(rs_rARM_SELF, Thread::ThreadSuspendTriggerOffset<4>().Int32Value(), tmp);
diff --git a/compiler/dex/quick/arm/utility_arm.cc b/compiler/dex/quick/arm/utility_arm.cc
index 1afd890..fe18ed9 100644
--- a/compiler/dex/quick/arm/utility_arm.cc
+++ b/compiler/dex/quick/arm/utility_arm.cc
@@ -1161,6 +1161,11 @@
   return NULL;
 }
 
+LIR* ArmMir2Lir::OpThreadMem(OpKind op, ThreadOffset<8> thread_offset) {
+  UNIMPLEMENTED(FATAL) << "Should not be called.";
+  return nullptr;
+}
+
 LIR* ArmMir2Lir::OpMem(OpKind op, RegStorage r_base, int disp) {
   LOG(FATAL) << "Unexpected use of OpMem for Arm";
   return NULL;
diff --git a/compiler/dex/quick/arm64/arm64_lir.h b/compiler/dex/quick/arm64/arm64_lir.h
index 452c8d7..7ae4b02 100644
--- a/compiler/dex/quick/arm64/arm64_lir.h
+++ b/compiler/dex/quick/arm64/arm64_lir.h
@@ -95,25 +95,6 @@
  * +========================+
  */
 
-#if 1
-#define A64_PTR_SIZE 4
-#define A64_GET_INT_OFFS(offs) ((offs).Int32Value())
-#else
-// Not yet ready for this.
-#define A64_PTR_SIZE 8
-#define A64_GET_INT_OFFS(offs) ((offs).Int32Value())
-#endif
-
-#define A64_QUICK_ENTRYPOINT_OFFSET(name) QUICK_ENTRYPOINT_OFFSET(A64_PTR_SIZE, name)
-#define A64_QUICK_ENTRYPOINT_INT_OFFS(name) A64_GET_INT_OFFS(A64_QUICK_ENTRYPOINT_OFFSET(name))
-#define A64_THREAD_THIN_LOCK_ID_OFFSET A64_GET_INT_OFFS(Thread::ThinLockIdOffset<A64_PTR_SIZE>())
-#define A64_THREAD_EXCEPTION_INT_OFFS A64_GET_INT_OFFS(Thread::ExceptionOffset<A64_PTR_SIZE>())
-#define A64_THREAD_CARD_TABLE_INT_OFFS A64_GET_INT_OFFS(Thread::CardTableOffset<A64_PTR_SIZE>())
-#define A64_THREAD_STACK_END_INT_OFFS A64_GET_INT_OFFS(Thread::StackEndOffset<A64_PTR_SIZE>())
-#define A64_THREAD_SUSPEND_TRIGGER_OFFSET \
-  A64_GET_INT_OFFS(Thread::ThreadSuspendTriggerOffset<A64_PTR_SIZE>())
-typedef ThreadOffset<A64_PTR_SIZE> A64ThreadOffset;
-
 // Offset to distinguish FP regs.
 #define ARM_FP_REG_OFFSET 32
 // First FP callee save.
diff --git a/compiler/dex/quick/arm64/call_arm64.cc b/compiler/dex/quick/arm64/call_arm64.cc
index c210816..51e97cd 100644
--- a/compiler/dex/quick/arm64/call_arm64.cc
+++ b/compiler/dex/quick/arm64/call_arm64.cc
@@ -180,7 +180,7 @@
   // Making a call - use explicit registers
   FlushAllRegs();   /* Everything to home location */
   LoadValueDirectFixed(rl_src, rs_x0);
-  LoadWordDisp(rs_rA64_SELF, A64_QUICK_ENTRYPOINT_INT_OFFS(pHandleFillArrayData),
+  LoadWordDisp(rs_rA64_SELF, QUICK_ENTRYPOINT_OFFSET(8, pHandleFillArrayData).Int32Value(),
                rs_rA64_LR);
   // Materialize a pointer to the fill data image
   NewLIR3(kA64Adr2xd, rx1, 0, WrapPointer(tab_rec));
@@ -209,7 +209,7 @@
         null_check_branch = OpCmpImmBranch(kCondEq, rs_x0, 0, NULL);
       }
     }
-    Load32Disp(rs_rA64_SELF, A64_THREAD_THIN_LOCK_ID_OFFSET, rs_x2);
+    Load32Disp(rs_rA64_SELF, Thread::ThinLockIdOffset<8>().Int32Value(), rs_x2);
     NewLIR3(kA64Ldxr2rX, rx1, rx0, mirror::Object::MonitorOffset().Int32Value() >> 2);
     MarkPossibleNullPointerException(opt_flags);
     LIR* not_unlocked_branch = OpCmpImmBranch(kCondNe, rs_x1, 0, NULL);
@@ -224,7 +224,7 @@
     }
     // TODO: move to a slow path.
     // Go expensive route - artLockObjectFromCode(obj);
-    LoadWordDisp(rs_rA64_SELF, A64_QUICK_ENTRYPOINT_INT_OFFS(pLockObject), rs_rA64_LR);
+    LoadWordDisp(rs_rA64_SELF, QUICK_ENTRYPOINT_OFFSET(8, pLockObject).Int32Value(), rs_rA64_LR);
     ClobberCallerSave();
     LIR* call_inst = OpReg(kOpBlx, rs_rA64_LR);
     MarkSafepointPC(call_inst);
@@ -235,7 +235,7 @@
   } else {
     // Explicit null-check as slow-path is entered using an IT.
     GenNullCheck(rs_x0, opt_flags);
-    Load32Disp(rs_rA64_SELF, A64_THREAD_THIN_LOCK_ID_OFFSET, rs_x2);
+    Load32Disp(rs_rA64_SELF, Thread::ThinLockIdOffset<8>().Int32Value(), rs_x2);
     MarkPossibleNullPointerException(opt_flags);
     NewLIR3(kA64Ldxr2rX, rx1, rx0, mirror::Object::MonitorOffset().Int32Value() >> 2);
     OpRegImm(kOpCmp, rs_x1, 0);
@@ -244,7 +244,8 @@
     OpRegImm(kOpCmp, rs_x1, 0);
     OpIT(kCondNe, "T");
     // Go expensive route - artLockObjectFromCode(self, obj);
-    LoadWordDisp/*ne*/(rs_rA64_SELF, A64_QUICK_ENTRYPOINT_INT_OFFS(pLockObject), rs_rA64_LR);
+    LoadWordDisp/*ne*/(rs_rA64_SELF, QUICK_ENTRYPOINT_OFFSET(8, pLockObject).Int32Value(),
+                       rs_rA64_LR);
     ClobberCallerSave();
     LIR* call_inst = OpReg(kOpBlx/*ne*/, rs_rA64_LR);
     MarkSafepointPC(call_inst);
@@ -262,7 +263,7 @@
   LoadValueDirectFixed(rl_src, rs_x0);  // Get obj
   LockCallTemps();  // Prepare for explicit register usage
   LIR* null_check_branch = nullptr;
-  Load32Disp(rs_rA64_SELF, A64_THREAD_THIN_LOCK_ID_OFFSET, rs_x2);
+  Load32Disp(rs_rA64_SELF, Thread::ThinLockIdOffset<8>().Int32Value(), rs_x2);
   constexpr bool kArchVariantHasGoodBranchPredictor = false;  // TODO: true if cortex-A15.
   if (kArchVariantHasGoodBranchPredictor) {
     if ((opt_flags & MIR_IGNORE_NULL_CHECK) && !(cu_->disable_opt & (1 << kNullCheckElimination))) {
@@ -287,7 +288,7 @@
     }
     // TODO: move to a slow path.
     // Go expensive route - artUnlockObjectFromCode(obj);
-    LoadWordDisp(rs_rA64_SELF, A64_QUICK_ENTRYPOINT_INT_OFFS(pUnlockObject), rs_rA64_LR);
+    LoadWordDisp(rs_rA64_SELF, QUICK_ENTRYPOINT_OFFSET(8, pUnlockObject).Int32Value(), rs_rA64_LR);
     ClobberCallerSave();
     LIR* call_inst = OpReg(kOpBlx, rs_rA64_LR);
     MarkSafepointPC(call_inst);
@@ -300,14 +301,15 @@
     GenNullCheck(rs_x0, opt_flags);
     Load32Disp(rs_x0, mirror::Object::MonitorOffset().Int32Value(), rs_x1);  // Get lock
     MarkPossibleNullPointerException(opt_flags);
-    Load32Disp(rs_rA64_SELF, Thread::ThinLockIdOffset<4>().Int32Value(), rs_x2);
+    Load32Disp(rs_rA64_SELF, Thread::ThinLockIdOffset<8>().Int32Value(), rs_x2);
     LoadConstantNoClobber(rs_x3, 0);
     // Is lock unheld on lock or held by us (==thread_id) on unlock?
     OpRegReg(kOpCmp, rs_x1, rs_x2);
     OpIT(kCondEq, "EE");
     Store32Disp/*eq*/(rs_x0, mirror::Object::MonitorOffset().Int32Value(), rs_x3);
     // Go expensive route - UnlockObjectFromCode(obj);
-    LoadWordDisp/*ne*/(rs_rA64_SELF, A64_QUICK_ENTRYPOINT_INT_OFFS(pUnlockObject), rs_rA64_LR);
+    LoadWordDisp/*ne*/(rs_rA64_SELF, QUICK_ENTRYPOINT_OFFSET(8, pUnlockObject).Int32Value(),
+                       rs_rA64_LR);
     ClobberCallerSave();
     LIR* call_inst = OpReg(kOpBlx/*ne*/, rs_rA64_LR);
     MarkSafepointPC(call_inst);
@@ -316,7 +318,7 @@
 }
 
 void Arm64Mir2Lir::GenMoveException(RegLocation rl_dest) {
-  int ex_offset = A64_THREAD_EXCEPTION_INT_OFFS;
+  int ex_offset = Thread::ExceptionOffset<8>().Int32Value();
   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
   RegStorage reset_reg = AllocTemp();
   Load32Disp(rs_rA64_SELF, ex_offset, rl_result.reg);
@@ -333,7 +335,7 @@
   RegStorage reg_card_base = AllocTemp();
   RegStorage reg_card_no = AllocTemp();
   LIR* branch_over = OpCmpImmBranch(kCondEq, val_reg, 0, NULL);
-  LoadWordDisp(rs_rA64_SELF, A64_THREAD_CARD_TABLE_INT_OFFS, reg_card_base);
+  LoadWordDisp(rs_rA64_SELF, Thread::CardTableOffset<8>().Int32Value(), reg_card_base);
   OpRegRegImm(kOpLsr, reg_card_no, tgt_addr_reg, gc::accounting::CardTable::kCardShift);
   StoreBaseIndexed(reg_card_base, reg_card_no, reg_card_base, 0, kUnsignedByte);
   LIR* target = NewLIR0(kPseudoTargetLabel);
@@ -364,7 +366,7 @@
   NewLIR0(kPseudoMethodEntry);
 
   if (!skip_overflow_check) {
-    LoadWordDisp(rs_rA64_SELF, A64_THREAD_STACK_END_INT_OFFS, rs_x12);
+    LoadWordDisp(rs_rA64_SELF, Thread::StackEndOffset<8>().Int32Value(), rs_x12);
     OpRegImm64(kOpSub, rs_rA64_SP, frame_size_, /*is_wide*/true);
     if (Runtime::Current()->ExplicitStackOverflowChecks()) {
       /* Load stack limit */
diff --git a/compiler/dex/quick/arm64/codegen_arm64.h b/compiler/dex/quick/arm64/codegen_arm64.h
index 26084a2..af0029c 100644
--- a/compiler/dex/quick/arm64/codegen_arm64.h
+++ b/compiler/dex/quick/arm64/codegen_arm64.h
@@ -31,7 +31,8 @@
                             RegLocation rl_dest, int lit);
     bool EasyMultiply(RegLocation rl_src, RegLocation rl_dest, int lit) OVERRIDE;
     LIR* CheckSuspendUsingLoad() OVERRIDE;
-    RegStorage LoadHelper(A64ThreadOffset offset);
+    RegStorage LoadHelper(ThreadOffset<4> offset) OVERRIDE;
+    RegStorage LoadHelper(ThreadOffset<8> offset) OVERRIDE;
     LIR* LoadBaseDispVolatile(RegStorage r_base, int displacement, RegStorage r_dest,
                               OpSize size) OVERRIDE;
     LIR* LoadBaseDisp(RegStorage r_base, int displacement, RegStorage r_dest,
@@ -181,12 +182,14 @@
     LIR* OpRegRegImm(OpKind op, RegStorage r_dest, RegStorage r_src1, int value);
     LIR* OpRegRegReg(OpKind op, RegStorage r_dest, RegStorage r_src1, RegStorage r_src2);
     LIR* OpTestSuspend(LIR* target);
-    LIR* OpThreadMem(OpKind op, A64ThreadOffset thread_offset);
+    LIR* OpThreadMem(OpKind op, ThreadOffset<4> thread_offset) OVERRIDE;
+    LIR* OpThreadMem(OpKind op, ThreadOffset<8> thread_offset) OVERRIDE;
     LIR* OpVldm(RegStorage r_base, int count);
     LIR* OpVstm(RegStorage r_base, int count);
     void OpLea(RegStorage r_base, RegStorage reg1, RegStorage reg2, int scale, int offset);
     void OpRegCopyWide(RegStorage dest, RegStorage src);
-    void OpTlsCmp(A64ThreadOffset offset, int val);
+    void OpTlsCmp(ThreadOffset<4> offset, int val) OVERRIDE;
+    void OpTlsCmp(ThreadOffset<8> offset, int val) OVERRIDE;
 
     LIR* LoadBaseDispBody(RegStorage r_base, int displacement, RegStorage r_dest, OpSize size);
     LIR* StoreBaseDispBody(RegStorage r_base, int displacement, RegStorage r_src, OpSize size);
diff --git a/compiler/dex/quick/arm64/fp_arm64.cc b/compiler/dex/quick/arm64/fp_arm64.cc
index c2a550e..87ab6fe 100644
--- a/compiler/dex/quick/arm64/fp_arm64.cc
+++ b/compiler/dex/quick/arm64/fp_arm64.cc
@@ -49,7 +49,7 @@
     case Instruction::REM_FLOAT_2ADDR:
     case Instruction::REM_FLOAT:
       FlushAllRegs();   // Send everything to home location
-      CallRuntimeHelperRegLocationRegLocation(A64_QUICK_ENTRYPOINT_OFFSET(pFmodf), rl_src1, rl_src2,
+      CallRuntimeHelperRegLocationRegLocation(QUICK_ENTRYPOINT_OFFSET(8, pFmodf), rl_src1, rl_src2,
                                               false);
       rl_result = GetReturn(true);
       StoreValue(rl_dest, rl_result);
@@ -92,7 +92,7 @@
     case Instruction::REM_DOUBLE_2ADDR:
     case Instruction::REM_DOUBLE:
       FlushAllRegs();   // Send everything to home location
-      CallRuntimeHelperRegLocationRegLocation(A64_QUICK_ENTRYPOINT_OFFSET(pFmod), rl_src1, rl_src2,
+      CallRuntimeHelperRegLocationRegLocation(QUICK_ENTRYPOINT_OFFSET(8, pFmod), rl_src1, rl_src2,
                                               false);
       rl_result = GetReturnWide(true);
       StoreValueWide(rl_dest, rl_result);
@@ -310,7 +310,7 @@
   branch = NewLIR2(kA64B2ct, kArmCondEq, 0);
   ClobberCallerSave();
   LockCallTemps();  // Using fixed registers
-  RegStorage r_tgt = LoadHelper(A64_QUICK_ENTRYPOINT_OFFSET(pSqrt));
+  RegStorage r_tgt = LoadHelper(QUICK_ENTRYPOINT_OFFSET(8, pSqrt));
   // NewLIR3(kThumb2Fmrrd, r0, r1, rl_src.reg.GetReg());
   NewLIR1(kA64Blr1x, r_tgt.GetReg());
   // NewLIR3(kThumb2Fmdrr, rl_result.reg.GetReg(), r0, r1);
diff --git a/compiler/dex/quick/arm64/int_arm64.cc b/compiler/dex/quick/arm64/int_arm64.cc
index 709f583..0465249 100644
--- a/compiler/dex/quick/arm64/int_arm64.cc
+++ b/compiler/dex/quick/arm64/int_arm64.cc
@@ -501,7 +501,11 @@
   LOG(FATAL) << "Unexpected use of OpLea for Arm64";
 }
 
-void Arm64Mir2Lir::OpTlsCmp(A64ThreadOffset offset, int val) {
+void Arm64Mir2Lir::OpTlsCmp(ThreadOffset<4> offset, int val) {
+  UNIMPLEMENTED(FATAL) << "Should not be used.";
+}
+
+void Arm64Mir2Lir::OpTlsCmp(ThreadOffset<8> offset, int val) {
   LOG(FATAL) << "Unexpected use of OpTlsCmp for Arm64";
 }
 
diff --git a/compiler/dex/quick/arm64/target_arm64.cc b/compiler/dex/quick/arm64/target_arm64.cc
index e4764eb..6caacc8 100644
--- a/compiler/dex/quick/arm64/target_arm64.cc
+++ b/compiler/dex/quick/arm64/target_arm64.cc
@@ -731,7 +731,12 @@
   FreeTemp(rs_x3);
 }
 
-RegStorage Arm64Mir2Lir::LoadHelper(A64ThreadOffset offset) {
+RegStorage Arm64Mir2Lir::LoadHelper(ThreadOffset<4> offset) {
+  UNIMPLEMENTED(FATAL) << "Should not be called.";
+  return RegStorage::InvalidReg();
+}
+
+RegStorage Arm64Mir2Lir::LoadHelper(ThreadOffset<8> offset) {
   // TODO(Arm64): use LoadWordDisp instead.
   //   e.g. LoadWordDisp(rs_rA64_SELF, offset.Int32Value(), rs_rA64_LR);
   LoadBaseDisp(rs_rA64_SELF, offset.Int32Value(), rs_rA64_LR, k64);
@@ -740,7 +745,7 @@
 
 LIR* Arm64Mir2Lir::CheckSuspendUsingLoad() {
   RegStorage tmp = rs_x0;
-  LoadWordDisp(rs_rA64_SELF, A64_THREAD_SUSPEND_TRIGGER_OFFSET, tmp);
+  LoadWordDisp(rs_rA64_SELF, Thread::ThreadSuspendTriggerOffset<8>().Int32Value(), tmp);
   LIR* load2 = LoadWordDisp(tmp, 0, tmp);
   return load2;
 }
diff --git a/compiler/dex/quick/arm64/utility_arm64.cc b/compiler/dex/quick/arm64/utility_arm64.cc
index ae17711..77e4c3c 100644
--- a/compiler/dex/quick/arm64/utility_arm64.cc
+++ b/compiler/dex/quick/arm64/utility_arm64.cc
@@ -1056,7 +1056,12 @@
   return NULL;
 }
 
-LIR* Arm64Mir2Lir::OpThreadMem(OpKind op, A64ThreadOffset thread_offset) {
+LIR* Arm64Mir2Lir::OpThreadMem(OpKind op, ThreadOffset<4> thread_offset) {
+  UNIMPLEMENTED(FATAL) << "Should not be used.";
+  return nullptr;
+}
+
+LIR* Arm64Mir2Lir::OpThreadMem(OpKind op, ThreadOffset<8> thread_offset) {
   LOG(FATAL) << "Unexpected use of OpThreadMem for Arm64";
   return NULL;
 }
diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc
index 732e776..350823d 100644
--- a/compiler/dex/quick/gen_common.cc
+++ b/compiler/dex/quick/gen_common.cc
@@ -73,7 +73,11 @@
       m2l_->ResetRegPool();
       m2l_->ResetDefTracking();
       GenerateTargetLabel(kPseudoThrowTarget);
-      m2l_->CallRuntimeHelper(QUICK_ENTRYPOINT_OFFSET(4, pThrowDivZero), true);
+      if (Is64BitInstructionSet(m2l_->cu_->instruction_set)) {
+        m2l_->CallRuntimeHelper(QUICK_ENTRYPOINT_OFFSET(8, pThrowDivZero), true);
+      } else {
+        m2l_->CallRuntimeHelper(QUICK_ENTRYPOINT_OFFSET(4, pThrowDivZero), true);
+      }
     }
   };
 
@@ -92,8 +96,13 @@
       m2l_->ResetRegPool();
       m2l_->ResetDefTracking();
       GenerateTargetLabel(kPseudoThrowTarget);
-      m2l_->CallRuntimeHelperRegReg(QUICK_ENTRYPOINT_OFFSET(4, pThrowArrayBounds),
-                                    index_, length_, true);
+      if (Is64BitInstructionSet(m2l_->cu_->instruction_set)) {
+        m2l_->CallRuntimeHelperRegReg(QUICK_ENTRYPOINT_OFFSET(8, pThrowArrayBounds),
+                                      index_, length_, true);
+      } else {
+        m2l_->CallRuntimeHelperRegReg(QUICK_ENTRYPOINT_OFFSET(4, pThrowArrayBounds),
+                                      index_, length_, true);
+      }
     }
 
    private:
@@ -120,8 +129,13 @@
 
       m2l_->OpRegCopy(m2l_->TargetReg(kArg1), length_);
       m2l_->LoadConstant(m2l_->TargetReg(kArg0), index_);
-      m2l_->CallRuntimeHelperRegReg(QUICK_ENTRYPOINT_OFFSET(4, pThrowArrayBounds),
-                                    m2l_->TargetReg(kArg0), m2l_->TargetReg(kArg1), true);
+      if (Is64BitInstructionSet(m2l_->cu_->instruction_set)) {
+        m2l_->CallRuntimeHelperRegReg(QUICK_ENTRYPOINT_OFFSET(8, pThrowArrayBounds),
+                                      m2l_->TargetReg(kArg0), m2l_->TargetReg(kArg1), true);
+      } else {
+        m2l_->CallRuntimeHelperRegReg(QUICK_ENTRYPOINT_OFFSET(4, pThrowArrayBounds),
+                                      m2l_->TargetReg(kArg0), m2l_->TargetReg(kArg1), true);
+      }
     }
 
    private:
@@ -144,7 +158,11 @@
       m2l_->ResetRegPool();
       m2l_->ResetDefTracking();
       GenerateTargetLabel(kPseudoThrowTarget);
-      m2l_->CallRuntimeHelper(QUICK_ENTRYPOINT_OFFSET(4, pThrowNullPointer), true);
+      if (Is64BitInstructionSet(m2l_->cu_->instruction_set)) {
+        m2l_->CallRuntimeHelper(QUICK_ENTRYPOINT_OFFSET(8, pThrowNullPointer), true);
+      } else {
+        m2l_->CallRuntimeHelper(QUICK_ENTRYPOINT_OFFSET(4, pThrowNullPointer), true);
+      }
     }
   };
 
@@ -314,19 +332,16 @@
   StoreValue(rl_dest, rl_result);
 }
 
-/*
- * Let helper function take care of everything.  Will call
- * Array::AllocFromCode(type_idx, method, count);
- * Note: AllocFromCode will handle checks for errNegativeArraySize.
- */
-void Mir2Lir::GenNewArray(uint32_t type_idx, RegLocation rl_dest,
-                          RegLocation rl_src) {
-  FlushAllRegs();  /* Everything to home location */
-  ThreadOffset<4> func_offset(-1);
-  const DexFile* dex_file = cu_->dex_file;
-  CompilerDriver* driver = cu_->compiler_driver;
-  if (cu_->compiler_driver->CanAccessTypeWithoutChecks(cu_->method_idx, *dex_file,
-                                                       type_idx)) {
+template <size_t pointer_size>
+static void GenNewArrayImpl(Mir2Lir* mir_to_lir, CompilationUnit* cu,
+                            uint32_t type_idx, RegLocation rl_dest,
+                            RegLocation rl_src) {
+  mir_to_lir->FlushAllRegs();  /* Everything to home location */
+  ThreadOffset<pointer_size> func_offset(-1);
+  const DexFile* dex_file = cu->dex_file;
+  CompilerDriver* driver = cu->compiler_driver;
+  if (cu->compiler_driver->CanAccessTypeWithoutChecks(cu->method_idx, *dex_file,
+                                                      type_idx)) {
     bool is_type_initialized;  // Ignored as an array does not have an initializer.
     bool use_direct_type_ptr;
     uintptr_t direct_type_ptr;
@@ -336,27 +351,54 @@
                                    &direct_type_ptr, &is_finalizable)) {
       // The fast path.
       if (!use_direct_type_ptr) {
-        LoadClassType(type_idx, kArg0);
-        func_offset = QUICK_ENTRYPOINT_OFFSET(4, pAllocArrayResolved);
-        CallRuntimeHelperRegMethodRegLocation(func_offset, TargetReg(kArg0), rl_src, true);
+        mir_to_lir->LoadClassType(type_idx, kArg0);
+        func_offset = QUICK_ENTRYPOINT_OFFSET(pointer_size, pAllocArrayResolved);
+        mir_to_lir->CallRuntimeHelperRegMethodRegLocation(func_offset, mir_to_lir->TargetReg(kArg0),
+                                                          rl_src, true);
       } else {
         // Use the direct pointer.
-        func_offset = QUICK_ENTRYPOINT_OFFSET(4, pAllocArrayResolved);
-        CallRuntimeHelperImmMethodRegLocation(func_offset, direct_type_ptr, rl_src, true);
+        func_offset = QUICK_ENTRYPOINT_OFFSET(pointer_size, pAllocArrayResolved);
+        mir_to_lir->CallRuntimeHelperImmMethodRegLocation(func_offset, direct_type_ptr, rl_src,
+                                                          true);
       }
     } else {
       // The slow path.
-      DCHECK_EQ(func_offset.Int32Value(), -1);
-      func_offset = QUICK_ENTRYPOINT_OFFSET(4, pAllocArray);
-      CallRuntimeHelperImmMethodRegLocation(func_offset, type_idx, rl_src, true);
+      func_offset = QUICK_ENTRYPOINT_OFFSET(pointer_size, pAllocArray);
+      mir_to_lir->CallRuntimeHelperImmMethodRegLocation(func_offset, type_idx, rl_src, true);
     }
     DCHECK_NE(func_offset.Int32Value(), -1);
   } else {
-    func_offset= QUICK_ENTRYPOINT_OFFSET(4, pAllocArrayWithAccessCheck);
-    CallRuntimeHelperImmMethodRegLocation(func_offset, type_idx, rl_src, true);
+    func_offset = QUICK_ENTRYPOINT_OFFSET(pointer_size, pAllocArrayWithAccessCheck);
+    mir_to_lir->CallRuntimeHelperImmMethodRegLocation(func_offset, type_idx, rl_src, true);
   }
-  RegLocation rl_result = GetReturn(false);
-  StoreValue(rl_dest, rl_result);
+  RegLocation rl_result = mir_to_lir->GetReturn(false);
+  mir_to_lir->StoreValue(rl_dest, rl_result);
+}
+
+/*
+ * Let helper function take care of everything.  Will call
+ * Array::AllocFromCode(type_idx, method, count);
+ * Note: AllocFromCode will handle checks for errNegativeArraySize.
+ */
+void Mir2Lir::GenNewArray(uint32_t type_idx, RegLocation rl_dest,
+                          RegLocation rl_src) {
+  if (Is64BitInstructionSet(cu_->instruction_set)) {
+    GenNewArrayImpl<8>(this, cu_, type_idx, rl_dest, rl_src);
+  } else {
+    GenNewArrayImpl<4>(this, cu_, type_idx, rl_dest, rl_src);
+  }
+}
+
+template <size_t pointer_size>
+static void GenFilledNewArrayCall(Mir2Lir* mir_to_lir, CompilationUnit* cu, int elems, int type_idx) {
+  ThreadOffset<pointer_size> func_offset(-1);
+  if (cu->compiler_driver->CanAccessTypeWithoutChecks(cu->method_idx, *cu->dex_file,
+                                                      type_idx)) {
+    func_offset = QUICK_ENTRYPOINT_OFFSET(pointer_size, pCheckAndAllocArray);
+  } else {
+    func_offset = QUICK_ENTRYPOINT_OFFSET(pointer_size, pCheckAndAllocArrayWithAccessCheck);
+  }
+  mir_to_lir->CallRuntimeHelperImmMethodImm(func_offset, type_idx, elems, true);
 }
 
 /*
@@ -369,14 +411,11 @@
   int elems = info->num_arg_words;
   int type_idx = info->index;
   FlushAllRegs();  /* Everything to home location */
-  ThreadOffset<4> func_offset(-1);
-  if (cu_->compiler_driver->CanAccessTypeWithoutChecks(cu_->method_idx, *cu_->dex_file,
-                                                       type_idx)) {
-    func_offset = QUICK_ENTRYPOINT_OFFSET(4, pCheckAndAllocArray);
+  if (Is64BitInstructionSet(cu_->instruction_set)) {
+    GenFilledNewArrayCall<8>(this, cu_, elems, type_idx);
   } else {
-    func_offset = QUICK_ENTRYPOINT_OFFSET(4, pCheckAndAllocArrayWithAccessCheck);
+    GenFilledNewArrayCall<4>(this, cu_, elems, type_idx);
   }
-  CallRuntimeHelperImmMethodImm(func_offset, type_idx, elems, true);
   FreeTemp(TargetReg(kArg2));
   FreeTemp(TargetReg(kArg1));
   /*
@@ -482,8 +521,13 @@
   void Compile() {
     LIR* unresolved_target = GenerateTargetLabel();
     uninit_->target = unresolved_target;
-    m2l_->CallRuntimeHelperImm(QUICK_ENTRYPOINT_OFFSET(4, pInitializeStaticStorage),
-                               storage_index_, true);
+    if (Is64BitInstructionSet(cu_->instruction_set)) {
+      m2l_->CallRuntimeHelperImm(QUICK_ENTRYPOINT_OFFSET(8, pInitializeStaticStorage),
+                                 storage_index_, true);
+    } else {
+      m2l_->CallRuntimeHelperImm(QUICK_ENTRYPOINT_OFFSET(4, pInitializeStaticStorage),
+                                 storage_index_, true);
+    }
     // Copy helper's result into r_base, a no-op on all but MIPS.
     m2l_->OpRegCopy(r_base_,  m2l_->TargetReg(kRet0));
 
@@ -496,6 +540,17 @@
   const RegStorage r_base_;
 };
 
+template <size_t pointer_size>
+static void GenSputCall(Mir2Lir* mir_to_lir, bool is_long_or_double, bool is_object,
+                        const MirSFieldLoweringInfo* field_info, RegLocation rl_src) {
+  ThreadOffset<pointer_size> setter_offset =
+      is_long_or_double ? QUICK_ENTRYPOINT_OFFSET(pointer_size, pSet64Static)
+          : (is_object ? QUICK_ENTRYPOINT_OFFSET(pointer_size, pSetObjStatic)
+              : QUICK_ENTRYPOINT_OFFSET(pointer_size, pSet32Static));
+  mir_to_lir->CallRuntimeHelperImmRegLocation(setter_offset, field_info->FieldIndex(), rl_src,
+                                              true);
+}
+
 void Mir2Lir::GenSput(MIR* mir, RegLocation rl_src, bool is_long_or_double,
                       bool is_object) {
   const MirSFieldLoweringInfo& field_info = mir_graph_->GetSFieldLoweringInfo(mir);
@@ -573,14 +628,24 @@
     FreeTemp(r_base);
   } else {
     FlushAllRegs();  // Everything to home locations
-    ThreadOffset<4> setter_offset =
-        is_long_or_double ? QUICK_ENTRYPOINT_OFFSET(4, pSet64Static)
-                          : (is_object ? QUICK_ENTRYPOINT_OFFSET(4, pSetObjStatic)
-                                       : QUICK_ENTRYPOINT_OFFSET(4, pSet32Static));
-    CallRuntimeHelperImmRegLocation(setter_offset, field_info.FieldIndex(), rl_src, true);
+    if (Is64BitInstructionSet(cu_->instruction_set)) {
+      GenSputCall<8>(this, is_long_or_double, is_object, &field_info, rl_src);
+    } else {
+      GenSputCall<4>(this, is_long_or_double, is_object, &field_info, rl_src);
+    }
   }
 }
 
+template <size_t pointer_size>
+static void GenSgetCall(Mir2Lir* mir_to_lir, bool is_long_or_double, bool is_object,
+                        const MirSFieldLoweringInfo* field_info) {
+  ThreadOffset<pointer_size> getter_offset =
+      is_long_or_double ? QUICK_ENTRYPOINT_OFFSET(pointer_size, pGet64Static)
+          : (is_object ? QUICK_ENTRYPOINT_OFFSET(pointer_size, pGetObjStatic)
+              : QUICK_ENTRYPOINT_OFFSET(pointer_size, pGet32Static));
+  mir_to_lir->CallRuntimeHelperImm(getter_offset, field_info->FieldIndex(), true);
+}
+
 void Mir2Lir::GenSget(MIR* mir, RegLocation rl_dest,
                       bool is_long_or_double, bool is_object) {
   const MirSFieldLoweringInfo& field_info = mir_graph_->GetSFieldLoweringInfo(mir);
@@ -655,11 +720,11 @@
     }
   } else {
     FlushAllRegs();  // Everything to home locations
-    ThreadOffset<4> getterOffset =
-        is_long_or_double ? QUICK_ENTRYPOINT_OFFSET(4, pGet64Static)
-                          :(is_object ? QUICK_ENTRYPOINT_OFFSET(4, pGetObjStatic)
-                                      : QUICK_ENTRYPOINT_OFFSET(4, pGet32Static));
-    CallRuntimeHelperImm(getterOffset, field_info.FieldIndex(), true);
+    if (Is64BitInstructionSet(cu_->instruction_set)) {
+      GenSgetCall<8>(this, is_long_or_double, is_object, &field_info);
+    } else {
+      GenSgetCall<4>(this, is_long_or_double, is_object, &field_info);
+    }
     if (is_long_or_double) {
       RegLocation rl_result = GetReturnWide(rl_dest.fp);
       StoreValueWide(rl_dest, rl_result);
@@ -680,6 +745,17 @@
   slow_paths_.Reset();
 }
 
+template <size_t pointer_size>
+static void GenIgetCall(Mir2Lir* mir_to_lir, bool is_long_or_double, bool is_object,
+                        const MirIFieldLoweringInfo* field_info, RegLocation rl_obj) {
+  ThreadOffset<pointer_size> getter_offset =
+      is_long_or_double ? QUICK_ENTRYPOINT_OFFSET(pointer_size, pGet64Instance)
+          : (is_object ? QUICK_ENTRYPOINT_OFFSET(pointer_size, pGetObjInstance)
+              : QUICK_ENTRYPOINT_OFFSET(pointer_size, pGet32Instance));
+  mir_to_lir->CallRuntimeHelperImmRegLocation(getter_offset, field_info->FieldIndex(), rl_obj,
+                                              true);
+}
+
 void Mir2Lir::GenIGet(MIR* mir, int opt_flags, OpSize size,
                       RegLocation rl_dest, RegLocation rl_obj, bool is_long_or_double,
                       bool is_object) {
@@ -711,11 +787,11 @@
       StoreValue(rl_dest, rl_result);
     }
   } else {
-    ThreadOffset<4> getterOffset =
-        is_long_or_double ? QUICK_ENTRYPOINT_OFFSET(4, pGet64Instance)
-                          : (is_object ? QUICK_ENTRYPOINT_OFFSET(4, pGetObjInstance)
-                                       : QUICK_ENTRYPOINT_OFFSET(4, pGet32Instance));
-    CallRuntimeHelperImmRegLocation(getterOffset, field_info.FieldIndex(), rl_obj, true);
+    if (Is64BitInstructionSet(cu_->instruction_set)) {
+      GenIgetCall<8>(this, is_long_or_double, is_object, &field_info, rl_obj);
+    } else {
+      GenIgetCall<4>(this, is_long_or_double, is_object, &field_info, rl_obj);
+    }
     if (is_long_or_double) {
       RegLocation rl_result = GetReturnWide(rl_dest.fp);
       StoreValueWide(rl_dest, rl_result);
@@ -726,6 +802,18 @@
   }
 }
 
+template <size_t pointer_size>
+static void GenIputCall(Mir2Lir* mir_to_lir, bool is_long_or_double, bool is_object,
+                        const MirIFieldLoweringInfo* field_info, RegLocation rl_obj,
+                        RegLocation rl_src) {
+  ThreadOffset<pointer_size> setter_offset =
+      is_long_or_double ? QUICK_ENTRYPOINT_OFFSET(pointer_size, pSet64Instance)
+          : (is_object ? QUICK_ENTRYPOINT_OFFSET(pointer_size, pSetObjInstance)
+              : QUICK_ENTRYPOINT_OFFSET(pointer_size, pSet32Instance));
+  mir_to_lir->CallRuntimeHelperImmRegLocationRegLocation(setter_offset, field_info->FieldIndex(),
+                                                         rl_obj, rl_src, true);
+}
+
 void Mir2Lir::GenIPut(MIR* mir, int opt_flags, OpSize size,
                       RegLocation rl_src, RegLocation rl_obj, bool is_long_or_double,
                       bool is_object) {
@@ -759,25 +847,35 @@
       MarkGCCard(rl_src.reg, rl_obj.reg);
     }
   } else {
-    ThreadOffset<4> setter_offset =
-        is_long_or_double ? QUICK_ENTRYPOINT_OFFSET(4, pSet64Instance)
-                          : (is_object ? QUICK_ENTRYPOINT_OFFSET(4, pSetObjInstance)
-                                       : QUICK_ENTRYPOINT_OFFSET(4, pSet32Instance));
-    CallRuntimeHelperImmRegLocationRegLocation(setter_offset, field_info.FieldIndex(),
-                                               rl_obj, rl_src, true);
+    if (Is64BitInstructionSet(cu_->instruction_set)) {
+      GenIputCall<8>(this, is_long_or_double, is_object, &field_info, rl_obj, rl_src);
+    } else {
+      GenIputCall<4>(this, is_long_or_double, is_object, &field_info, rl_obj, rl_src);
+    }
   }
 }
 
+template <size_t pointer_size>
+static void GenArrayObjPutCall(Mir2Lir* mir_to_lir, bool needs_range_check, bool needs_null_check,
+                               RegLocation rl_array, RegLocation rl_index, RegLocation rl_src) {
+  ThreadOffset<pointer_size> helper = needs_range_check
+        ? (needs_null_check ? QUICK_ENTRYPOINT_OFFSET(pointer_size, pAputObjectWithNullAndBoundCheck)
+                            : QUICK_ENTRYPOINT_OFFSET(pointer_size, pAputObjectWithBoundCheck))
+        : QUICK_ENTRYPOINT_OFFSET(pointer_size, pAputObject);
+  mir_to_lir->CallRuntimeHelperRegLocationRegLocationRegLocation(helper, rl_array, rl_index, rl_src,
+                                                                 true);
+}
+
 void Mir2Lir::GenArrayObjPut(int opt_flags, RegLocation rl_array, RegLocation rl_index,
                              RegLocation rl_src) {
   bool needs_range_check = !(opt_flags & MIR_IGNORE_RANGE_CHECK);
   bool needs_null_check = !((cu_->disable_opt & (1 << kNullCheckElimination)) &&
       (opt_flags & MIR_IGNORE_NULL_CHECK));
-  ThreadOffset<4> helper = needs_range_check
-      ? (needs_null_check ? QUICK_ENTRYPOINT_OFFSET(4, pAputObjectWithNullAndBoundCheck)
-                          : QUICK_ENTRYPOINT_OFFSET(4, pAputObjectWithBoundCheck))
-      : QUICK_ENTRYPOINT_OFFSET(4, pAputObject);
-  CallRuntimeHelperRegLocationRegLocationRegLocation(helper, rl_array, rl_index, rl_src, true);
+  if (Is64BitInstructionSet(cu_->instruction_set)) {
+    GenArrayObjPutCall<8>(this, needs_range_check, needs_null_check, rl_array, rl_index, rl_src);
+  } else {
+    GenArrayObjPutCall<4>(this, needs_range_check, needs_null_check, rl_array, rl_index, rl_src);
+  }
 }
 
 void Mir2Lir::GenConstClass(uint32_t type_idx, RegLocation rl_dest) {
@@ -789,8 +887,13 @@
                                                    type_idx)) {
     // Call out to helper which resolves type and verifies access.
     // Resolved type returned in kRet0.
-    CallRuntimeHelperImmReg(QUICK_ENTRYPOINT_OFFSET(4, pInitializeTypeAndVerifyAccess),
-                            type_idx, rl_method.reg, true);
+    if (Is64BitInstructionSet(cu_->instruction_set)) {
+      CallRuntimeHelperImmReg(QUICK_ENTRYPOINT_OFFSET(8, pInitializeTypeAndVerifyAccess),
+                              type_idx, rl_method.reg, true);
+    } else {
+      CallRuntimeHelperImmReg(QUICK_ENTRYPOINT_OFFSET(4, pInitializeTypeAndVerifyAccess),
+                              type_idx, rl_method.reg, true);
+    }
     RegLocation rl_result = GetReturn(false);
     StoreValue(rl_dest, rl_result);
   } else {
@@ -819,8 +922,13 @@
         void Compile() {
           GenerateTargetLabel();
 
-          m2l_->CallRuntimeHelperImmReg(QUICK_ENTRYPOINT_OFFSET(4, pInitializeType), type_idx_,
-                                        rl_method_.reg, true);
+          if (Is64BitInstructionSet(cu_->instruction_set)) {
+            m2l_->CallRuntimeHelperImmReg(QUICK_ENTRYPOINT_OFFSET(8, pInitializeType), type_idx_,
+                                          rl_method_.reg, true);
+          } else {
+            m2l_->CallRuntimeHelperImmReg(QUICK_ENTRYPOINT_OFFSET(4, pInitializeType), type_idx_,
+                                                      rl_method_.reg, true);
+          }
           m2l_->OpRegCopy(rl_result_.reg,  m2l_->TargetReg(kRet0));
 
           m2l_->OpUnconditionalBranch(cont_);
@@ -883,8 +991,13 @@
 
         void Compile() {
           GenerateTargetLabel();
-          m2l_->CallRuntimeHelperRegImm(QUICK_ENTRYPOINT_OFFSET(4, pResolveString),
-                                        r_method_, string_idx_, true);
+          if (Is64BitInstructionSet(cu_->instruction_set)) {
+            m2l_->CallRuntimeHelperRegImm(QUICK_ENTRYPOINT_OFFSET(8, pResolveString),
+                                          r_method_, string_idx_, true);
+          } else {
+            m2l_->CallRuntimeHelperRegImm(QUICK_ENTRYPOINT_OFFSET(4, pResolveString),
+                                          r_method_, string_idx_, true);
+          }
           m2l_->OpUnconditionalBranch(cont_);
         }
 
@@ -908,19 +1021,17 @@
   }
 }
 
-/*
- * Let helper function take care of everything.  Will
- * call Class::NewInstanceFromCode(type_idx, method);
- */
-void Mir2Lir::GenNewInstance(uint32_t type_idx, RegLocation rl_dest) {
-  FlushAllRegs();  /* Everything to home location */
+template <size_t pointer_size>
+static void GenNewInstanceImpl(Mir2Lir* mir_to_lir, CompilationUnit* cu, uint32_t type_idx,
+                               RegLocation rl_dest) {
+  mir_to_lir->FlushAllRegs();  /* Everything to home location */
   // alloc will always check for resolution, do we also need to verify
   // access because the verifier was unable to?
-  ThreadOffset<4> func_offset(-1);
-  const DexFile* dex_file = cu_->dex_file;
-  CompilerDriver* driver = cu_->compiler_driver;
+  ThreadOffset<pointer_size> func_offset(-1);
+  const DexFile* dex_file = cu->dex_file;
+  CompilerDriver* driver = cu->compiler_driver;
   if (driver->CanAccessInstantiableTypeWithoutChecks(
-      cu_->method_idx, *dex_file, type_idx)) {
+      cu->method_idx, *dex_file, type_idx)) {
     bool is_type_initialized;
     bool use_direct_type_ptr;
     uintptr_t direct_type_ptr;
@@ -931,42 +1042,58 @@
                                    !is_finalizable) {
       // The fast path.
       if (!use_direct_type_ptr) {
-        LoadClassType(type_idx, kArg0);
+        mir_to_lir->LoadClassType(type_idx, kArg0);
         if (!is_type_initialized) {
-          func_offset = QUICK_ENTRYPOINT_OFFSET(4, pAllocObjectResolved);
-          CallRuntimeHelperRegMethod(func_offset, TargetReg(kArg0), true);
+          func_offset = QUICK_ENTRYPOINT_OFFSET(pointer_size, pAllocObjectResolved);
+          mir_to_lir->CallRuntimeHelperRegMethod(func_offset, mir_to_lir->TargetReg(kArg0), true);
         } else {
-          func_offset = QUICK_ENTRYPOINT_OFFSET(4, pAllocObjectInitialized);
-          CallRuntimeHelperRegMethod(func_offset, TargetReg(kArg0), true);
+          func_offset = QUICK_ENTRYPOINT_OFFSET(pointer_size, pAllocObjectInitialized);
+          mir_to_lir->CallRuntimeHelperRegMethod(func_offset, mir_to_lir->TargetReg(kArg0), true);
         }
       } else {
         // Use the direct pointer.
         if (!is_type_initialized) {
-          func_offset = QUICK_ENTRYPOINT_OFFSET(4, pAllocObjectResolved);
-          CallRuntimeHelperImmMethod(func_offset, direct_type_ptr, true);
+          func_offset = QUICK_ENTRYPOINT_OFFSET(pointer_size, pAllocObjectResolved);
+          mir_to_lir->CallRuntimeHelperImmMethod(func_offset, direct_type_ptr, true);
         } else {
-          func_offset = QUICK_ENTRYPOINT_OFFSET(4, pAllocObjectInitialized);
-          CallRuntimeHelperImmMethod(func_offset, direct_type_ptr, true);
+          func_offset = QUICK_ENTRYPOINT_OFFSET(pointer_size, pAllocObjectInitialized);
+          mir_to_lir->CallRuntimeHelperImmMethod(func_offset, direct_type_ptr, true);
         }
       }
     } else {
       // The slow path.
       DCHECK_EQ(func_offset.Int32Value(), -1);
-      func_offset = QUICK_ENTRYPOINT_OFFSET(4, pAllocObject);
-      CallRuntimeHelperImmMethod(func_offset, type_idx, true);
+      func_offset = QUICK_ENTRYPOINT_OFFSET(pointer_size, pAllocObject);
+      mir_to_lir->CallRuntimeHelperImmMethod(func_offset, type_idx, true);
     }
     DCHECK_NE(func_offset.Int32Value(), -1);
   } else {
-    func_offset = QUICK_ENTRYPOINT_OFFSET(4, pAllocObjectWithAccessCheck);
-    CallRuntimeHelperImmMethod(func_offset, type_idx, true);
+    func_offset = QUICK_ENTRYPOINT_OFFSET(pointer_size, pAllocObjectWithAccessCheck);
+    mir_to_lir->CallRuntimeHelperImmMethod(func_offset, type_idx, true);
   }
-  RegLocation rl_result = GetReturn(false);
-  StoreValue(rl_dest, rl_result);
+  RegLocation rl_result = mir_to_lir->GetReturn(false);
+  mir_to_lir->StoreValue(rl_dest, rl_result);
+}
+
+/*
+ * Let helper function take care of everything.  Will
+ * call Class::NewInstanceFromCode(type_idx, method);
+ */
+void Mir2Lir::GenNewInstance(uint32_t type_idx, RegLocation rl_dest) {
+  if (Is64BitInstructionSet(cu_->instruction_set)) {
+    GenNewInstanceImpl<8>(this, cu_, type_idx, rl_dest);
+  } else {
+    GenNewInstanceImpl<4>(this, cu_, type_idx, rl_dest);
+  }
 }
 
 void Mir2Lir::GenThrow(RegLocation rl_src) {
   FlushAllRegs();
-  CallRuntimeHelperRegLocation(QUICK_ENTRYPOINT_OFFSET(4, pDeliverException), rl_src, true);
+  if (Is64BitInstructionSet(cu_->instruction_set)) {
+    CallRuntimeHelperRegLocation(QUICK_ENTRYPOINT_OFFSET(8, pDeliverException), rl_src, true);
+  } else {
+    CallRuntimeHelperRegLocation(QUICK_ENTRYPOINT_OFFSET(4, pDeliverException), rl_src, true);
+  }
 }
 
 // For final classes there are no sub-classes to check and so we can answer the instance-of
@@ -1041,8 +1168,13 @@
   if (needs_access_check) {
     // Check we have access to type_idx and if not throw IllegalAccessError,
     // returns Class* in kArg0
-    CallRuntimeHelperImm(QUICK_ENTRYPOINT_OFFSET(4, pInitializeTypeAndVerifyAccess),
-                         type_idx, true);
+    if (Is64BitInstructionSet(cu_->instruction_set)) {
+      CallRuntimeHelperImm(QUICK_ENTRYPOINT_OFFSET(8, pInitializeTypeAndVerifyAccess),
+                           type_idx, true);
+    } else {
+      CallRuntimeHelperImm(QUICK_ENTRYPOINT_OFFSET(4, pInitializeTypeAndVerifyAccess),
+                           type_idx, true);
+    }
     OpRegCopy(class_reg, TargetReg(kRet0));  // Align usage with fast path
     LoadValueDirectFixed(rl_src, TargetReg(kArg0));  // kArg0 <= ref
   } else if (use_declaring_class) {
@@ -1061,7 +1193,11 @@
       LIR* hop_branch = OpCmpImmBranch(kCondNe, class_reg, 0, NULL);
       // Not resolved
       // Call out to helper, which will return resolved type in kRet0
-      CallRuntimeHelperImm(QUICK_ENTRYPOINT_OFFSET(4, pInitializeType), type_idx, true);
+      if (Is64BitInstructionSet(cu_->instruction_set)) {
+        CallRuntimeHelperImm(QUICK_ENTRYPOINT_OFFSET(8, pInitializeType), type_idx, true);
+      } else {
+        CallRuntimeHelperImm(QUICK_ENTRYPOINT_OFFSET(4, pInitializeType), type_idx, true);
+      }
       OpRegCopy(TargetReg(kArg2), TargetReg(kRet0));  // Align usage with fast path
       LoadValueDirectFixed(rl_src, TargetReg(kArg0));  /* reload Ref */
       // Rejoin code paths
@@ -1097,7 +1233,9 @@
     }
   } else {
     if (cu_->instruction_set == kThumb2) {
-      RegStorage r_tgt = LoadHelper(QUICK_ENTRYPOINT_OFFSET(4, pInstanceofNonTrivial));
+      RegStorage r_tgt = Is64BitInstructionSet(cu_->instruction_set) ?
+          LoadHelper(QUICK_ENTRYPOINT_OFFSET(8, pInstanceofNonTrivial)) :
+          LoadHelper(QUICK_ENTRYPOINT_OFFSET(4, pInstanceofNonTrivial));
       LIR* it = nullptr;
       if (!type_known_abstract) {
       /* Uses conditional nullification */
@@ -1117,7 +1255,9 @@
         LoadConstant(rl_result.reg, 1);     // assume true
         branchover = OpCmpBranch(kCondEq, TargetReg(kArg1), TargetReg(kArg2), NULL);
       }
-      RegStorage r_tgt = LoadHelper(QUICK_ENTRYPOINT_OFFSET(4, pInstanceofNonTrivial));
+      RegStorage r_tgt = Is64BitInstructionSet(cu_->instruction_set) ?
+          LoadHelper(QUICK_ENTRYPOINT_OFFSET(8, pInstanceofNonTrivial)) :
+          LoadHelper(QUICK_ENTRYPOINT_OFFSET(4, pInstanceofNonTrivial));
       OpRegCopy(TargetReg(kArg0), TargetReg(kArg2));    // .ne case - arg0 <= class
       OpReg(kOpBlx, r_tgt);    // .ne case: helper(class, ref->class)
       FreeTemp(r_tgt);
@@ -1178,8 +1318,13 @@
     // Check we have access to type_idx and if not throw IllegalAccessError,
     // returns Class* in kRet0
     // InitializeTypeAndVerifyAccess(idx, method)
-    CallRuntimeHelperImmReg(QUICK_ENTRYPOINT_OFFSET(4, pInitializeTypeAndVerifyAccess),
-                            type_idx, TargetReg(kArg1), true);
+    if (Is64BitInstructionSet(cu_->instruction_set)) {
+      CallRuntimeHelperImmReg(QUICK_ENTRYPOINT_OFFSET(8, pInitializeTypeAndVerifyAccess),
+                              type_idx, TargetReg(kArg1), true);
+    } else {
+      CallRuntimeHelperImmReg(QUICK_ENTRYPOINT_OFFSET(4, pInitializeTypeAndVerifyAccess),
+                              type_idx, TargetReg(kArg1), true);
+    }
     OpRegCopy(class_reg, TargetReg(kRet0));  // Align usage with fast path
   } else if (use_declaring_class) {
     LoadRefDisp(TargetReg(kArg1), mirror::ArtMethod::DeclaringClassOffset().Int32Value(),
@@ -1209,11 +1354,17 @@
 
           // Call out to helper, which will return resolved type in kArg0
           // InitializeTypeFromCode(idx, method)
-          m2l_->CallRuntimeHelperImmReg(QUICK_ENTRYPOINT_OFFSET(4, pInitializeType), type_idx_,
-                                        m2l_->TargetReg(kArg1), true);
+          if (Is64BitInstructionSet(m2l_->cu_->instruction_set)) {
+            m2l_->CallRuntimeHelperImmReg(QUICK_ENTRYPOINT_OFFSET(8, pInitializeType), type_idx_,
+                                          m2l_->TargetReg(kArg1), true);
+          } else {
+            m2l_->CallRuntimeHelperImmReg(QUICK_ENTRYPOINT_OFFSET(4, pInitializeType), type_idx_,
+                                                      m2l_->TargetReg(kArg1), true);
+          }
           m2l_->OpRegCopy(class_reg_, m2l_->TargetReg(kRet0));  // Align usage with fast path
           m2l_->OpUnconditionalBranch(cont_);
         }
+
        public:
         const int type_idx_;
         const RegStorage class_reg_;
@@ -1240,8 +1391,13 @@
         m2l_->LoadRefDisp(m2l_->TargetReg(kArg0), mirror::Object::ClassOffset().Int32Value(),
                           m2l_->TargetReg(kArg1));
       }
-      m2l_->CallRuntimeHelperRegReg(QUICK_ENTRYPOINT_OFFSET(4, pCheckCast), m2l_->TargetReg(kArg2),
-                                    m2l_->TargetReg(kArg1), true);
+      if (Is64BitInstructionSet(m2l_->cu_->instruction_set)) {
+        m2l_->CallRuntimeHelperRegReg(QUICK_ENTRYPOINT_OFFSET(8, pCheckCast), m2l_->TargetReg(kArg2),
+                                      m2l_->TargetReg(kArg1), true);
+      } else {
+        m2l_->CallRuntimeHelperRegReg(QUICK_ENTRYPOINT_OFFSET(4, pCheckCast), m2l_->TargetReg(kArg2),
+                                              m2l_->TargetReg(kArg1), true);
+      }
 
       m2l_->OpUnconditionalBranch(cont_);
     }
@@ -1323,28 +1479,38 @@
 }
 
 
-void Mir2Lir::GenShiftOpLong(Instruction::Code opcode, RegLocation rl_dest,
-                             RegLocation rl_src1, RegLocation rl_shift) {
-  ThreadOffset<4> func_offset(-1);
+template <size_t pointer_size>
+static void GenShiftOpLongCall(Mir2Lir* mir_to_lir, Instruction::Code opcode, RegLocation rl_src1,
+                               RegLocation rl_shift) {
+  ThreadOffset<pointer_size> func_offset(-1);
 
   switch (opcode) {
     case Instruction::SHL_LONG:
     case Instruction::SHL_LONG_2ADDR:
-      func_offset = QUICK_ENTRYPOINT_OFFSET(4, pShlLong);
+      func_offset = QUICK_ENTRYPOINT_OFFSET(pointer_size, pShlLong);
       break;
     case Instruction::SHR_LONG:
     case Instruction::SHR_LONG_2ADDR:
-      func_offset = QUICK_ENTRYPOINT_OFFSET(4, pShrLong);
+      func_offset = QUICK_ENTRYPOINT_OFFSET(pointer_size, pShrLong);
       break;
     case Instruction::USHR_LONG:
     case Instruction::USHR_LONG_2ADDR:
-      func_offset = QUICK_ENTRYPOINT_OFFSET(4, pUshrLong);
+      func_offset = QUICK_ENTRYPOINT_OFFSET(pointer_size, pUshrLong);
       break;
     default:
       LOG(FATAL) << "Unexpected case";
   }
-  FlushAllRegs();   /* Send everything to home location */
-  CallRuntimeHelperRegLocationRegLocation(func_offset, rl_src1, rl_shift, false);
+  mir_to_lir->FlushAllRegs();   /* Send everything to home location */
+  mir_to_lir->CallRuntimeHelperRegLocationRegLocation(func_offset, rl_src1, rl_shift, false);
+}
+
+void Mir2Lir::GenShiftOpLong(Instruction::Code opcode, RegLocation rl_dest,
+                             RegLocation rl_src1, RegLocation rl_shift) {
+  if (Is64BitInstructionSet(cu_->instruction_set)) {
+    GenShiftOpLongCall<8>(this, opcode, rl_src1, rl_shift);
+  } else {
+    GenShiftOpLongCall<4>(this, opcode, rl_src1, rl_shift);
+  }
   RegLocation rl_result = GetReturnWide(false);
   StoreValueWide(rl_dest, rl_result);
 }
@@ -1471,16 +1637,21 @@
 
     // If we haven't already generated the code use the callout function.
     if (!done) {
-      ThreadOffset<4> func_offset = QUICK_ENTRYPOINT_OFFSET(4, pIdivmod);
       FlushAllRegs();   /* Send everything to home location */
       LoadValueDirectFixed(rl_src2, TargetReg(kArg1));
-      RegStorage r_tgt = CallHelperSetup(func_offset);
+      RegStorage r_tgt = Is64BitInstructionSet(cu_->instruction_set) ?
+          CallHelperSetup(QUICK_ENTRYPOINT_OFFSET(8, pIdivmod)) :
+          CallHelperSetup(QUICK_ENTRYPOINT_OFFSET(4, pIdivmod));
       LoadValueDirectFixed(rl_src1, TargetReg(kArg0));
       if (check_zero) {
         GenDivZeroCheck(TargetReg(kArg1));
       }
       // NOTE: callout here is not a safepoint.
-      CallHelper(r_tgt, func_offset, false /* not a safepoint */);
+      if (Is64BitInstructionSet(cu_->instruction_set)) {
+        CallHelper(r_tgt, QUICK_ENTRYPOINT_OFFSET(8, pIdivmod), false /* not a safepoint */);
+      } else {
+        CallHelper(r_tgt, QUICK_ENTRYPOINT_OFFSET(4, pIdivmod), false /* not a safepoint */);
+      }
       if (op == kOpDiv)
         rl_result = GetReturn(false);
       else
@@ -1739,8 +1910,13 @@
         FlushAllRegs();   /* Everything to home location. */
         LoadValueDirectFixed(rl_src, TargetReg(kArg0));
         Clobber(TargetReg(kArg0));
-        ThreadOffset<4> func_offset = QUICK_ENTRYPOINT_OFFSET(4, pIdivmod);
-        CallRuntimeHelperRegImm(func_offset, TargetReg(kArg0), lit, false);
+        if (Is64BitInstructionSet(cu_->instruction_set)) {
+          CallRuntimeHelperRegImm(QUICK_ENTRYPOINT_OFFSET(8, pIdivmod), TargetReg(kArg0), lit,
+                                  false);
+        } else {
+          CallRuntimeHelperRegImm(QUICK_ENTRYPOINT_OFFSET(4, pIdivmod), TargetReg(kArg0), lit,
+                                  false);
+        }
         if (is_div)
           rl_result = GetReturn(false);
         else
@@ -1763,37 +1939,38 @@
   StoreValue(rl_dest, rl_result);
 }
 
-void Mir2Lir::GenArithOpLong(Instruction::Code opcode, RegLocation rl_dest,
-                             RegLocation rl_src1, RegLocation rl_src2) {
+template <size_t pointer_size>
+static void GenArithOpLongImpl(Mir2Lir* mir_to_lir, CompilationUnit* cu, Instruction::Code opcode,
+                               RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
   RegLocation rl_result;
   OpKind first_op = kOpBkpt;
   OpKind second_op = kOpBkpt;
   bool call_out = false;
   bool check_zero = false;
-  ThreadOffset<4> func_offset(-1);
-  int ret_reg = TargetReg(kRet0).GetReg();
+  ThreadOffset<pointer_size> func_offset(-1);
+  int ret_reg = mir_to_lir->TargetReg(kRet0).GetReg();
 
   switch (opcode) {
     case Instruction::NOT_LONG:
-      rl_src2 = LoadValueWide(rl_src2, kCoreReg);
-      rl_result = EvalLoc(rl_dest, kCoreReg, true);
+      rl_src2 = mir_to_lir->LoadValueWide(rl_src2, kCoreReg);
+      rl_result = mir_to_lir->EvalLoc(rl_dest, kCoreReg, true);
       // Check for destructive overlap
       if (rl_result.reg.GetLowReg() == rl_src2.reg.GetHighReg()) {
-        RegStorage t_reg = AllocTemp();
-        OpRegCopy(t_reg, rl_src2.reg.GetHigh());
-        OpRegReg(kOpMvn, rl_result.reg.GetLow(), rl_src2.reg.GetLow());
-        OpRegReg(kOpMvn, rl_result.reg.GetHigh(), t_reg);
-        FreeTemp(t_reg);
+        RegStorage t_reg = mir_to_lir->AllocTemp();
+        mir_to_lir->OpRegCopy(t_reg, rl_src2.reg.GetHigh());
+        mir_to_lir->OpRegReg(kOpMvn, rl_result.reg.GetLow(), rl_src2.reg.GetLow());
+        mir_to_lir->OpRegReg(kOpMvn, rl_result.reg.GetHigh(), t_reg);
+        mir_to_lir->FreeTemp(t_reg);
       } else {
-        OpRegReg(kOpMvn, rl_result.reg.GetLow(), rl_src2.reg.GetLow());
-        OpRegReg(kOpMvn, rl_result.reg.GetHigh(), rl_src2.reg.GetHigh());
+        mir_to_lir->OpRegReg(kOpMvn, rl_result.reg.GetLow(), rl_src2.reg.GetLow());
+        mir_to_lir->OpRegReg(kOpMvn, rl_result.reg.GetHigh(), rl_src2.reg.GetHigh());
       }
-      StoreValueWide(rl_dest, rl_result);
+      mir_to_lir->StoreValueWide(rl_dest, rl_result);
       return;
     case Instruction::ADD_LONG:
     case Instruction::ADD_LONG_2ADDR:
-      if (cu_->instruction_set != kThumb2) {
-        GenAddLong(opcode, rl_dest, rl_src1, rl_src2);
+      if (cu->instruction_set != kThumb2) {
+        mir_to_lir->GenAddLong(opcode, rl_dest, rl_src1, rl_src2);
         return;
       }
       first_op = kOpAdd;
@@ -1801,8 +1978,8 @@
       break;
     case Instruction::SUB_LONG:
     case Instruction::SUB_LONG_2ADDR:
-      if (cu_->instruction_set != kThumb2) {
-        GenSubLong(opcode, rl_dest, rl_src1, rl_src2);
+      if (cu->instruction_set != kThumb2) {
+        mir_to_lir->GenSubLong(opcode, rl_dest, rl_src1, rl_src2);
         return;
       }
       first_op = kOpSub;
@@ -1810,42 +1987,43 @@
       break;
     case Instruction::MUL_LONG:
     case Instruction::MUL_LONG_2ADDR:
-      if (cu_->instruction_set != kMips) {
-        GenMulLong(opcode, rl_dest, rl_src1, rl_src2);
+      if (cu->instruction_set != kMips) {
+        mir_to_lir->GenMulLong(opcode, rl_dest, rl_src1, rl_src2);
         return;
       } else {
         call_out = true;
-        ret_reg = TargetReg(kRet0).GetReg();
-        func_offset = QUICK_ENTRYPOINT_OFFSET(4, pLmul);
+        ret_reg = mir_to_lir->TargetReg(kRet0).GetReg();
+        func_offset = QUICK_ENTRYPOINT_OFFSET(pointer_size, pLmul);
       }
       break;
     case Instruction::DIV_LONG:
     case Instruction::DIV_LONG_2ADDR:
       call_out = true;
       check_zero = true;
-      ret_reg = TargetReg(kRet0).GetReg();
-      func_offset = QUICK_ENTRYPOINT_OFFSET(4, pLdiv);
+      ret_reg = mir_to_lir->TargetReg(kRet0).GetReg();
+      func_offset = QUICK_ENTRYPOINT_OFFSET(pointer_size, pLdiv);
       break;
     case Instruction::REM_LONG:
     case Instruction::REM_LONG_2ADDR:
       call_out = true;
       check_zero = true;
-      func_offset = QUICK_ENTRYPOINT_OFFSET(4, pLmod);
+      func_offset = QUICK_ENTRYPOINT_OFFSET(pointer_size, pLmod);
       /* NOTE - for Arm, result is in kArg2/kArg3 instead of kRet0/kRet1 */
-      ret_reg = (cu_->instruction_set == kThumb2) ? TargetReg(kArg2).GetReg() : TargetReg(kRet0).GetReg();
+      ret_reg = (cu->instruction_set == kThumb2) ? mir_to_lir->TargetReg(kArg2).GetReg() :
+          mir_to_lir->TargetReg(kRet0).GetReg();
       break;
     case Instruction::AND_LONG_2ADDR:
     case Instruction::AND_LONG:
-      if (cu_->instruction_set == kX86 || cu_->instruction_set == kX86_64) {
-        return GenAndLong(opcode, rl_dest, rl_src1, rl_src2);
+      if (cu->instruction_set == kX86 || cu->instruction_set == kX86_64) {
+        return mir_to_lir->GenAndLong(opcode, rl_dest, rl_src1, rl_src2);
       }
       first_op = kOpAnd;
       second_op = kOpAnd;
       break;
     case Instruction::OR_LONG:
     case Instruction::OR_LONG_2ADDR:
-      if (cu_->instruction_set == kX86 || cu_->instruction_set == kX86_64) {
-        GenOrLong(opcode, rl_dest, rl_src1, rl_src2);
+      if (cu->instruction_set == kX86 || cu->instruction_set == kX86_64) {
+        mir_to_lir->GenOrLong(opcode, rl_dest, rl_src1, rl_src2);
         return;
       }
       first_op = kOpOr;
@@ -1853,51 +2031,66 @@
       break;
     case Instruction::XOR_LONG:
     case Instruction::XOR_LONG_2ADDR:
-      if (cu_->instruction_set == kX86 || cu_->instruction_set == kX86_64) {
-        GenXorLong(opcode, rl_dest, rl_src1, rl_src2);
+      if (cu->instruction_set == kX86 || cu->instruction_set == kX86_64) {
+        mir_to_lir->GenXorLong(opcode, rl_dest, rl_src1, rl_src2);
         return;
       }
       first_op = kOpXor;
       second_op = kOpXor;
       break;
     case Instruction::NEG_LONG: {
-      GenNegLong(rl_dest, rl_src2);
+      mir_to_lir->GenNegLong(rl_dest, rl_src2);
       return;
     }
     default:
       LOG(FATAL) << "Invalid long arith op";
   }
   if (!call_out) {
-    GenLong3Addr(first_op, second_op, rl_dest, rl_src1, rl_src2);
+    mir_to_lir->GenLong3Addr(first_op, second_op, rl_dest, rl_src1, rl_src2);
   } else {
-    FlushAllRegs();   /* Send everything to home location */
+    mir_to_lir->FlushAllRegs();   /* Send everything to home location */
     if (check_zero) {
-      RegStorage r_tmp1 = RegStorage::MakeRegPair(TargetReg(kArg0), TargetReg(kArg1));
-      RegStorage r_tmp2 = RegStorage::MakeRegPair(TargetReg(kArg2), TargetReg(kArg3));
-      LoadValueDirectWideFixed(rl_src2, r_tmp2);
-      RegStorage r_tgt = CallHelperSetup(func_offset);
-      GenDivZeroCheckWide(RegStorage::MakeRegPair(TargetReg(kArg2), TargetReg(kArg3)));
-      LoadValueDirectWideFixed(rl_src1, r_tmp1);
+      RegStorage r_tmp1 = RegStorage::MakeRegPair(mir_to_lir->TargetReg(kArg0),
+                                                  mir_to_lir->TargetReg(kArg1));
+      RegStorage r_tmp2 = RegStorage::MakeRegPair(mir_to_lir->TargetReg(kArg2),
+                                                  mir_to_lir->TargetReg(kArg3));
+      mir_to_lir->LoadValueDirectWideFixed(rl_src2, r_tmp2);
+      RegStorage r_tgt = mir_to_lir->CallHelperSetup(func_offset);
+      mir_to_lir->GenDivZeroCheckWide(RegStorage::MakeRegPair(mir_to_lir->TargetReg(kArg2),
+                                                              mir_to_lir->TargetReg(kArg3)));
+      mir_to_lir->LoadValueDirectWideFixed(rl_src1, r_tmp1);
       // NOTE: callout here is not a safepoint
-      CallHelper(r_tgt, func_offset, false /* not safepoint */);
+      mir_to_lir->CallHelper(r_tgt, func_offset, false /* not safepoint */);
     } else {
-      CallRuntimeHelperRegLocationRegLocation(func_offset, rl_src1, rl_src2, false);
+      mir_to_lir->CallRuntimeHelperRegLocationRegLocation(func_offset, rl_src1, rl_src2, false);
     }
     // Adjust return regs in to handle case of rem returning kArg2/kArg3
-    if (ret_reg == TargetReg(kRet0).GetReg())
-      rl_result = GetReturnWide(false);
+    if (ret_reg == mir_to_lir->TargetReg(kRet0).GetReg())
+      rl_result = mir_to_lir->GetReturnWide(false);
     else
-      rl_result = GetReturnWideAlt();
-    StoreValueWide(rl_dest, rl_result);
+      rl_result = mir_to_lir->GetReturnWideAlt();
+    mir_to_lir->StoreValueWide(rl_dest, rl_result);
   }
 }
 
-void Mir2Lir::GenConversionCall(ThreadOffset<4> func_offset,
+void Mir2Lir::GenArithOpLong(Instruction::Code opcode, RegLocation rl_dest,
+                             RegLocation rl_src1, RegLocation rl_src2) {
+  if (Is64BitInstructionSet(cu_->instruction_set)) {
+    GenArithOpLongImpl<8>(this, cu_, opcode, rl_dest, rl_src1, rl_src2);
+  } else {
+    GenArithOpLongImpl<4>(this, cu_, opcode, rl_dest, rl_src1, rl_src2);
+  }
+}
+
+template <size_t pointer_size>
+void Mir2Lir::GenConversionCall(ThreadOffset<pointer_size> func_offset,
                                 RegLocation rl_dest, RegLocation rl_src) {
   /*
    * Don't optimize the register usage since it calls out to support
    * functions
    */
+  DCHECK_EQ(pointer_size, GetInstructionSetPointerSize(cu_->instruction_set));
+
   FlushAllRegs();   /* Send everything to home location */
   CallRuntimeHelperRegLocation(func_offset, rl_src, false);
   if (rl_dest.wide) {
@@ -1910,6 +2103,10 @@
     StoreValue(rl_dest, rl_result);
   }
 }
+template void Mir2Lir::GenConversionCall(ThreadOffset<4> func_offset,
+                                         RegLocation rl_dest, RegLocation rl_src);
+template void Mir2Lir::GenConversionCall(ThreadOffset<8> func_offset,
+                                         RegLocation rl_dest, RegLocation rl_src);
 
 class SuspendCheckSlowPath : public Mir2Lir::LIRSlowPath {
  public:
@@ -1921,7 +2118,11 @@
     m2l_->ResetRegPool();
     m2l_->ResetDefTracking();
     GenerateTargetLabel(kPseudoSuspendTarget);
-    m2l_->CallRuntimeHelper(QUICK_ENTRYPOINT_OFFSET(4, pTestSuspend), true);
+    if (Is64BitInstructionSet(cu_->instruction_set)) {
+      m2l_->CallRuntimeHelper(QUICK_ENTRYPOINT_OFFSET(8, pTestSuspend), true);
+    } else {
+      m2l_->CallRuntimeHelper(QUICK_ENTRYPOINT_OFFSET(4, pTestSuspend), true);
+    }
     if (cont_ != nullptr) {
       m2l_->OpUnconditionalBranch(cont_);
     }
@@ -1976,13 +2177,21 @@
 /* Call out to helper assembly routine that will null check obj and then lock it. */
 void Mir2Lir::GenMonitorEnter(int opt_flags, RegLocation rl_src) {
   FlushAllRegs();
-  CallRuntimeHelperRegLocation(QUICK_ENTRYPOINT_OFFSET(4, pLockObject), rl_src, true);
+  if (Is64BitInstructionSet(cu_->instruction_set)) {
+    CallRuntimeHelperRegLocation(QUICK_ENTRYPOINT_OFFSET(8, pLockObject), rl_src, true);
+  } else {
+    CallRuntimeHelperRegLocation(QUICK_ENTRYPOINT_OFFSET(4, pLockObject), rl_src, true);
+  }
 }
 
 /* Call out to helper assembly routine that will null check obj and then unlock it. */
 void Mir2Lir::GenMonitorExit(int opt_flags, RegLocation rl_src) {
   FlushAllRegs();
-  CallRuntimeHelperRegLocation(QUICK_ENTRYPOINT_OFFSET(4, pUnlockObject), rl_src, true);
+  if (Is64BitInstructionSet(cu_->instruction_set)) {
+    CallRuntimeHelperRegLocation(QUICK_ENTRYPOINT_OFFSET(8, pUnlockObject), rl_src, true);
+  } else {
+    CallRuntimeHelperRegLocation(QUICK_ENTRYPOINT_OFFSET(4, pUnlockObject), rl_src, true);
+  }
 }
 
 /* Generic code for generating a wide constant into a VR. */
diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc
index d321b00..24ed4a3 100644
--- a/compiler/dex/quick/gen_invoke.cc
+++ b/compiler/dex/quick/gen_invoke.cc
@@ -63,19 +63,46 @@
   AddSlowPath(new (arena_) IntrinsicSlowPathPath(this, info, branch, resume));
 }
 
+// Macro to help instantiate.
+// TODO: This might be used to only instantiate <4> on pure 32b systems.
+#define INSTANTIATE(sig_part1, ...) \
+  template sig_part1(ThreadOffset<4>, __VA_ARGS__); \
+  template sig_part1(ThreadOffset<8>, __VA_ARGS__); \
+
+
 /*
  * To save scheduling time, helper calls are broken into two parts: generation of
  * the helper target address, and the actual call to the helper.  Because x86
  * has a memory call operation, part 1 is a NOP for x86.  For other targets,
  * load arguments between the two parts.
  */
+// template <size_t pointer_size>
 RegStorage Mir2Lir::CallHelperSetup(ThreadOffset<4> helper_offset) {
-  return (cu_->instruction_set == kX86 || cu_->instruction_set == kX86_64) ? RegStorage::InvalidReg() : LoadHelper(helper_offset);
+  // All CallRuntimeHelperXXX call this first. So make a central check here.
+  DCHECK_EQ(4U, GetInstructionSetPointerSize(cu_->instruction_set));
+
+  if (cu_->instruction_set == kX86 || cu_->instruction_set == kX86_64) {
+    return RegStorage::InvalidReg();
+  } else {
+    return LoadHelper(helper_offset);
+  }
+}
+
+RegStorage Mir2Lir::CallHelperSetup(ThreadOffset<8> helper_offset) {
+  // All CallRuntimeHelperXXX call this first. So make a central check here.
+  DCHECK_EQ(8U, GetInstructionSetPointerSize(cu_->instruction_set));
+
+  if (cu_->instruction_set == kX86 || cu_->instruction_set == kX86_64) {
+    return RegStorage::InvalidReg();
+  } else {
+    return LoadHelper(helper_offset);
+  }
 }
 
 /* NOTE: if r_tgt is a temp, it will be freed following use */
-LIR* Mir2Lir::CallHelper(RegStorage r_tgt, ThreadOffset<4> helper_offset, bool safepoint_pc,
-                         bool use_link) {
+template <size_t pointer_size>
+LIR* Mir2Lir::CallHelper(RegStorage r_tgt, ThreadOffset<pointer_size> helper_offset,
+                         bool safepoint_pc, bool use_link) {
   LIR* call_inst;
   OpKind op = use_link ? kOpBlx : kOpBx;
   if (cu_->instruction_set == kX86 || cu_->instruction_set == kX86_64) {
@@ -89,30 +116,41 @@
   }
   return call_inst;
 }
+template LIR* Mir2Lir::CallHelper(RegStorage r_tgt, ThreadOffset<4> helper_offset,
+                                        bool safepoint_pc, bool use_link);
+template LIR* Mir2Lir::CallHelper(RegStorage r_tgt, ThreadOffset<8> helper_offset,
+                                        bool safepoint_pc, bool use_link);
 
-void Mir2Lir::CallRuntimeHelper(ThreadOffset<4> helper_offset, bool safepoint_pc) {
+template <size_t pointer_size>
+void Mir2Lir::CallRuntimeHelper(ThreadOffset<pointer_size> helper_offset, bool safepoint_pc) {
   RegStorage r_tgt = CallHelperSetup(helper_offset);
   ClobberCallerSave();
-  CallHelper(r_tgt, helper_offset, safepoint_pc);
+  CallHelper<pointer_size>(r_tgt, helper_offset, safepoint_pc);
 }
+INSTANTIATE(void Mir2Lir::CallRuntimeHelper, bool safepoint_pc)
 
-void Mir2Lir::CallRuntimeHelperImm(ThreadOffset<4> helper_offset, int arg0, bool safepoint_pc) {
+template <size_t pointer_size>
+void Mir2Lir::CallRuntimeHelperImm(ThreadOffset<pointer_size> helper_offset, int arg0, bool safepoint_pc) {
   RegStorage r_tgt = CallHelperSetup(helper_offset);
   LoadConstant(TargetReg(kArg0), arg0);
   ClobberCallerSave();
-  CallHelper(r_tgt, helper_offset, safepoint_pc);
+  CallHelper<pointer_size>(r_tgt, helper_offset, safepoint_pc);
 }
+INSTANTIATE(void Mir2Lir::CallRuntimeHelperImm, int arg0, bool safepoint_pc)
 
-void Mir2Lir::CallRuntimeHelperReg(ThreadOffset<4> helper_offset, RegStorage arg0,
+template <size_t pointer_size>
+void Mir2Lir::CallRuntimeHelperReg(ThreadOffset<pointer_size> helper_offset, RegStorage arg0,
                                    bool safepoint_pc) {
   RegStorage r_tgt = CallHelperSetup(helper_offset);
   OpRegCopy(TargetReg(kArg0), arg0);
   ClobberCallerSave();
-  CallHelper(r_tgt, helper_offset, safepoint_pc);
+  CallHelper<pointer_size>(r_tgt, helper_offset, safepoint_pc);
 }
+INSTANTIATE(void Mir2Lir::CallRuntimeHelperReg, RegStorage arg0, bool safepoint_pc)
 
-void Mir2Lir::CallRuntimeHelperRegLocation(ThreadOffset<4> helper_offset, RegLocation arg0,
-                                           bool safepoint_pc) {
+template <size_t pointer_size>
+void Mir2Lir::CallRuntimeHelperRegLocation(ThreadOffset<pointer_size> helper_offset,
+                                           RegLocation arg0, bool safepoint_pc) {
   RegStorage r_tgt = CallHelperSetup(helper_offset);
   if (arg0.wide == 0) {
     LoadValueDirectFixed(arg0, TargetReg(kArg0));
@@ -121,19 +159,23 @@
     LoadValueDirectWideFixed(arg0, r_tmp);
   }
   ClobberCallerSave();
-  CallHelper(r_tgt, helper_offset, safepoint_pc);
+  CallHelper<pointer_size>(r_tgt, helper_offset, safepoint_pc);
 }
+INSTANTIATE(void Mir2Lir::CallRuntimeHelperRegLocation, RegLocation arg0, bool safepoint_pc)
 
-void Mir2Lir::CallRuntimeHelperImmImm(ThreadOffset<4> helper_offset, int arg0, int arg1,
+template <size_t pointer_size>
+void Mir2Lir::CallRuntimeHelperImmImm(ThreadOffset<pointer_size> helper_offset, int arg0, int arg1,
                                       bool safepoint_pc) {
   RegStorage r_tgt = CallHelperSetup(helper_offset);
   LoadConstant(TargetReg(kArg0), arg0);
   LoadConstant(TargetReg(kArg1), arg1);
   ClobberCallerSave();
-  CallHelper(r_tgt, helper_offset, safepoint_pc);
+  CallHelper<pointer_size>(r_tgt, helper_offset, safepoint_pc);
 }
+INSTANTIATE(void Mir2Lir::CallRuntimeHelperImmImm, int arg0, int arg1, bool safepoint_pc)
 
-void Mir2Lir::CallRuntimeHelperImmRegLocation(ThreadOffset<4> helper_offset, int arg0,
+template <size_t pointer_size>
+void Mir2Lir::CallRuntimeHelperImmRegLocation(ThreadOffset<pointer_size> helper_offset, int arg0,
                                               RegLocation arg1, bool safepoint_pc) {
   RegStorage r_tgt = CallHelperSetup(helper_offset);
   if (arg1.wide == 0) {
@@ -144,46 +186,58 @@
   }
   LoadConstant(TargetReg(kArg0), arg0);
   ClobberCallerSave();
-  CallHelper(r_tgt, helper_offset, safepoint_pc);
+  CallHelper<pointer_size>(r_tgt, helper_offset, safepoint_pc);
 }
+INSTANTIATE(void Mir2Lir::CallRuntimeHelperImmRegLocation, int arg0, RegLocation arg1,
+            bool safepoint_pc)
 
-void Mir2Lir::CallRuntimeHelperRegLocationImm(ThreadOffset<4> helper_offset, RegLocation arg0,
-                                              int arg1, bool safepoint_pc) {
+template <size_t pointer_size>
+void Mir2Lir::CallRuntimeHelperRegLocationImm(ThreadOffset<pointer_size> helper_offset,
+                                              RegLocation arg0, int arg1, bool safepoint_pc) {
   RegStorage r_tgt = CallHelperSetup(helper_offset);
   LoadValueDirectFixed(arg0, TargetReg(kArg0));
   LoadConstant(TargetReg(kArg1), arg1);
   ClobberCallerSave();
-  CallHelper(r_tgt, helper_offset, safepoint_pc);
+  CallHelper<pointer_size>(r_tgt, helper_offset, safepoint_pc);
 }
+INSTANTIATE(void Mir2Lir::CallRuntimeHelperRegLocationImm, RegLocation arg0, int arg1,
+            bool safepoint_pc)
 
-void Mir2Lir::CallRuntimeHelperImmReg(ThreadOffset<4> helper_offset, int arg0, RegStorage arg1,
-                                      bool safepoint_pc) {
+template <size_t pointer_size>
+void Mir2Lir::CallRuntimeHelperImmReg(ThreadOffset<pointer_size> helper_offset, int arg0,
+                                      RegStorage arg1, bool safepoint_pc) {
   RegStorage r_tgt = CallHelperSetup(helper_offset);
   OpRegCopy(TargetReg(kArg1), arg1);
   LoadConstant(TargetReg(kArg0), arg0);
   ClobberCallerSave();
-  CallHelper(r_tgt, helper_offset, safepoint_pc);
+  CallHelper<pointer_size>(r_tgt, helper_offset, safepoint_pc);
 }
+INSTANTIATE(void Mir2Lir::CallRuntimeHelperImmReg, int arg0, RegStorage arg1, bool safepoint_pc)
 
-void Mir2Lir::CallRuntimeHelperRegImm(ThreadOffset<4> helper_offset, RegStorage arg0, int arg1,
-                                      bool safepoint_pc) {
+template <size_t pointer_size>
+void Mir2Lir::CallRuntimeHelperRegImm(ThreadOffset<pointer_size> helper_offset, RegStorage arg0,
+                                      int arg1, bool safepoint_pc) {
   RegStorage r_tgt = CallHelperSetup(helper_offset);
   OpRegCopy(TargetReg(kArg0), arg0);
   LoadConstant(TargetReg(kArg1), arg1);
   ClobberCallerSave();
-  CallHelper(r_tgt, helper_offset, safepoint_pc);
+  CallHelper<pointer_size>(r_tgt, helper_offset, safepoint_pc);
 }
+INSTANTIATE(void Mir2Lir::CallRuntimeHelperRegImm, RegStorage arg0, int arg1, bool safepoint_pc)
 
-void Mir2Lir::CallRuntimeHelperImmMethod(ThreadOffset<4> helper_offset, int arg0,
+template <size_t pointer_size>
+void Mir2Lir::CallRuntimeHelperImmMethod(ThreadOffset<pointer_size> helper_offset, int arg0,
                                          bool safepoint_pc) {
   RegStorage r_tgt = CallHelperSetup(helper_offset);
   LoadCurrMethodDirect(TargetReg(kArg1));
   LoadConstant(TargetReg(kArg0), arg0);
   ClobberCallerSave();
-  CallHelper(r_tgt, helper_offset, safepoint_pc);
+  CallHelper<pointer_size>(r_tgt, helper_offset, safepoint_pc);
 }
+INSTANTIATE(void Mir2Lir::CallRuntimeHelperImmMethod, int arg0, bool safepoint_pc)
 
-void Mir2Lir::CallRuntimeHelperRegMethod(ThreadOffset<4> helper_offset, RegStorage arg0,
+template <size_t pointer_size>
+void Mir2Lir::CallRuntimeHelperRegMethod(ThreadOffset<pointer_size> helper_offset, RegStorage arg0,
                                          bool safepoint_pc) {
   RegStorage r_tgt = CallHelperSetup(helper_offset);
   DCHECK_NE(TargetReg(kArg1).GetReg(), arg0.GetReg());
@@ -192,11 +246,14 @@
   }
   LoadCurrMethodDirect(TargetReg(kArg1));
   ClobberCallerSave();
-  CallHelper(r_tgt, helper_offset, safepoint_pc);
+  CallHelper<pointer_size>(r_tgt, helper_offset, safepoint_pc);
 }
+INSTANTIATE(void Mir2Lir::CallRuntimeHelperRegMethod, RegStorage arg0, bool safepoint_pc)
 
-void Mir2Lir::CallRuntimeHelperRegMethodRegLocation(ThreadOffset<4> helper_offset, RegStorage arg0,
-                                                    RegLocation arg2, bool safepoint_pc) {
+template <size_t pointer_size>
+void Mir2Lir::CallRuntimeHelperRegMethodRegLocation(ThreadOffset<pointer_size> helper_offset,
+                                                    RegStorage arg0, RegLocation arg2,
+                                                    bool safepoint_pc) {
   RegStorage r_tgt = CallHelperSetup(helper_offset);
   DCHECK_NE(TargetReg(kArg1).GetReg(), arg0.GetReg());
   if (TargetReg(kArg0) != arg0) {
@@ -205,10 +262,13 @@
   LoadCurrMethodDirect(TargetReg(kArg1));
   LoadValueDirectFixed(arg2, TargetReg(kArg2));
   ClobberCallerSave();
-  CallHelper(r_tgt, helper_offset, safepoint_pc);
+  CallHelper<pointer_size>(r_tgt, helper_offset, safepoint_pc);
 }
+INSTANTIATE(void Mir2Lir::CallRuntimeHelperRegMethodRegLocation, RegStorage arg0, RegLocation arg2,
+            bool safepoint_pc)
 
-void Mir2Lir::CallRuntimeHelperRegLocationRegLocation(ThreadOffset<4> helper_offset,
+template <size_t pointer_size>
+void Mir2Lir::CallRuntimeHelperRegLocationRegLocation(ThreadOffset<pointer_size> helper_offset,
                                                       RegLocation arg0, RegLocation arg1,
                                                       bool safepoint_pc) {
   RegStorage r_tgt = CallHelperSetup(helper_offset);
@@ -255,8 +315,10 @@
     }
   }
   ClobberCallerSave();
-  CallHelper(r_tgt, helper_offset, safepoint_pc);
+  CallHelper<pointer_size>(r_tgt, helper_offset, safepoint_pc);
 }
+INSTANTIATE(void Mir2Lir::CallRuntimeHelperRegLocationRegLocation, RegLocation arg0,
+            RegLocation arg1, bool safepoint_pc)
 
 void Mir2Lir::CopyToArgumentRegs(RegStorage arg0, RegStorage arg1) {
   if (arg1.GetReg() == TargetReg(kArg0).GetReg()) {
@@ -275,48 +337,61 @@
   }
 }
 
-void Mir2Lir::CallRuntimeHelperRegReg(ThreadOffset<4> helper_offset, RegStorage arg0,
+template <size_t pointer_size>
+void Mir2Lir::CallRuntimeHelperRegReg(ThreadOffset<pointer_size> helper_offset, RegStorage arg0,
                                       RegStorage arg1, bool safepoint_pc) {
   RegStorage r_tgt = CallHelperSetup(helper_offset);
   CopyToArgumentRegs(arg0, arg1);
   ClobberCallerSave();
-  CallHelper(r_tgt, helper_offset, safepoint_pc);
+  CallHelper<pointer_size>(r_tgt, helper_offset, safepoint_pc);
 }
+INSTANTIATE(void Mir2Lir::CallRuntimeHelperRegReg, RegStorage arg0, RegStorage arg1,
+            bool safepoint_pc)
 
-void Mir2Lir::CallRuntimeHelperRegRegImm(ThreadOffset<4> helper_offset, RegStorage arg0,
+template <size_t pointer_size>
+void Mir2Lir::CallRuntimeHelperRegRegImm(ThreadOffset<pointer_size> helper_offset, RegStorage arg0,
                                          RegStorage arg1, int arg2, bool safepoint_pc) {
   RegStorage r_tgt = CallHelperSetup(helper_offset);
   CopyToArgumentRegs(arg0, arg1);
   LoadConstant(TargetReg(kArg2), arg2);
   ClobberCallerSave();
-  CallHelper(r_tgt, helper_offset, safepoint_pc);
+  CallHelper<pointer_size>(r_tgt, helper_offset, safepoint_pc);
 }
+INSTANTIATE(void Mir2Lir::CallRuntimeHelperRegRegImm, RegStorage arg0, RegStorage arg1, int arg2,
+            bool safepoint_pc)
 
-void Mir2Lir::CallRuntimeHelperImmMethodRegLocation(ThreadOffset<4> helper_offset,
+template <size_t pointer_size>
+void Mir2Lir::CallRuntimeHelperImmMethodRegLocation(ThreadOffset<pointer_size> helper_offset,
                                                     int arg0, RegLocation arg2, bool safepoint_pc) {
   RegStorage r_tgt = CallHelperSetup(helper_offset);
   LoadValueDirectFixed(arg2, TargetReg(kArg2));
   LoadCurrMethodDirect(TargetReg(kArg1));
   LoadConstant(TargetReg(kArg0), arg0);
   ClobberCallerSave();
-  CallHelper(r_tgt, helper_offset, safepoint_pc);
+  CallHelper<pointer_size>(r_tgt, helper_offset, safepoint_pc);
 }
+INSTANTIATE(void Mir2Lir::CallRuntimeHelperImmMethodRegLocation, int arg0, RegLocation arg2,
+            bool safepoint_pc)
 
-void Mir2Lir::CallRuntimeHelperImmMethodImm(ThreadOffset<4> helper_offset, int arg0,
+template <size_t pointer_size>
+void Mir2Lir::CallRuntimeHelperImmMethodImm(ThreadOffset<pointer_size> helper_offset, int arg0,
                                             int arg2, bool safepoint_pc) {
   RegStorage r_tgt = CallHelperSetup(helper_offset);
   LoadCurrMethodDirect(TargetReg(kArg1));
   LoadConstant(TargetReg(kArg2), arg2);
   LoadConstant(TargetReg(kArg0), arg0);
   ClobberCallerSave();
-  CallHelper(r_tgt, helper_offset, safepoint_pc);
+  CallHelper<pointer_size>(r_tgt, helper_offset, safepoint_pc);
 }
+INSTANTIATE(void Mir2Lir::CallRuntimeHelperImmMethodImm, int arg0, int arg2, bool safepoint_pc)
 
-void Mir2Lir::CallRuntimeHelperImmRegLocationRegLocation(ThreadOffset<4> helper_offset,
+template <size_t pointer_size>
+void Mir2Lir::CallRuntimeHelperImmRegLocationRegLocation(ThreadOffset<pointer_size> helper_offset,
                                                          int arg0, RegLocation arg1,
                                                          RegLocation arg2, bool safepoint_pc) {
   RegStorage r_tgt = CallHelperSetup(helper_offset);
-  DCHECK_EQ(arg1.wide, 0U);
+  DCHECK_EQ(static_cast<unsigned int>(arg1.wide), 0U);  // The static_cast works around an
+                                                        // instantiation bug in GCC.
   LoadValueDirectFixed(arg1, TargetReg(kArg1));
   if (arg2.wide == 0) {
     LoadValueDirectFixed(arg2, TargetReg(kArg2));
@@ -326,23 +401,28 @@
   }
   LoadConstant(TargetReg(kArg0), arg0);
   ClobberCallerSave();
-  CallHelper(r_tgt, helper_offset, safepoint_pc);
+  CallHelper<pointer_size>(r_tgt, helper_offset, safepoint_pc);
 }
+INSTANTIATE(void Mir2Lir::CallRuntimeHelperImmRegLocationRegLocation, int arg0, RegLocation arg1,
+            RegLocation arg2, bool safepoint_pc)
 
-void Mir2Lir::CallRuntimeHelperRegLocationRegLocationRegLocation(ThreadOffset<4> helper_offset,
+template <size_t pointer_size>
+void Mir2Lir::CallRuntimeHelperRegLocationRegLocationRegLocation(ThreadOffset<pointer_size> helper_offset,
                                                                  RegLocation arg0, RegLocation arg1,
                                                                  RegLocation arg2,
                                                                  bool safepoint_pc) {
   RegStorage r_tgt = CallHelperSetup(helper_offset);
-  DCHECK_EQ(arg0.wide, 0U);
+  DCHECK_EQ(static_cast<unsigned int>(arg0.wide), 0U);
   LoadValueDirectFixed(arg0, TargetReg(kArg0));
-  DCHECK_EQ(arg1.wide, 0U);
+  DCHECK_EQ(static_cast<unsigned int>(arg1.wide), 0U);
   LoadValueDirectFixed(arg1, TargetReg(kArg1));
-  DCHECK_EQ(arg1.wide, 0U);
+  DCHECK_EQ(static_cast<unsigned int>(arg1.wide), 0U);
   LoadValueDirectFixed(arg2, TargetReg(kArg2));
   ClobberCallerSave();
-  CallHelper(r_tgt, helper_offset, safepoint_pc);
+  CallHelper<pointer_size>(r_tgt, helper_offset, safepoint_pc);
 }
+INSTANTIATE(void Mir2Lir::CallRuntimeHelperRegLocationRegLocationRegLocation, RegLocation arg0,
+            RegLocation arg1, RegLocation arg2, bool safepoint_pc)
 
 /*
  * If there are any ins passed in registers that have not been promoted
@@ -627,7 +707,8 @@
   return state + 1;
 }
 
-static int NextInvokeInsnSP(CompilationUnit* cu, CallInfo* info, ThreadOffset<4> trampoline,
+template <size_t pointer_size>
+static int NextInvokeInsnSP(CompilationUnit* cu, CallInfo* info, ThreadOffset<pointer_size> trampoline,
                             int state, const MethodReference& target_method,
                             uint32_t method_idx) {
   Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
@@ -653,32 +734,52 @@
                                 const MethodReference& target_method,
                                 uint32_t unused, uintptr_t unused2,
                                 uintptr_t unused3, InvokeType unused4) {
-  ThreadOffset<4> trampoline = QUICK_ENTRYPOINT_OFFSET(4, pInvokeStaticTrampolineWithAccessCheck);
-  return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
+  if (Is64BitInstructionSet(cu->instruction_set)) {
+    ThreadOffset<8> trampoline = QUICK_ENTRYPOINT_OFFSET(8, pInvokeStaticTrampolineWithAccessCheck);
+    return NextInvokeInsnSP<8>(cu, info, trampoline, state, target_method, 0);
+  } else {
+    ThreadOffset<4> trampoline = QUICK_ENTRYPOINT_OFFSET(4, pInvokeStaticTrampolineWithAccessCheck);
+    return NextInvokeInsnSP<4>(cu, info, trampoline, state, target_method, 0);
+  }
 }
 
 static int NextDirectCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
                                 const MethodReference& target_method,
                                 uint32_t unused, uintptr_t unused2,
                                 uintptr_t unused3, InvokeType unused4) {
-  ThreadOffset<4> trampoline = QUICK_ENTRYPOINT_OFFSET(4, pInvokeDirectTrampolineWithAccessCheck);
-  return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
+  if (Is64BitInstructionSet(cu->instruction_set)) {
+    ThreadOffset<8> trampoline = QUICK_ENTRYPOINT_OFFSET(8, pInvokeDirectTrampolineWithAccessCheck);
+    return NextInvokeInsnSP<8>(cu, info, trampoline, state, target_method, 0);
+  } else {
+    ThreadOffset<4> trampoline = QUICK_ENTRYPOINT_OFFSET(4, pInvokeDirectTrampolineWithAccessCheck);
+    return NextInvokeInsnSP<4>(cu, info, trampoline, state, target_method, 0);
+  }
 }
 
 static int NextSuperCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
                                const MethodReference& target_method,
                                uint32_t unused, uintptr_t unused2,
                                uintptr_t unused3, InvokeType unused4) {
-  ThreadOffset<4> trampoline = QUICK_ENTRYPOINT_OFFSET(4, pInvokeSuperTrampolineWithAccessCheck);
-  return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
+  if (Is64BitInstructionSet(cu->instruction_set)) {
+    ThreadOffset<8> trampoline = QUICK_ENTRYPOINT_OFFSET(8, pInvokeSuperTrampolineWithAccessCheck);
+    return NextInvokeInsnSP<8>(cu, info, trampoline, state, target_method, 0);
+  } else {
+    ThreadOffset<4> trampoline = QUICK_ENTRYPOINT_OFFSET(4, pInvokeSuperTrampolineWithAccessCheck);
+    return NextInvokeInsnSP<4>(cu, info, trampoline, state, target_method, 0);
+  }
 }
 
 static int NextVCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
                            const MethodReference& target_method,
                            uint32_t unused, uintptr_t unused2,
                            uintptr_t unused3, InvokeType unused4) {
-  ThreadOffset<4> trampoline = QUICK_ENTRYPOINT_OFFSET(4, pInvokeVirtualTrampolineWithAccessCheck);
-  return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
+  if (Is64BitInstructionSet(cu->instruction_set)) {
+    ThreadOffset<8> trampoline = QUICK_ENTRYPOINT_OFFSET(8, pInvokeVirtualTrampolineWithAccessCheck);
+    return NextInvokeInsnSP<8>(cu, info, trampoline, state, target_method, 0);
+  } else {
+    ThreadOffset<4> trampoline = QUICK_ENTRYPOINT_OFFSET(4, pInvokeVirtualTrampolineWithAccessCheck);
+    return NextInvokeInsnSP<4>(cu, info, trampoline, state, target_method, 0);
+  }
 }
 
 static int NextInterfaceCallInsnWithAccessCheck(CompilationUnit* cu,
@@ -686,9 +787,13 @@
                                                 const MethodReference& target_method,
                                                 uint32_t unused, uintptr_t unused2,
                                                 uintptr_t unused3, InvokeType unused4) {
-  ThreadOffset<4> trampoline =
-      QUICK_ENTRYPOINT_OFFSET(4, pInvokeInterfaceTrampolineWithAccessCheck);
-  return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
+  if (Is64BitInstructionSet(cu->instruction_set)) {
+      ThreadOffset<8> trampoline = QUICK_ENTRYPOINT_OFFSET(8, pInvokeInterfaceTrampolineWithAccessCheck);
+      return NextInvokeInsnSP<8>(cu, info, trampoline, state, target_method, 0);
+    } else {
+      ThreadOffset<4> trampoline = QUICK_ENTRYPOINT_OFFSET(4, pInvokeInterfaceTrampolineWithAccessCheck);
+      return NextInvokeInsnSP<4>(cu, info, trampoline, state, target_method, 0);
+    }
 }
 
 int Mir2Lir::LoadArgRegs(CallInfo* info, int call_state,
@@ -696,8 +801,10 @@
                          const MethodReference& target_method,
                          uint32_t vtable_idx, uintptr_t direct_code,
                          uintptr_t direct_method, InvokeType type, bool skip_this) {
-  int last_arg_reg = TargetReg(kArg3).GetReg();
-  int next_reg = TargetReg(kArg1).GetReg();
+  int last_arg_reg = 3 - 1;
+  int arg_regs[3] = {TargetReg(kArg1).GetReg(), TargetReg(kArg2).GetReg(), TargetReg(kArg3).GetReg()};
+
+  int next_reg = 0;
   int next_arg = 0;
   if (skip_this) {
     next_reg++;
@@ -706,8 +813,8 @@
   for (; (next_reg <= last_arg_reg) && (next_arg < info->num_arg_words); next_reg++) {
     RegLocation rl_arg = info->args[next_arg++];
     rl_arg = UpdateRawLoc(rl_arg);
-    if (rl_arg.wide && (next_reg <= TargetReg(kArg2).GetReg())) {
-      RegStorage r_tmp(RegStorage::k64BitPair, next_reg, next_reg + 1);
+    if (rl_arg.wide && (next_reg <= last_arg_reg - 1)) {
+      RegStorage r_tmp(RegStorage::k64BitPair, arg_regs[next_reg], arg_regs[next_reg + 1]);
       LoadValueDirectWideFixed(rl_arg, r_tmp);
       next_reg++;
       next_arg++;
@@ -716,7 +823,7 @@
         rl_arg = NarrowRegLoc(rl_arg);
         rl_arg.is_const = false;
       }
-      LoadValueDirectFixed(rl_arg, RegStorage::Solo32(next_reg));
+      LoadValueDirectFixed(rl_arg, RegStorage::Solo32(arg_regs[next_reg]));
     }
     call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
                                 direct_code, direct_method, type);
@@ -1010,8 +1117,13 @@
     // Generate memcpy
     OpRegRegImm(kOpAdd, TargetReg(kArg0), TargetReg(kSp), outs_offset);
     OpRegRegImm(kOpAdd, TargetReg(kArg1), TargetReg(kSp), start_offset);
-    CallRuntimeHelperRegRegImm(QUICK_ENTRYPOINT_OFFSET(4, pMemcpy), TargetReg(kArg0),
-                               TargetReg(kArg1), (info->num_arg_words - 3) * 4, false);
+    if (Is64BitInstructionSet(cu_->instruction_set)) {
+      CallRuntimeHelperRegRegImm(QUICK_ENTRYPOINT_OFFSET(8, pMemcpy), TargetReg(kArg0),
+                                 TargetReg(kArg1), (info->num_arg_words - 3) * 4, false);
+    } else {
+      CallRuntimeHelperRegRegImm(QUICK_ENTRYPOINT_OFFSET(4, pMemcpy), TargetReg(kArg0),
+                                 TargetReg(kArg1), (info->num_arg_words - 3) * 4, false);
+    }
   }
 
   call_state = LoadArgRegs(info, call_state, next_call_insn,
@@ -1341,7 +1453,9 @@
     RegLocation rl_start = info->args[2];     // 3rd arg only present in III flavor of IndexOf.
     LoadValueDirectFixed(rl_start, reg_start);
   }
-  RegStorage r_tgt = LoadHelper(QUICK_ENTRYPOINT_OFFSET(4, pIndexOf));
+  RegStorage r_tgt = Is64BitInstructionSet(cu_->instruction_set) ?
+      LoadHelper(QUICK_ENTRYPOINT_OFFSET(8, pIndexOf)) :
+      LoadHelper(QUICK_ENTRYPOINT_OFFSET(4, pIndexOf));
   GenExplicitNullCheck(reg_ptr, info->opt_flags);
   LIR* high_code_point_branch =
       rl_char.is_const ? nullptr : OpCmpImmBranch(kCondGt, reg_char, 0xFFFF, nullptr);
@@ -1378,8 +1492,16 @@
   RegLocation rl_cmp = info->args[1];
   LoadValueDirectFixed(rl_this, reg_this);
   LoadValueDirectFixed(rl_cmp, reg_cmp);
-  RegStorage r_tgt = (cu_->instruction_set != kX86 && cu_->instruction_set != kX86_64) ?
-      LoadHelper(QUICK_ENTRYPOINT_OFFSET(4, pStringCompareTo)) : RegStorage::InvalidReg();
+  RegStorage r_tgt;
+  if (cu_->instruction_set != kX86 && cu_->instruction_set != kX86_64) {
+    if (Is64BitInstructionSet(cu_->instruction_set)) {
+      r_tgt = LoadHelper(QUICK_ENTRYPOINT_OFFSET(8, pStringCompareTo));
+    } else {
+      r_tgt = LoadHelper(QUICK_ENTRYPOINT_OFFSET(4, pStringCompareTo));
+    }
+  } else {
+    r_tgt = RegStorage::InvalidReg();
+  }
   GenExplicitNullCheck(reg_this, info->opt_flags);
   info->opt_flags |= MIR_IGNORE_NULL_CHECK;  // Record that we've null checked.
   // TUNING: check if rl_cmp.s_reg_low is already null checked
@@ -1389,7 +1511,11 @@
   if (cu_->instruction_set != kX86 && cu_->instruction_set != kX86_64) {
     OpReg(kOpBlx, r_tgt);
   } else {
-    OpThreadMem(kOpBlx, QUICK_ENTRYPOINT_OFFSET(4, pStringCompareTo));
+    if (Is64BitInstructionSet(cu_->instruction_set)) {
+      OpThreadMem(kOpBlx, QUICK_ENTRYPOINT_OFFSET(8, pStringCompareTo));
+    } else {
+      OpThreadMem(kOpBlx, QUICK_ENTRYPOINT_OFFSET(4, pStringCompareTo));
+    }
   }
   RegLocation rl_return = GetReturn(false);
   RegLocation rl_dest = InlineTarget(info);
@@ -1400,12 +1526,32 @@
 bool Mir2Lir::GenInlinedCurrentThread(CallInfo* info) {
   RegLocation rl_dest = InlineTarget(info);
   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
-  ThreadOffset<4> offset = Thread::PeerOffset<4>();
-  if (cu_->instruction_set == kThumb2 || cu_->instruction_set == kMips) {
-    Load32Disp(TargetReg(kSelf), offset.Int32Value(), rl_result.reg);
-  } else {
-    CHECK(cu_->instruction_set == kX86 || cu_->instruction_set == kX86_64);
-    reinterpret_cast<X86Mir2Lir*>(this)->OpRegThreadMem(kOpMov, rl_result.reg, offset);
+
+  switch (cu_->instruction_set) {
+    case kArm:
+      // Fall-through.
+    case kThumb2:
+      // Fall-through.
+    case kMips:
+      Load32Disp(TargetReg(kSelf), Thread::PeerOffset<4>().Int32Value(), rl_result.reg);
+      break;
+
+    case kArm64:
+      Load32Disp(TargetReg(kSelf), Thread::PeerOffset<8>().Int32Value(), rl_result.reg);
+      break;
+
+    case kX86:
+      reinterpret_cast<X86Mir2Lir*>(this)->OpRegThreadMem(kOpMov, rl_result.reg,
+                                                          Thread::PeerOffset<4>());
+      break;
+
+    case kX86_64:
+      reinterpret_cast<X86Mir2Lir*>(this)->OpRegThreadMem(kOpMov, rl_result.reg,
+                                                          Thread::PeerOffset<8>());
+      break;
+
+    default:
+      LOG(FATAL) << "Unexpected isa " << cu_->instruction_set;
   }
   StoreValue(rl_dest, rl_result);
   return true;
@@ -1427,7 +1573,7 @@
   RegLocation rl_offset = LoadValue(rl_src_offset, kCoreReg);
   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
   if (is_long) {
-    if (cu_->instruction_set == kX86) {
+    if (cu_->instruction_set == kX86 || cu_->instruction_set == kX86_64) {
       LoadBaseIndexedDisp(rl_object.reg, rl_offset.reg, 0, 0, rl_result.reg, k64);
     } else {
       RegStorage rl_temp_offset = AllocTemp();
@@ -1474,7 +1620,7 @@
   RegLocation rl_value;
   if (is_long) {
     rl_value = LoadValueWide(rl_src_value, kCoreReg);
-    if (cu_->instruction_set == kX86) {
+    if (cu_->instruction_set == kX86 || cu_->instruction_set == kX86_64) {
       StoreBaseIndexedDisp(rl_object.reg, rl_offset.reg, 0, 0, rl_value.reg, k64);
     } else {
       RegStorage rl_temp_offset = AllocTemp();
@@ -1519,6 +1665,31 @@
   GenInvokeNoInline(info);
 }
 
+template <size_t pointer_size>
+static LIR* GenInvokeNoInlineCall(Mir2Lir* mir_to_lir, InvokeType type) {
+  ThreadOffset<pointer_size> trampoline(-1);
+  switch (type) {
+    case kInterface:
+      trampoline = QUICK_ENTRYPOINT_OFFSET(pointer_size, pInvokeInterfaceTrampolineWithAccessCheck);
+      break;
+    case kDirect:
+      trampoline = QUICK_ENTRYPOINT_OFFSET(pointer_size, pInvokeDirectTrampolineWithAccessCheck);
+      break;
+    case kStatic:
+      trampoline = QUICK_ENTRYPOINT_OFFSET(pointer_size, pInvokeStaticTrampolineWithAccessCheck);
+      break;
+    case kSuper:
+      trampoline = QUICK_ENTRYPOINT_OFFSET(pointer_size, pInvokeSuperTrampolineWithAccessCheck);
+      break;
+    case kVirtual:
+      trampoline = QUICK_ENTRYPOINT_OFFSET(pointer_size, pInvokeVirtualTrampolineWithAccessCheck);
+      break;
+    default:
+      LOG(FATAL) << "Unexpected invoke type";
+  }
+  return mir_to_lir->OpThreadMem(kOpBlx, trampoline);
+}
+
 void Mir2Lir::GenInvokeNoInline(CallInfo* info) {
   int call_state = 0;
   LIR* null_ck;
@@ -1586,27 +1757,12 @@
                           mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value());
       }
     } else {
-      ThreadOffset<4> trampoline(-1);
-      switch (info->type) {
-      case kInterface:
-        trampoline = QUICK_ENTRYPOINT_OFFSET(4, pInvokeInterfaceTrampolineWithAccessCheck);
-        break;
-      case kDirect:
-        trampoline = QUICK_ENTRYPOINT_OFFSET(4, pInvokeDirectTrampolineWithAccessCheck);
-        break;
-      case kStatic:
-        trampoline = QUICK_ENTRYPOINT_OFFSET(4, pInvokeStaticTrampolineWithAccessCheck);
-        break;
-      case kSuper:
-        trampoline = QUICK_ENTRYPOINT_OFFSET(4, pInvokeSuperTrampolineWithAccessCheck);
-        break;
-      case kVirtual:
-        trampoline = QUICK_ENTRYPOINT_OFFSET(4, pInvokeVirtualTrampolineWithAccessCheck);
-        break;
-      default:
-        LOG(FATAL) << "Unexpected invoke type";
+      // TODO: Extract?
+      if (Is64BitInstructionSet(cu_->instruction_set)) {
+        call_inst = GenInvokeNoInlineCall<8>(this, info->type);
+      } else {
+        call_inst = GenInvokeNoInlineCall<4>(this, info->type);
       }
-      call_inst = OpThreadMem(kOpBlx, trampoline);
     }
   }
   MarkSafepointPC(call_inst);
diff --git a/compiler/dex/quick/gen_loadstore.cc b/compiler/dex/quick/gen_loadstore.cc
index faa9461..8fcb09b 100644
--- a/compiler/dex/quick/gen_loadstore.cc
+++ b/compiler/dex/quick/gen_loadstore.cc
@@ -139,12 +139,25 @@
 }
 
 RegLocation Mir2Lir::LoadValue(RegLocation rl_src, RegisterClass op_kind) {
-  rl_src = EvalLoc(rl_src, op_kind, false);
-  if (IsInexpensiveConstant(rl_src) || rl_src.location != kLocPhysReg) {
-    LoadValueDirect(rl_src, rl_src.reg);
-    rl_src.location = kLocPhysReg;
-    MarkLive(rl_src);
+  rl_src = UpdateLoc(rl_src);
+  if (rl_src.location == kLocPhysReg) {
+    if (!RegClassMatches(op_kind, rl_src.reg)) {
+      // Wrong register class, realloc, copy and transfer ownership.
+      RegStorage new_reg = AllocTypedTemp(rl_src.fp, op_kind);
+      OpRegCopy(new_reg, rl_src.reg);
+      // Associate the old sreg with the new register and clobber the old register.
+      GetRegInfo(new_reg)->SetSReg(GetRegInfo(rl_src.reg)->SReg());
+      Clobber(rl_src.reg);
+      rl_src.reg = new_reg;
+    }
+    return rl_src;
   }
+
+  DCHECK_NE(rl_src.s_reg_low, INVALID_SREG);
+  rl_src.reg = AllocTypedTemp(rl_src.fp, op_kind);
+  LoadValueDirect(rl_src, rl_src.reg);
+  rl_src.location = kLocPhysReg;
+  MarkLive(rl_src);
   return rl_src;
 }
 
@@ -203,12 +216,26 @@
 
 RegLocation Mir2Lir::LoadValueWide(RegLocation rl_src, RegisterClass op_kind) {
   DCHECK(rl_src.wide);
-  rl_src = EvalLoc(rl_src, op_kind, false);
-  if (IsInexpensiveConstant(rl_src) || rl_src.location != kLocPhysReg) {
-    LoadValueDirectWide(rl_src, rl_src.reg);
-    rl_src.location = kLocPhysReg;
-    MarkLive(rl_src);
+  rl_src = UpdateLocWide(rl_src);
+  if (rl_src.location == kLocPhysReg) {
+    if (!RegClassMatches(op_kind, rl_src.reg)) {
+      // Wrong register class, realloc, copy and transfer ownership.
+      RegStorage new_regs = AllocTypedTempWide(rl_src.fp, op_kind);
+      OpRegCopyWide(new_regs, rl_src.reg);
+      // Associate the old sreg with the new register and clobber the old register.
+      GetRegInfo(new_regs)->SetSReg(GetRegInfo(rl_src.reg)->SReg());
+      Clobber(rl_src.reg);
+      rl_src.reg = new_regs;
+    }
+    return rl_src;
   }
+
+  DCHECK_NE(rl_src.s_reg_low, INVALID_SREG);
+  DCHECK_NE(GetSRegHi(rl_src.s_reg_low), INVALID_SREG);
+  rl_src.reg = AllocTypedTempWide(rl_src.fp, op_kind);
+  LoadValueDirectWide(rl_src, rl_src.reg);
+  rl_src.location = kLocPhysReg;
+  MarkLive(rl_src);
   return rl_src;
 }
 
diff --git a/compiler/dex/quick/mips/codegen_mips.h b/compiler/dex/quick/mips/codegen_mips.h
index 90d5a28..b7ea34f 100644
--- a/compiler/dex/quick/mips/codegen_mips.h
+++ b/compiler/dex/quick/mips/codegen_mips.h
@@ -31,7 +31,8 @@
                             RegLocation rl_dest, int lit);
     bool EasyMultiply(RegLocation rl_src, RegLocation rl_dest, int lit) OVERRIDE;
     LIR* CheckSuspendUsingLoad() OVERRIDE;
-    RegStorage LoadHelper(ThreadOffset<4> offset);
+    RegStorage LoadHelper(ThreadOffset<4> offset) OVERRIDE;
+    RegStorage LoadHelper(ThreadOffset<8> offset) OVERRIDE;
     LIR* LoadBaseDispVolatile(RegStorage r_base, int displacement, RegStorage r_dest,
                               OpSize size) OVERRIDE;
     LIR* LoadBaseDisp(RegStorage r_base, int displacement, RegStorage r_dest,
@@ -171,12 +172,14 @@
     LIR* OpRegRegImm(OpKind op, RegStorage r_dest, RegStorage r_src1, int value);
     LIR* OpRegRegReg(OpKind op, RegStorage r_dest, RegStorage r_src1, RegStorage r_src2);
     LIR* OpTestSuspend(LIR* target);
-    LIR* OpThreadMem(OpKind op, ThreadOffset<4> thread_offset);
+    LIR* OpThreadMem(OpKind op, ThreadOffset<4> thread_offset) OVERRIDE;
+    LIR* OpThreadMem(OpKind op, ThreadOffset<8> thread_offset) OVERRIDE;
     LIR* OpVldm(RegStorage r_base, int count);
     LIR* OpVstm(RegStorage r_base, int count);
     void OpLea(RegStorage r_base, RegStorage reg1, RegStorage reg2, int scale, int offset);
     void OpRegCopyWide(RegStorage dest, RegStorage src);
-    void OpTlsCmp(ThreadOffset<4> offset, int val);
+    void OpTlsCmp(ThreadOffset<4> offset, int val) OVERRIDE;
+    void OpTlsCmp(ThreadOffset<8> offset, int val) OVERRIDE;
 
     // TODO: collapse r_dest.
     LIR* LoadBaseDispBody(RegStorage r_base, int displacement, RegStorage r_dest,
diff --git a/compiler/dex/quick/mips/int_mips.cc b/compiler/dex/quick/mips/int_mips.cc
index fdfe7fe..55e93d7 100644
--- a/compiler/dex/quick/mips/int_mips.cc
+++ b/compiler/dex/quick/mips/int_mips.cc
@@ -269,6 +269,10 @@
   LOG(FATAL) << "Unexpected use of OpTlsCmp for Arm";
 }
 
+void MipsMir2Lir::OpTlsCmp(ThreadOffset<8> offset, int val) {
+  UNIMPLEMENTED(FATAL) << "Should not be called.";
+}
+
 bool MipsMir2Lir::GenInlinedCas(CallInfo* info, bool is_long, bool is_object) {
   DCHECK_NE(cu_->instruction_set, kThumb2);
   return false;
diff --git a/compiler/dex/quick/mips/target_mips.cc b/compiler/dex/quick/mips/target_mips.cc
index 570c220..2821209 100644
--- a/compiler/dex/quick/mips/target_mips.cc
+++ b/compiler/dex/quick/mips/target_mips.cc
@@ -512,6 +512,11 @@
   return rs_rT9;
 }
 
+RegStorage MipsMir2Lir::LoadHelper(ThreadOffset<8> offset) {
+  UNIMPLEMENTED(FATAL) << "Should not be called.";
+  return RegStorage::InvalidReg();
+}
+
 LIR* MipsMir2Lir::CheckSuspendUsingLoad() {
   RegStorage tmp = AllocTemp();
   // NOTE: native pointer.
diff --git a/compiler/dex/quick/mips/utility_mips.cc b/compiler/dex/quick/mips/utility_mips.cc
index 58fbace..2757b7b 100644
--- a/compiler/dex/quick/mips/utility_mips.cc
+++ b/compiler/dex/quick/mips/utility_mips.cc
@@ -670,6 +670,11 @@
   return NULL;
 }
 
+LIR* MipsMir2Lir::OpThreadMem(OpKind op, ThreadOffset<8> thread_offset) {
+  UNIMPLEMENTED(FATAL) << "Should not be called.";
+  return nullptr;
+}
+
 LIR* MipsMir2Lir::OpMem(OpKind op, RegStorage r_base, int disp) {
   LOG(FATAL) << "Unexpected use of OpMem for MIPS";
   return NULL;
diff --git a/compiler/dex/quick/mir_to_lir-inl.h b/compiler/dex/quick/mir_to_lir-inl.h
index b5b50a4..2973e14 100644
--- a/compiler/dex/quick/mir_to_lir-inl.h
+++ b/compiler/dex/quick/mir_to_lir-inl.h
@@ -25,7 +25,8 @@
 
 /* Mark a temp register as dead.  Does not affect allocation state. */
 inline void Mir2Lir::ClobberBody(RegisterInfo* p) {
-  if (p->IsTemp()) {
+  DCHECK(p->IsTemp());
+  if (!p->IsDead()) {
     DCHECK(!(p->IsLive() && p->IsDirty()))  << "Live & dirty temp in clobber";
     p->MarkDead();
     p->ResetDefBody();
diff --git a/compiler/dex/quick/mir_to_lir.cc b/compiler/dex/quick/mir_to_lir.cc
index 0ffd189..2c4ca88 100644
--- a/compiler/dex/quick/mir_to_lir.cc
+++ b/compiler/dex/quick/mir_to_lir.cc
@@ -37,7 +37,7 @@
 }
 
 // TODO: needs revisit for 64-bit.
-RegStorage Mir2Lir::LoadArg(int in_position, bool wide) {
+RegStorage Mir2Lir::LoadArg(int in_position, RegisterClass reg_class, bool wide) {
   RegStorage reg_arg_low = GetArgMappingToPhysicalReg(in_position);
   RegStorage reg_arg_high = wide ? GetArgMappingToPhysicalReg(in_position + 1) :
       RegStorage::InvalidReg();
@@ -56,28 +56,45 @@
   if (wide && !reg_arg_high.Valid()) {
     // If the low part is not in a reg, we allocate a pair. Otherwise, we just load to high reg.
     if (!reg_arg_low.Valid()) {
-      RegStorage new_regs = AllocTypedTempWide(false, kAnyReg);
-      reg_arg_low = new_regs.GetLow();
-      reg_arg_high = new_regs.GetHigh();
+      RegStorage new_regs = AllocTypedTempWide(false, reg_class);
       LoadBaseDisp(TargetReg(kSp), offset, new_regs, k64);
+      return new_regs;  // The reg_class is OK, we can return.
     } else {
+      // Assume that no ABI allows splitting a wide fp reg between a narrow fp reg and memory,
+      // i.e. the low part is in a core reg. Load the second part in a core reg as well for now.
+      DCHECK(!reg_arg_low.IsFloat());
       reg_arg_high = AllocTemp();
       int offset_high = offset + sizeof(uint32_t);
       Load32Disp(TargetReg(kSp), offset_high, reg_arg_high);
+      // Continue below to check the reg_class.
     }
   }
 
   // If the low part is not in a register yet, we need to load it.
   if (!reg_arg_low.Valid()) {
-    reg_arg_low = AllocTemp();
+    // Assume that if the low part of a wide arg is passed in memory, so is the high part,
+    // thus we don't get here for wide args as it's handled above. Big-endian ABIs could
+    // conceivably break this assumption but Android supports only little-endian architectures.
+    DCHECK(!wide);
+    reg_arg_low = AllocTypedTemp(false, reg_class);
     Load32Disp(TargetReg(kSp), offset, reg_arg_low);
+    return reg_arg_low;  // The reg_class is OK, we can return.
   }
 
-  if (wide) {
-    return RegStorage::MakeRegPair(reg_arg_low, reg_arg_high);
-  } else {
-    return reg_arg_low;
+  RegStorage reg_arg = wide ? RegStorage::MakeRegPair(reg_arg_low, reg_arg_high) : reg_arg_low;
+  // Check if we need to copy the arg to a different reg_class.
+  if (!RegClassMatches(reg_class, reg_arg)) {
+    if (wide) {
+      RegStorage new_regs = AllocTypedTempWide(false, reg_class);
+      OpRegCopyWide(new_regs, reg_arg);
+      reg_arg = new_regs;
+    } else {
+      RegStorage new_reg = AllocTypedTemp(false, reg_class);
+      OpRegCopy(new_reg, reg_arg);
+      reg_arg = new_reg;
+    }
   }
+  return reg_arg;
 }
 
 void Mir2Lir::LoadArgDirect(int in_position, RegLocation rl_dest) {
@@ -138,16 +155,29 @@
   // Point of no return - no aborts after this
   GenPrintLabel(mir);
   LockArg(data.object_arg);
+  RegStorage reg_obj = LoadArg(data.object_arg, kCoreReg);
   RegLocation rl_dest = wide ? GetReturnWide(double_or_float) : GetReturn(double_or_float);
-  RegStorage reg_obj = LoadArg(data.object_arg);
+  RegisterClass reg_class = RegClassForFieldLoadStore(size, data.is_volatile);
+  RegStorage r_result = rl_dest.reg;
+  if (!RegClassMatches(reg_class, r_result)) {
+    r_result = wide ? AllocTypedTempWide(rl_dest.fp, reg_class)
+                    : AllocTypedTemp(rl_dest.fp, reg_class);
+  }
   if (data.is_volatile) {
-    LoadBaseDispVolatile(reg_obj, data.field_offset, rl_dest.reg, size);
+    LoadBaseDispVolatile(reg_obj, data.field_offset, r_result, size);
     // Without context sensitive analysis, we must issue the most conservative barriers.
     // In this case, either a load or store may follow so we issue both barriers.
     GenMemBarrier(kLoadLoad);
     GenMemBarrier(kLoadStore);
   } else {
-    LoadBaseDisp(reg_obj, data.field_offset, rl_dest.reg, size);
+    LoadBaseDisp(reg_obj, data.field_offset, r_result, size);
+  }
+  if (r_result != rl_dest.reg) {
+    if (wide) {
+      OpRegCopyWide(rl_dest.reg, r_result);
+    } else {
+      OpRegCopy(rl_dest.reg, r_result);
+    }
   }
   return true;
 }
@@ -175,8 +205,9 @@
   GenPrintLabel(mir);
   LockArg(data.object_arg);
   LockArg(data.src_arg, wide);
-  RegStorage reg_obj = LoadArg(data.object_arg);
-  RegStorage reg_src = LoadArg(data.src_arg, wide);
+  RegStorage reg_obj = LoadArg(data.object_arg, kCoreReg);
+  RegisterClass reg_class = RegClassForFieldLoadStore(size, data.is_volatile);
+  RegStorage reg_src = LoadArg(data.src_arg, reg_class, wide);
   if (data.is_volatile) {
     // There might have been a store before this volatile one so insert StoreStore barrier.
     GenMemBarrier(kStoreStore);
@@ -979,7 +1010,7 @@
   }
 
   // Free temp registers and reset redundant store tracking.
-  ClobberAllRegs();
+  ClobberAllTemps();
 
   if (bb->block_type == kEntryBlock) {
     ResetRegPool();
@@ -994,7 +1025,7 @@
   for (mir = bb->first_mir_insn; mir != NULL; mir = mir->next) {
     ResetRegPool();
     if (cu_->disable_opt & (1 << kTrackLiveTemps)) {
-      ClobberAllRegs();
+      ClobberAllTemps();
       // Reset temp allocation to minimize differences when A/B testing.
       reg_pool_->ResetNextTemp();
     }
@@ -1074,7 +1105,7 @@
   // Free temp registers and reset redundant store tracking.
   ResetRegPool();
   ResetDefTracking();
-  ClobberAllRegs();
+  ClobberAllTemps();
 
   return GenSpecialCase(bb, mir, special);
 }
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index 74245a4..6a0f3b2 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -333,6 +333,9 @@
       bool InUse() { return (storage_mask_ & master_->used_storage_) != 0; }
       void MarkInUse() { master_->used_storage_ |= storage_mask_; }
       void MarkFree() { master_->used_storage_ &= ~storage_mask_; }
+      // No part of the containing storage is live in this view.
+      bool IsDead() { return (master_->liveness_ & storage_mask_) == 0; }
+      // Liveness of this view matches.  Note: not equivalent to !IsDead().
       bool IsLive() { return (master_->liveness_ & storage_mask_) == storage_mask_; }
       void MarkLive() { master_->liveness_ |= storage_mask_; }
       void MarkDead() {
@@ -358,9 +361,13 @@
         master_ = master;
         if (master != this) {
           master_->aliased_ = true;
+          DCHECK(alias_chain_ == nullptr);
+          alias_chain_ = master_->alias_chain_;
+          master_->alias_chain_ = this;
         }
       }
       bool IsAliased() { return aliased_; }
+      RegisterInfo* GetAliasChain() { return alias_chain_; }
       uint32_t StorageMask() { return storage_mask_; }
       void SetStorageMask(uint32_t storage_mask) { storage_mask_ = storage_mask; }
       LIR* DefStart() { return def_start_; }
@@ -385,6 +392,7 @@
       uint32_t storage_mask_;      // Track allocation of sub-units.
       LIR *def_start_;             // Starting inst in last def sequence.
       LIR *def_end_;               // Ending inst in last def sequence.
+      RegisterInfo* alias_chain_;  // Chain of aliased registers.
     };
 
     class RegisterPool {
@@ -462,7 +470,7 @@
      public:
       LIRSlowPath(Mir2Lir* m2l, const DexOffset dexpc, LIR* fromfast,
                   LIR* cont = nullptr) :
-        m2l_(m2l), current_dex_pc_(dexpc), fromfast_(fromfast), cont_(cont) {
+        m2l_(m2l), cu_(m2l->cu_), current_dex_pc_(dexpc), fromfast_(fromfast), cont_(cont) {
       }
       virtual ~LIRSlowPath() {}
       virtual void Compile() = 0;
@@ -475,6 +483,7 @@
       LIR* GenerateTargetLabel(int opcode = kPseudoTargetLabel);
 
       Mir2Lir* const m2l_;
+      CompilationUnit* const cu_;
       const DexOffset current_dex_pc_;
       LIR* const fromfast_;
       LIR* const cont_;
@@ -655,7 +664,7 @@
     void ResetDefLoc(RegLocation rl);
     void ResetDefLocWide(RegLocation rl);
     void ResetDefTracking();
-    void ClobberAllRegs();
+    void ClobberAllTemps();
     void FlushSpecificReg(RegisterInfo* info);
     void FlushAllRegs();
     bool RegClassMatches(int reg_class, RegStorage reg);
@@ -673,9 +682,9 @@
     RegLocation UpdateRawLoc(RegLocation loc);
 
     /**
-     * @brief Used to load register location into a typed temporary or pair of temporaries.
+     * @brief Used to prepare a register location to receive a wide value.
      * @see EvalLoc
-     * @param loc The register location to load from.
+     * @param loc the location where the value will be stored.
      * @param reg_class Type of register needed.
      * @param update Whether the liveness information should be updated.
      * @return Returns the properly typed temporary in physical register pairs.
@@ -683,8 +692,8 @@
     RegLocation EvalLocWide(RegLocation loc, int reg_class, bool update);
 
     /**
-     * @brief Used to load register location into a typed temporary.
-     * @param loc The register location to load from.
+     * @brief Used to prepare a register location to receive a value.
+     * @param loc the location where the value will be stored.
      * @param reg_class Type of register needed.
      * @param update Whether the liveness information should be updated.
      * @return Returns the properly typed temporary in physical register.
@@ -756,7 +765,8 @@
                           RegLocation rl_src, int lit);
     void GenArithOpLong(Instruction::Code opcode, RegLocation rl_dest,
                         RegLocation rl_src1, RegLocation rl_src2);
-    void GenConversionCall(ThreadOffset<4> func_offset, RegLocation rl_dest,
+    template <size_t pointer_size>
+    void GenConversionCall(ThreadOffset<pointer_size> func_offset, RegLocation rl_dest,
                            RegLocation rl_src);
     void GenSuspendTest(int opt_flags);
     void GenSuspendTestAndBranch(int opt_flags, LIR* target);
@@ -767,45 +777,66 @@
                        RegLocation rl_src1, RegLocation rl_src2);
 
     // Shared by all targets - implemented in gen_invoke.cc.
-    LIR* CallHelper(RegStorage r_tgt, ThreadOffset<4> helper_offset, bool safepoint_pc,
+    template <size_t pointer_size>
+    LIR* CallHelper(RegStorage r_tgt, ThreadOffset<pointer_size> helper_offset, bool safepoint_pc,
                     bool use_link = true);
     RegStorage CallHelperSetup(ThreadOffset<4> helper_offset);
-    void CallRuntimeHelper(ThreadOffset<4> helper_offset, bool safepoint_pc);
-    void CallRuntimeHelperImm(ThreadOffset<4> helper_offset, int arg0, bool safepoint_pc);
-    void CallRuntimeHelperReg(ThreadOffset<4> helper_offset, RegStorage arg0, bool safepoint_pc);
-    void CallRuntimeHelperRegLocation(ThreadOffset<4> helper_offset, RegLocation arg0,
+    RegStorage CallHelperSetup(ThreadOffset<8> helper_offset);
+    template <size_t pointer_size>
+    void CallRuntimeHelper(ThreadOffset<pointer_size> helper_offset, bool safepoint_pc);
+    template <size_t pointer_size>
+    void CallRuntimeHelperImm(ThreadOffset<pointer_size> helper_offset, int arg0, bool safepoint_pc);
+    template <size_t pointer_size>
+    void CallRuntimeHelperReg(ThreadOffset<pointer_size> helper_offset, RegStorage arg0, bool safepoint_pc);
+    template <size_t pointer_size>
+    void CallRuntimeHelperRegLocation(ThreadOffset<pointer_size> helper_offset, RegLocation arg0,
                                       bool safepoint_pc);
-    void CallRuntimeHelperImmImm(ThreadOffset<4> helper_offset, int arg0, int arg1,
+    template <size_t pointer_size>
+    void CallRuntimeHelperImmImm(ThreadOffset<pointer_size> helper_offset, int arg0, int arg1,
                                  bool safepoint_pc);
-    void CallRuntimeHelperImmRegLocation(ThreadOffset<4> helper_offset, int arg0,
+    template <size_t pointer_size>
+    void CallRuntimeHelperImmRegLocation(ThreadOffset<pointer_size> helper_offset, int arg0,
                                          RegLocation arg1, bool safepoint_pc);
-    void CallRuntimeHelperRegLocationImm(ThreadOffset<4> helper_offset, RegLocation arg0,
+    template <size_t pointer_size>
+    void CallRuntimeHelperRegLocationImm(ThreadOffset<pointer_size> helper_offset, RegLocation arg0,
                                          int arg1, bool safepoint_pc);
-    void CallRuntimeHelperImmReg(ThreadOffset<4> helper_offset, int arg0, RegStorage arg1,
+    template <size_t pointer_size>
+    void CallRuntimeHelperImmReg(ThreadOffset<pointer_size> helper_offset, int arg0, RegStorage arg1,
                                  bool safepoint_pc);
-    void CallRuntimeHelperRegImm(ThreadOffset<4> helper_offset, RegStorage arg0, int arg1,
+    template <size_t pointer_size>
+    void CallRuntimeHelperRegImm(ThreadOffset<pointer_size> helper_offset, RegStorage arg0, int arg1,
                                  bool safepoint_pc);
-    void CallRuntimeHelperImmMethod(ThreadOffset<4> helper_offset, int arg0,
+    template <size_t pointer_size>
+    void CallRuntimeHelperImmMethod(ThreadOffset<pointer_size> helper_offset, int arg0,
                                     bool safepoint_pc);
-    void CallRuntimeHelperRegMethod(ThreadOffset<4> helper_offset, RegStorage arg0,
+    template <size_t pointer_size>
+    void CallRuntimeHelperRegMethod(ThreadOffset<pointer_size> helper_offset, RegStorage arg0,
                                     bool safepoint_pc);
-    void CallRuntimeHelperRegMethodRegLocation(ThreadOffset<4> helper_offset, RegStorage arg0,
-                                               RegLocation arg2, bool safepoint_pc);
-    void CallRuntimeHelperRegLocationRegLocation(ThreadOffset<4> helper_offset,
+    template <size_t pointer_size>
+    void CallRuntimeHelperRegMethodRegLocation(ThreadOffset<pointer_size> helper_offset,
+                                               RegStorage arg0, RegLocation arg2, bool safepoint_pc);
+    template <size_t pointer_size>
+    void CallRuntimeHelperRegLocationRegLocation(ThreadOffset<pointer_size> helper_offset,
                                                  RegLocation arg0, RegLocation arg1,
                                                  bool safepoint_pc);
-    void CallRuntimeHelperRegReg(ThreadOffset<4> helper_offset, RegStorage arg0, RegStorage arg1,
-                                 bool safepoint_pc);
-    void CallRuntimeHelperRegRegImm(ThreadOffset<4> helper_offset, RegStorage arg0, RegStorage arg1,
-                                    int arg2, bool safepoint_pc);
-    void CallRuntimeHelperImmMethodRegLocation(ThreadOffset<4> helper_offset, int arg0,
+    template <size_t pointer_size>
+    void CallRuntimeHelperRegReg(ThreadOffset<pointer_size> helper_offset, RegStorage arg0,
+                                 RegStorage arg1, bool safepoint_pc);
+    template <size_t pointer_size>
+    void CallRuntimeHelperRegRegImm(ThreadOffset<pointer_size> helper_offset, RegStorage arg0,
+                                    RegStorage arg1, int arg2, bool safepoint_pc);
+    template <size_t pointer_size>
+    void CallRuntimeHelperImmMethodRegLocation(ThreadOffset<pointer_size> helper_offset, int arg0,
                                                RegLocation arg2, bool safepoint_pc);
-    void CallRuntimeHelperImmMethodImm(ThreadOffset<4> helper_offset, int arg0, int arg2,
+    template <size_t pointer_size>
+    void CallRuntimeHelperImmMethodImm(ThreadOffset<pointer_size> helper_offset, int arg0, int arg2,
                                        bool safepoint_pc);
-    void CallRuntimeHelperImmRegLocationRegLocation(ThreadOffset<4> helper_offset,
+    template <size_t pointer_size>
+    void CallRuntimeHelperImmRegLocationRegLocation(ThreadOffset<pointer_size> helper_offset,
                                                     int arg0, RegLocation arg1, RegLocation arg2,
                                                     bool safepoint_pc);
-    void CallRuntimeHelperRegLocationRegLocationRegLocation(ThreadOffset<4> helper_offset,
+    template <size_t pointer_size>
+    void CallRuntimeHelperRegLocationRegLocationRegLocation(ThreadOffset<pointer_size> helper_offset,
                                                             RegLocation arg0, RegLocation arg1,
                                                             RegLocation arg2,
                                                             bool safepoint_pc);
@@ -1002,7 +1033,10 @@
                                     RegLocation rl_src, RegLocation rl_dest, int lit) = 0;
     virtual bool EasyMultiply(RegLocation rl_src, RegLocation rl_dest, int lit) = 0;
     virtual LIR* CheckSuspendUsingLoad() = 0;
+
     virtual RegStorage LoadHelper(ThreadOffset<4> offset) = 0;
+    virtual RegStorage LoadHelper(ThreadOffset<8> offset) = 0;
+
     virtual LIR* LoadBaseDispVolatile(RegStorage r_base, int displacement, RegStorage r_dest,
                                       OpSize size) = 0;
     virtual LIR* LoadBaseDisp(RegStorage r_base, int displacement, RegStorage r_dest,
@@ -1233,12 +1267,14 @@
                              RegStorage r_src2) = 0;
     virtual LIR* OpTestSuspend(LIR* target) = 0;
     virtual LIR* OpThreadMem(OpKind op, ThreadOffset<4> thread_offset) = 0;
+    virtual LIR* OpThreadMem(OpKind op, ThreadOffset<8> thread_offset) = 0;
     virtual LIR* OpVldm(RegStorage r_base, int count) = 0;
     virtual LIR* OpVstm(RegStorage r_base, int count) = 0;
     virtual void OpLea(RegStorage r_base, RegStorage reg1, RegStorage reg2, int scale,
                        int offset) = 0;
     virtual void OpRegCopyWide(RegStorage dest, RegStorage src) = 0;
     virtual void OpTlsCmp(ThreadOffset<4> offset, int val) = 0;
+    virtual void OpTlsCmp(ThreadOffset<8> offset, int val) = 0;
     virtual bool InexpensiveConstantInt(int32_t value) = 0;
     virtual bool InexpensiveConstantFloat(int32_t value) = 0;
     virtual bool InexpensiveConstantLong(int64_t value) = 0;
@@ -1361,7 +1397,7 @@
      * @param wide Whether the argument is 64-bit or not.
      * @return Returns the register (or register pair) for the loaded argument.
      */
-    RegStorage LoadArg(int in_position, bool wide = false);
+    RegStorage LoadArg(int in_position, RegisterClass reg_class, bool wide = false);
 
     /**
      * @brief Used to load a VR argument directly to a specified register location.
diff --git a/compiler/dex/quick/ralloc_util.cc b/compiler/dex/quick/ralloc_util.cc
index ca9a3ab..bcc077b 100644
--- a/compiler/dex/quick/ralloc_util.cc
+++ b/compiler/dex/quick/ralloc_util.cc
@@ -40,7 +40,8 @@
 
 Mir2Lir::RegisterInfo::RegisterInfo(RegStorage r, uint64_t mask)
   : reg_(r), is_temp_(false), wide_value_(false), dirty_(false), aliased_(false), partner_(r),
-    s_reg_(INVALID_SREG), def_use_mask_(mask), master_(this) {
+    s_reg_(INVALID_SREG), def_use_mask_(mask), master_(this), def_start_(nullptr),
+    def_end_(nullptr), alias_chain_(nullptr) {
   switch (r.StorageSize()) {
     case 0: storage_mask_ = 0xffffffff; break;
     case 4: storage_mask_ = 0x00000001; break;
@@ -66,9 +67,13 @@
     next_sp_reg_(0), dp_regs_(arena, dp_regs.size()), next_dp_reg_(0), m2l_(m2l)  {
   // Initialize the fast lookup map.
   m2l_->reginfo_map_.Reset();
-  m2l_->reginfo_map_.Resize(RegStorage::kMaxRegs);
-  for (unsigned i = 0; i < RegStorage::kMaxRegs; i++) {
-    m2l_->reginfo_map_.Insert(nullptr);
+  if (kIsDebugBuild) {
+    m2l_->reginfo_map_.Resize(RegStorage::kMaxRegs);
+    for (unsigned i = 0; i < RegStorage::kMaxRegs; i++) {
+      m2l_->reginfo_map_.Insert(nullptr);
+    }
+  } else {
+    m2l_->reginfo_map_.SetSize(RegStorage::kMaxRegs);
   }
 
   // Construct the register pool.
@@ -139,29 +144,43 @@
 }
 
 void Mir2Lir::Clobber(RegStorage reg) {
-  if (reg.IsPair()) {
+  if (UNLIKELY(reg.IsPair())) {
     DCHECK(!GetRegInfo(reg.GetLow())->IsAliased());
-    ClobberBody(GetRegInfo(reg.GetLow()));
+    Clobber(reg.GetLow());
     DCHECK(!GetRegInfo(reg.GetHigh())->IsAliased());
-    ClobberBody(GetRegInfo(reg.GetHigh()));
+    Clobber(reg.GetHigh());
   } else {
     RegisterInfo* info = GetRegInfo(reg);
-    if (info->IsAliased()) {
-      ClobberAliases(info);
-    } else if (info != info->Master() && info->Master()->SReg() != INVALID_SREG) {
-      ClobberBody(info->Master());
+    if (info->IsTemp() && !info->IsDead()) {
+      ClobberBody(info);
+      if (info->IsAliased()) {
+        ClobberAliases(info);
+      } else {
+        RegisterInfo* master = info->Master();
+        if (info != master) {
+          ClobberBody(info->Master());
+        }
+      }
     }
-    ClobberBody(info);
   }
 }
 
 void Mir2Lir::ClobberAliases(RegisterInfo* info) {
-  DCHECK(info->IsAliased());
-  GrowableArray<RegisterInfo*>::Iterator iter(&tempreg_info_);
-  for (RegisterInfo* tmpreg_info = iter.Next(); tmpreg_info != NULL; tmpreg_info = iter.Next()) {
-    if (tmpreg_info->Master() == info) {
-      // tmpreg_info is an alias of info.
-      ClobberBody(tmpreg_info);
+  for (RegisterInfo* alias = info->GetAliasChain(); alias != nullptr;
+       alias = alias->GetAliasChain()) {
+    DCHECK(!alias->IsAliased());  // Only the master should be marked as alised.
+    if (alias->SReg() != INVALID_SREG) {
+      alias->SetSReg(INVALID_SREG);
+      alias->ResetDefBody();
+      if (alias->IsWide()) {
+        alias->SetIsWide(false);
+        if (alias->GetReg() != alias->Partner()) {
+          RegisterInfo* p = GetRegInfo(alias->Partner());
+          p->SetIsWide(false);
+          p->MarkDead();
+          p->ResetDefBody();
+        }
+      }
     }
   }
 }
@@ -185,11 +204,10 @@
     GrowableArray<RegisterInfo*>::Iterator iter(&tempreg_info_);
     for (RegisterInfo* info = iter.Next(); info != NULL; info = iter.Next()) {
       if (info->SReg() == s_reg) {
+        ClobberBody(info);
         if (info->IsAliased()) {
-          // TUNING: if this gets hot, we could add links to follow - aliasing is static.
           ClobberAliases(info);
         }
-        ClobberBody(info);
       }
     }
   }
@@ -645,7 +663,7 @@
   }
 }
 
-void Mir2Lir::ClobberAllRegs() {
+void Mir2Lir::ClobberAllTemps() {
   GrowableArray<RegisterInfo*>::Iterator iter(&tempreg_info_);
   for (RegisterInfo* info = iter.Next(); info != NULL; info = iter.Next()) {
     ClobberBody(info);
@@ -703,10 +721,9 @@
 void Mir2Lir::FlushAllRegs() {
   GrowableArray<RegisterInfo*>::Iterator it(&tempreg_info_);
   for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
-    if (info->IsLive() && info->IsDirty()) {
+    if (info->IsDirty() && info->IsLive()) {
       FlushSpecificReg(info);
     }
-    DCHECK(info->IsTemp());
     info->MarkDead();
     info->SetSReg(INVALID_SREG);
     info->ResetDefBody();
@@ -937,9 +954,8 @@
   /* If already in registers, we can assume proper form.  Right reg class? */
   if (loc.location == kLocPhysReg) {
     if (!RegClassMatches(reg_class, loc.reg)) {
-      /* Wrong register class.  Reallocate and copy */
+      // Wrong register class.  Reallocate and transfer ownership.
       RegStorage new_regs = AllocTypedTempWide(loc.fp, reg_class);
-      OpRegCopyWide(new_regs, loc.reg);
       // Associate the old sreg with the new register and clobber the old register.
       GetRegInfo(new_regs)->SetSReg(GetRegInfo(loc.reg)->SReg());
       Clobber(loc.reg);
@@ -971,9 +987,8 @@
 
   if (loc.location == kLocPhysReg) {
     if (!RegClassMatches(reg_class, loc.reg)) {
-      /* Wrong register class.  Realloc, copy and transfer ownership */
+      // Wrong register class.  Reallocate and transfer ownership.
       RegStorage new_reg = AllocTypedTemp(loc.fp, reg_class);
-      OpRegCopy(new_reg, loc.reg);
       // Associate the old sreg with the new register and clobber the old register.
       GetRegInfo(new_reg)->SetSReg(GetRegInfo(loc.reg)->SReg());
       Clobber(loc.reg);
diff --git a/compiler/dex/quick/x86/call_x86.cc b/compiler/dex/quick/x86/call_x86.cc
index f701a1f..cf2b10a 100644
--- a/compiler/dex/quick/x86/call_x86.cc
+++ b/compiler/dex/quick/x86/call_x86.cc
@@ -161,7 +161,9 @@
 }
 
 void X86Mir2Lir::GenMoveException(RegLocation rl_dest) {
-  int ex_offset = Thread::ExceptionOffset<4>().Int32Value();
+  int ex_offset = Is64BitInstructionSet(cu_->instruction_set) ?
+      Thread::ExceptionOffset<8>().Int32Value() :
+      Thread::ExceptionOffset<4>().Int32Value();
   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
   NewLIR2(kX86Mov32RT, rl_result.reg.GetReg(), ex_offset);
   NewLIR2(kX86Mov32TI, ex_offset, 0);
@@ -175,7 +177,10 @@
   RegStorage reg_card_base = AllocTemp();
   RegStorage reg_card_no = AllocTemp();
   LIR* branch_over = OpCmpImmBranch(kCondEq, val_reg, 0, NULL);
-  NewLIR2(kX86Mov32RT, reg_card_base.GetReg(), Thread::CardTableOffset<4>().Int32Value());
+  int ct_offset = Is64BitInstructionSet(cu_->instruction_set) ?
+      Thread::CardTableOffset<8>().Int32Value() :
+      Thread::CardTableOffset<4>().Int32Value();
+  NewLIR2(kX86Mov32RT, reg_card_base.GetReg(), ct_offset);
   OpRegRegImm(kOpLsr, reg_card_no, tgt_addr_reg, gc::accounting::CardTable::kCardShift);
   StoreBaseIndexed(reg_card_base, reg_card_no, reg_card_base, 0, kUnsignedByte);
   LIR* target = NewLIR0(kPseudoTargetLabel);
@@ -222,10 +227,14 @@
         GenerateTargetLabel(kPseudoThrowTarget);
         m2l_->OpRegImm(kOpAdd, rs_rX86_SP, sp_displace_);
         m2l_->ClobberCallerSave();
-        ThreadOffset<4> func_offset = QUICK_ENTRYPOINT_OFFSET(4, pThrowStackOverflow);
         // Assumes codegen and target are in thumb2 mode.
-        m2l_->CallHelper(RegStorage::InvalidReg(), func_offset, false /* MarkSafepointPC */,
-                         false /* UseLink */);
+        if (Is64BitInstructionSet(cu_->instruction_set)) {
+          m2l_->CallHelper(RegStorage::InvalidReg(), QUICK_ENTRYPOINT_OFFSET(8, pThrowStackOverflow),
+                           false /* MarkSafepointPC */, false /* UseLink */);
+        } else {
+          m2l_->CallHelper(RegStorage::InvalidReg(), QUICK_ENTRYPOINT_OFFSET(4, pThrowStackOverflow),
+                                     false /* MarkSafepointPC */, false /* UseLink */);
+        }
       }
 
      private:
@@ -240,9 +249,15 @@
     // in case a signal comes in that's not using an alternate signal stack and the large frame may
     // have moved us outside of the reserved area at the end of the stack.
     // cmp rX86_SP, fs:[stack_end_]; jcc throw_slowpath
-    OpRegThreadMem(kOpCmp, rs_rX86_SP, Thread::StackEndOffset<4>());
+    if (Is64BitInstructionSet(cu_->instruction_set)) {
+      OpRegThreadMem(kOpCmp, rs_rX86_SP, Thread::StackEndOffset<8>());
+    } else {
+      OpRegThreadMem(kOpCmp, rs_rX86_SP, Thread::StackEndOffset<4>());
+    }
     LIR* branch = OpCondBranch(kCondUlt, nullptr);
-    AddSlowPath(new(arena_)StackOverflowSlowPath(this, branch, frame_size_ - 4));
+    AddSlowPath(new(arena_)StackOverflowSlowPath(this, branch,
+                                                 frame_size_ -
+                                                 GetInstructionSetPointerSize(cu_->instruction_set)));
   }
 
   FlushIns(ArgLocs, rl_method);
diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h
index 9648312..11e7ff9 100644
--- a/compiler/dex/quick/x86/codegen_x86.h
+++ b/compiler/dex/quick/x86/codegen_x86.h
@@ -31,7 +31,8 @@
                             RegLocation rl_dest, int lit);
     bool EasyMultiply(RegLocation rl_src, RegLocation rl_dest, int lit) OVERRIDE;
     LIR* CheckSuspendUsingLoad() OVERRIDE;
-    RegStorage LoadHelper(ThreadOffset<4> offset);
+    RegStorage LoadHelper(ThreadOffset<4> offset) OVERRIDE;
+    RegStorage LoadHelper(ThreadOffset<8> offset) OVERRIDE;
     LIR* LoadBaseDispVolatile(RegStorage r_base, int displacement, RegStorage r_dest,
                               OpSize size) OVERRIDE;
     LIR* LoadBaseDisp(RegStorage r_base, int displacement, RegStorage r_dest,
@@ -245,14 +246,17 @@
     LIR* OpRegRegImm(OpKind op, RegStorage r_dest, RegStorage r_src1, int value);
     LIR* OpRegRegReg(OpKind op, RegStorage r_dest, RegStorage r_src1, RegStorage r_src2);
     LIR* OpTestSuspend(LIR* target);
-    LIR* OpThreadMem(OpKind op, ThreadOffset<4> thread_offset);
+    LIR* OpThreadMem(OpKind op, ThreadOffset<4> thread_offset) OVERRIDE;
+    LIR* OpThreadMem(OpKind op, ThreadOffset<8> thread_offset) OVERRIDE;
     LIR* OpVldm(RegStorage r_base, int count);
     LIR* OpVstm(RegStorage r_base, int count);
     void OpLea(RegStorage r_base, RegStorage reg1, RegStorage reg2, int scale, int offset);
     void OpRegCopyWide(RegStorage dest, RegStorage src);
-    void OpTlsCmp(ThreadOffset<4> offset, int val);
+    void OpTlsCmp(ThreadOffset<4> offset, int val) OVERRIDE;
+    void OpTlsCmp(ThreadOffset<8> offset, int val) OVERRIDE;
 
     void OpRegThreadMem(OpKind op, RegStorage r_dest, ThreadOffset<4> thread_offset);
+    void OpRegThreadMem(OpKind op, RegStorage r_dest, ThreadOffset<8> thread_offset);
     void SpillCoreRegs();
     void UnSpillCoreRegs();
     static const X86EncodingMap EncodingMap[kX86Last];
diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc
index 698fce4..368234e 100644
--- a/compiler/dex/quick/x86/int_x86.cc
+++ b/compiler/dex/quick/x86/int_x86.cc
@@ -724,6 +724,12 @@
 }
 
 void X86Mir2Lir::OpTlsCmp(ThreadOffset<4> offset, int val) {
+  DCHECK_EQ(kX86, cu_->instruction_set);
+  NewLIR2(kX86Cmp16TI8, offset.Int32Value(), val);
+}
+
+void X86Mir2Lir::OpTlsCmp(ThreadOffset<8> offset, int val) {
+  DCHECK_EQ(kX86_64, cu_->instruction_set);
   NewLIR2(kX86Cmp16TI8, offset.Int32Value(), val);
 }
 
@@ -956,7 +962,11 @@
 
 // Test suspend flag, return target of taken suspend branch
 LIR* X86Mir2Lir::OpTestSuspend(LIR* target) {
-  OpTlsCmp(Thread::ThreadFlagsOffset<4>(), 0);
+  if (Is64BitInstructionSet(cu_->instruction_set)) {
+    OpTlsCmp(Thread::ThreadFlagsOffset<8>(), 0);
+  } else {
+    OpTlsCmp(Thread::ThreadFlagsOffset<4>(), 0);
+  }
   return OpCondBranch((target == NULL) ? kCondNe : kCondEq, target);
 }
 
@@ -1196,7 +1206,7 @@
   if (rl_src.location == kLocPhysReg) {
     // Both operands are in registers.
     // But we must ensure that rl_src is in pair
-    rl_src = EvalLocWide(rl_src, kCoreReg, true);
+    rl_src = LoadValueWide(rl_src, kCoreReg);
     if (rl_dest.reg.GetLowReg() == rl_src.reg.GetHighReg()) {
       // The registers are the same, so we would clobber it before the use.
       RegStorage temp_reg = AllocTemp();
@@ -1365,6 +1375,20 @@
 }
 
 void X86Mir2Lir::OpRegThreadMem(OpKind op, RegStorage r_dest, ThreadOffset<4> thread_offset) {
+  DCHECK_EQ(kX86, cu_->instruction_set);
+  X86OpCode opcode = kX86Bkpt;
+  switch (op) {
+  case kOpCmp: opcode = kX86Cmp32RT;  break;
+  case kOpMov: opcode = kX86Mov32RT;  break;
+  default:
+    LOG(FATAL) << "Bad opcode: " << op;
+    break;
+  }
+  NewLIR2(opcode, r_dest.GetReg(), thread_offset.Int32Value());
+}
+
+void X86Mir2Lir::OpRegThreadMem(OpKind op, RegStorage r_dest, ThreadOffset<8> thread_offset) {
+  DCHECK_EQ(kX86_64, cu_->instruction_set);
   X86OpCode opcode = kX86Bkpt;
   switch (op) {
   case kOpCmp: opcode = kX86Cmp32RT;  break;
diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc
index c401baf..2db9845 100644
--- a/compiler/dex/quick/x86/target_x86.cc
+++ b/compiler/dex/quick/x86/target_x86.cc
@@ -589,6 +589,12 @@
   return RegStorage::InvalidReg();
 }
 
+// Not used in x86
+RegStorage X86Mir2Lir::LoadHelper(ThreadOffset<8> offset) {
+  LOG(FATAL) << "Unexpected use of LoadHelper in x86";
+  return RegStorage::InvalidReg();
+}
+
 LIR* X86Mir2Lir::CheckSuspendUsingLoad() {
   LOG(FATAL) << "Unexpected use of CheckSuspendUsingLoad in x86";
   return nullptr;
diff --git a/compiler/dex/quick/x86/utility_x86.cc b/compiler/dex/quick/x86/utility_x86.cc
index a4e1255..1da4f17 100644
--- a/compiler/dex/quick/x86/utility_x86.cc
+++ b/compiler/dex/quick/x86/utility_x86.cc
@@ -472,6 +472,20 @@
 }
 
 LIR* X86Mir2Lir::OpThreadMem(OpKind op, ThreadOffset<4> thread_offset) {
+  DCHECK_EQ(kX86, cu_->instruction_set);
+  X86OpCode opcode = kX86Bkpt;
+  switch (op) {
+    case kOpBlx: opcode = kX86CallT;  break;
+    case kOpBx: opcode = kX86JmpT;  break;
+    default:
+      LOG(FATAL) << "Bad opcode: " << op;
+      break;
+  }
+  return NewLIR1(opcode, thread_offset.Int32Value());
+}
+
+LIR* X86Mir2Lir::OpThreadMem(OpKind op, ThreadOffset<8> thread_offset) {
+  DCHECK_EQ(kX86_64, cu_->instruction_set);
   X86OpCode opcode = kX86Bkpt;
   switch (op) {
     case kOpBlx: opcode = kX86CallT;  break;
diff --git a/compiler/dex/reg_storage.h b/compiler/dex/reg_storage.h
index df5aa7b..979f516 100644
--- a/compiler/dex/reg_storage.h
+++ b/compiler/dex/reg_storage.h
@@ -22,14 +22,14 @@
 
 /*
  * 16-bit representation of the physical register container holding a Dalvik value.
- * The encoding allows up to 32 physical elements per storage class, and supports eight
+ * The encoding allows up to 64 physical elements per storage class, and supports eight
  * register container shapes.
  *
- * [V] [D] [HHHHH] [SSS] [F] [LLLLL]
+ * [V] [HHHHH] [SSS] [F] [LLLLLL]
  *
- * [LLLLL]
+ * [LLLLLL]
  *  Physical register number for the low or solo register.
- *    0..31
+ *    0..63
  *
  * [F]
  *  Describes type of the [LLLLL] register.
@@ -51,19 +51,13 @@
  *  Physical register number of the high register (valid only for register pair).
  *    0..31
  *
- * [D]
- *  Describes type of the [HHHHH] register (valid only for register pair).
- *    0: Core
- *    1: Floating point
- *
  * [V]
  *    0 -> Invalid
  *    1 -> Valid
  *
  * Note that in all non-invalid cases, we can determine if the storage is floating point
- * by testing bit 6.  Though a mismatch appears to be permitted by the format, the [F][D] values
- * from each half of a pair must match (this allows the high and low regs of a pair to be more
- * easily individually manipulated).
+ * by testing bit 7.  Note also that a register pair is effectively limited to a pair of
+ * physical register numbers in the 0..31 range.
  *
  * On some target architectures, the same underlying physical register container can be given
  * different views.  For example, Arm's 32-bit single-precision floating point registers
@@ -82,30 +76,30 @@
     kValidMask     = 0x8000,
     kValid         = 0x8000,
     kInvalid       = 0x0000,
-    kShapeMask     = 0x01c0,
-    k32BitSolo     = 0x0040,
-    k64BitSolo     = 0x0080,
-    k64BitPair     = 0x00c0,
-    k128BitSolo    = 0x0100,
-    k256BitSolo    = 0x0140,
-    k512BitSolo    = 0x0180,
-    k1024BitSolo   = 0x01c0,
-    k64BitMask     = 0x0180,
-    k64Bits        = 0x0080,
-    kShapeTypeMask = 0x01e0,
-    kFloatingPoint = 0x0020,
+    kShapeMask     = 0x0380,
+    k32BitSolo     = 0x0080,
+    k64BitSolo     = 0x0100,
+    k64BitPair     = 0x0180,
+    k128BitSolo    = 0x0200,
+    k256BitSolo    = 0x0280,
+    k512BitSolo    = 0x0300,
+    k1024BitSolo   = 0x0380,
+    k64BitMask     = 0x0300,
+    k64Bits        = 0x0100,
+    kShapeTypeMask = 0x03c0,
+    kFloatingPoint = 0x0040,
     kCoreRegister  = 0x0000,
   };
 
-  static const uint16_t kRegValMask  = 0x01ff;  // Num, type and shape.
-  static const uint16_t kRegTypeMask = 0x003f;  // Num and type.
-  static const uint16_t kRegNumMask  = 0x001f;  // Num only.
+  static const uint16_t kRegValMask  = 0x03ff;     // Num, type and shape.
+  static const uint16_t kRegTypeMask = 0x007f;     // Num and type.
+  static const uint16_t kRegNumMask  = 0x003f;     // Num only.
+  static const uint16_t kHighRegNumMask = 0x001f;  // 0..31 for high reg
   static const uint16_t kMaxRegs     = kRegValMask + 1;
-  // TODO: deprecate use of kInvalidRegVal and speed up GetReg().
-  static const uint16_t kInvalidRegVal = 0x01ff;
-  static const uint16_t kHighRegShift = 9;
-  static const uint16_t kShapeMaskShift = 6;
-  static const uint16_t kHighRegMask = (kRegTypeMask << kHighRegShift);
+  // TODO: deprecate use of kInvalidRegVal and speed up GetReg().  Rely on valid bit instead.
+  static const uint16_t kInvalidRegVal = 0x03ff;
+  static const uint16_t kHighRegShift = 10;
+  static const uint16_t kHighRegMask = (kHighRegNumMask << kHighRegShift);
 
   // Reg is [F][LLLLL], will override any existing shape and use rs_kind.
   RegStorage(RegStorageKind rs_kind, int reg) {
@@ -116,7 +110,9 @@
   RegStorage(RegStorageKind rs_kind, int low_reg, int high_reg) {
     DCHECK_EQ(rs_kind, k64BitPair);
     DCHECK_EQ(low_reg & kFloatingPoint, high_reg & kFloatingPoint);
-    reg_ = kValid | rs_kind | ((high_reg & kRegTypeMask) << kHighRegShift) | (low_reg & kRegTypeMask);
+    DCHECK_LE(high_reg & kRegNumMask, kHighRegNumMask) << "High reg must be in 0..31";
+    reg_ = kValid | rs_kind | ((high_reg & kHighRegNumMask) << kHighRegShift) |
+        (low_reg & kRegTypeMask);
   }
   constexpr explicit RegStorage(uint16_t val) : reg_(val) {}
   RegStorage() : reg_(kInvalid) {}
@@ -206,7 +202,7 @@
   // Retrieve the most significant register of a pair.
   int GetHighReg() const {
     DCHECK(IsPair());
-    return k32BitSolo | ((reg_ & kHighRegMask) >> kHighRegShift);
+    return k32BitSolo | ((reg_ & kHighRegMask) >> kHighRegShift) | (reg_ & kFloatingPoint);
   }
 
   // Create a stand-alone RegStorage from the high reg of a pair.
@@ -217,7 +213,7 @@
 
   void SetHighReg(int reg) {
     DCHECK(IsPair());
-    reg_ = (reg_ & ~kHighRegMask) | ((reg & kRegTypeMask) << kHighRegShift);
+    reg_ = (reg_ & ~kHighRegMask) | ((reg & kHighRegNumMask) << kHighRegShift);
   }
 
   // Return the register number of low or solo.
diff --git a/compiler/driver/compiler_driver-inl.h b/compiler/driver/compiler_driver-inl.h
index d9f2a3a..08fd386 100644
--- a/compiler/driver/compiler_driver-inl.h
+++ b/compiler/driver/compiler_driver-inl.h
@@ -28,7 +28,7 @@
 #include "mirror/dex_cache-inl.h"
 #include "mirror/art_field-inl.h"
 #include "scoped_thread_state_change.h"
-#include "sirt_ref-inl.h"
+#include "handle_scope-inl.h"
 
 namespace art {
 
@@ -42,10 +42,10 @@
 }
 
 inline mirror::Class* CompilerDriver::ResolveCompilingMethodsClass(
-    ScopedObjectAccess& soa, const SirtRef<mirror::DexCache>& dex_cache,
-    const SirtRef<mirror::ClassLoader>& class_loader, const DexCompilationUnit* mUnit) {
-  DCHECK(dex_cache->GetDexFile() == mUnit->GetDexFile());
-  DCHECK(class_loader.get() == soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
+    ScopedObjectAccess& soa, const Handle<mirror::DexCache>& dex_cache,
+    const 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()));
   const DexFile::MethodId& referrer_method_id =
       mUnit->GetDexFile()->GetMethodId(mUnit->GetDexMethodIndex());
   mirror::Class* referrer_class = mUnit->GetClassLinker()->ResolveType(
@@ -59,11 +59,11 @@
 }
 
 inline mirror::ArtField* CompilerDriver::ResolveField(
-    ScopedObjectAccess& soa, const SirtRef<mirror::DexCache>& dex_cache,
-    const SirtRef<mirror::ClassLoader>& class_loader, const DexCompilationUnit* mUnit,
+    ScopedObjectAccess& soa, const Handle<mirror::DexCache>& dex_cache,
+    const Handle<mirror::ClassLoader>& class_loader, const DexCompilationUnit* mUnit,
     uint32_t field_idx, bool is_static) {
-  DCHECK(dex_cache->GetDexFile() == mUnit->GetDexFile());
-  DCHECK(class_loader.get() == soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
+  DCHECK_EQ(dex_cache->GetDexFile(), mUnit->GetDexFile());
+  DCHECK_EQ(class_loader.Get(), soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
   mirror::ArtField* resolved_field = mUnit->GetClassLinker()->ResolveField(
       *mUnit->GetDexFile(), field_idx, dex_cache, class_loader, is_static);
   DCHECK_EQ(resolved_field == nullptr, soa.Self()->IsExceptionPending());
@@ -165,11 +165,11 @@
 }
 
 inline mirror::ArtMethod* CompilerDriver::ResolveMethod(
-    ScopedObjectAccess& soa, const SirtRef<mirror::DexCache>& dex_cache,
-    const SirtRef<mirror::ClassLoader>& class_loader, const DexCompilationUnit* mUnit,
+    ScopedObjectAccess& soa, const Handle<mirror::DexCache>& dex_cache,
+    const Handle<mirror::ClassLoader>& class_loader, const DexCompilationUnit* mUnit,
     uint32_t method_idx, InvokeType invoke_type) {
   DCHECK(dex_cache->GetDexFile() == mUnit->GetDexFile());
-  DCHECK(class_loader.get() == soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
+  DCHECK(class_loader.Get() == soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
   mirror::ArtMethod* resolved_method = mUnit->GetClassLinker()->ResolveMethod(
       *mUnit->GetDexFile(), method_idx, dex_cache, class_loader, nullptr, invoke_type);
   DCHECK_EQ(resolved_method == nullptr, soa.Self()->IsExceptionPending());
@@ -206,8 +206,8 @@
 }
 
 inline int CompilerDriver::IsFastInvoke(
-    ScopedObjectAccess& soa, const SirtRef<mirror::DexCache>& dex_cache,
-    const SirtRef<mirror::ClassLoader>& class_loader, const DexCompilationUnit* mUnit,
+    ScopedObjectAccess& soa, const Handle<mirror::DexCache>& dex_cache,
+    const Handle<mirror::ClassLoader>& class_loader, const DexCompilationUnit* mUnit,
     mirror::Class* referrer_class, mirror::ArtMethod* resolved_method, InvokeType* invoke_type,
     MethodReference* target_method, const MethodReference* devirt_target,
     uintptr_t* direct_code, uintptr_t* direct_method) {
@@ -217,7 +217,7 @@
   }
   mirror::Class* methods_class = resolved_method->GetDeclaringClass();
   if (UNLIKELY(!referrer_class->CanAccessResolvedMethod(methods_class, resolved_method,
-                                                        dex_cache.get(),
+                                                        dex_cache.Get(),
                                                         target_method->dex_method_index))) {
     return 0;
   }
@@ -237,7 +237,7 @@
     // Sharpen a virtual call into a direct call. The method_idx is into referrer's
     // dex cache, check that this resolved method is where we expect it.
     CHECK(target_method->dex_file == mUnit->GetDexFile());
-    DCHECK(dex_cache.get() == mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile()));
+    DCHECK(dex_cache.Get() == mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile()));
     CHECK(referrer_class->GetDexCache()->GetResolvedMethod(target_method->dex_method_index) ==
         resolved_method) << PrettyMethod(resolved_method);
     int stats_flags = kFlagMethodResolved;
@@ -259,8 +259,9 @@
                                                   devirt_target->dex_method_index,
                                                   dex_cache, class_loader, NULL, kVirtual);
     } else {
-      SirtRef<mirror::DexCache> target_dex_cache(soa.Self(),
-          class_linker->FindDexCache(*devirt_target->dex_file));
+      StackHandleScope<1> hs(soa.Self());
+      Handle<mirror::DexCache> target_dex_cache(
+          hs.NewHandle(class_linker->FindDexCache(*devirt_target->dex_file)));
       called_method = class_linker->ResolveMethod(*devirt_target->dex_file,
                                                   devirt_target->dex_method_index,
                                                   target_dex_cache, class_loader, NULL, kVirtual);
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 6817f14..55ba643 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -49,7 +49,7 @@
 #include "mirror/throwable.h"
 #include "scoped_thread_state_change.h"
 #include "ScopedLocalRef.h"
-#include "sirt_ref-inl.h"
+#include "handle_scope-inl.h"
 #include "thread.h"
 #include "thread_pool.h"
 #include "trampolines/trampoline_compiler.h"
@@ -377,8 +377,10 @@
   compiler_->Init();
 
   CHECK(!Runtime::Current()->IsStarted());
-  if (!image_) {
-    CHECK(image_classes_.get() == NULL);
+  if (image_) {
+    CHECK(image_classes_.get() != nullptr);
+  } else {
+    CHECK(image_classes_.get() == nullptr);
   }
 
   // Are we generating CFI information?
@@ -509,7 +511,7 @@
 }
 
 static DexToDexCompilationLevel GetDexToDexCompilationlevel(
-    Thread* self, SirtRef<mirror::ClassLoader>& class_loader, const DexFile& dex_file,
+    Thread* self, Handle<mirror::ClassLoader>& class_loader, const DexFile& dex_file,
     const DexFile::ClassDef& class_def) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   const char* descriptor = dex_file.GetClassDescriptor(class_def);
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
@@ -524,7 +526,7 @@
   // function). Since image classes can be verified again while compiling an application,
   // we must prevent the DEX-to-DEX compiler from introducing them.
   // TODO: find a way to enable "quick" instructions for image classes and remove this check.
-  bool compiling_image_classes = class_loader.get() == nullptr;
+  bool compiling_image_classes = class_loader.Get() == nullptr;
   if (compiling_image_classes) {
     return kRequired;
   } else if (klass->IsVerified()) {
@@ -574,8 +576,9 @@
   {
     ScopedObjectAccess soa(Thread::Current());
     const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_idx);
-    SirtRef<mirror::ClassLoader> class_loader(soa.Self(),
-                                              soa.Decode<mirror::ClassLoader*>(jclass_loader));
+    StackHandleScope<1> hs(soa.Self());
+    Handle<mirror::ClassLoader> class_loader(
+        hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
     dex_to_dex_compilation_level = GetDexToDexCompilationlevel(self, class_loader, *dex_file,
                                                                class_def);
   }
@@ -591,7 +594,7 @@
                              ThreadPool* thread_pool, TimingLogger* timings) {
   for (size_t i = 0; i != dex_files.size(); ++i) {
     const DexFile* dex_file = dex_files[i];
-    CHECK(dex_file != NULL);
+    CHECK(dex_file != nullptr);
     ResolveDexFile(class_loader, *dex_file, thread_pool, timings);
   }
 }
@@ -689,6 +692,7 @@
 // Make a list of descriptors for classes to include in the image
 void CompilerDriver::LoadImageClasses(TimingLogger* timings)
       LOCKS_EXCLUDED(Locks::mutator_lock_) {
+  CHECK(timings != nullptr);
   if (!IsImage()) {
     return;
   }
@@ -698,10 +702,13 @@
   Thread* self = Thread::Current();
   ScopedObjectAccess soa(self);
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  CHECK(image_classes_.get() != nullptr);
   for (auto it = image_classes_->begin(), end = image_classes_->end(); it != end;) {
     const std::string& descriptor(*it);
-    SirtRef<mirror::Class> klass(self, class_linker->FindSystemClass(self, descriptor.c_str()));
-    if (klass.get() == NULL) {
+    StackHandleScope<1> hs(self);
+    Handle<mirror::Class> klass(
+        hs.NewHandle(class_linker->FindSystemClass(self, descriptor.c_str())));
+    if (klass.Get() == NULL) {
       VLOG(compiler) << "Failed to find class " << descriptor;
       image_classes_->erase(it++);
       self->ClearException();
@@ -714,8 +721,9 @@
   // exceptions are resolved by the verifier when there is a catch block in an interested method.
   // Do this here so that exception classes appear to have been specified image classes.
   std::set<std::pair<uint16_t, const DexFile*> > unresolved_exception_types;
-  SirtRef<mirror::Class> java_lang_Throwable(self,
-                                     class_linker->FindSystemClass(self, "Ljava/lang/Throwable;"));
+  StackHandleScope<1> hs(self);
+  Handle<mirror::Class> java_lang_Throwable(
+      hs.NewHandle(class_linker->FindSystemClass(self, "Ljava/lang/Throwable;")));
   do {
     unresolved_exception_types.clear();
     class_linker->VisitClasses(ResolveCatchBlockExceptionsClassVisitor,
@@ -723,16 +731,17 @@
     for (const std::pair<uint16_t, const DexFile*>& exception_type : unresolved_exception_types) {
       uint16_t exception_type_idx = exception_type.first;
       const DexFile* dex_file = exception_type.second;
-      SirtRef<mirror::DexCache> dex_cache(self, class_linker->FindDexCache(*dex_file));
-      SirtRef<mirror::ClassLoader> class_loader(self, nullptr);
-      SirtRef<mirror::Class> klass(self, class_linker->ResolveType(*dex_file, exception_type_idx,
-                                                                   dex_cache, class_loader));
-      if (klass.get() == NULL) {
+      StackHandleScope<3> hs(self);
+      Handle<mirror::DexCache> dex_cache(hs.NewHandle(class_linker->FindDexCache(*dex_file)));
+      auto class_loader(hs.NewHandle<mirror::ClassLoader>(nullptr));
+      Handle<mirror::Class> klass(hs.NewHandle(
+          class_linker->ResolveType(*dex_file, exception_type_idx, dex_cache, class_loader)));
+      if (klass.Get() == NULL) {
         const DexFile::TypeId& type_id = dex_file->GetTypeId(exception_type_idx);
         const char* descriptor = dex_file->GetTypeDescriptor(type_id);
         LOG(FATAL) << "Failed to resolve class " << descriptor;
       }
-      DCHECK(java_lang_Throwable->IsAssignableFrom(klass.get()));
+      DCHECK(java_lang_Throwable->IsAssignableFrom(klass.Get()));
     }
     // Resolving exceptions may load classes that reference more exceptions, iterate until no
     // more are found
@@ -816,7 +825,9 @@
   if (IsImage()) {
     // We resolve all const-string strings when building for the image.
     ScopedObjectAccess soa(Thread::Current());
-    SirtRef<mirror::DexCache> dex_cache(soa.Self(), Runtime::Current()->GetClassLinker()->FindDexCache(dex_file));
+    StackHandleScope<1> hs(soa.Self());
+    Handle<mirror::DexCache> dex_cache(
+        hs.NewHandle(Runtime::Current()->GetClassLinker()->FindDexCache(dex_file)));
     Runtime::Current()->GetClassLinker()->ResolveString(dex_file, string_idx, dex_cache);
     result = true;
   }
@@ -980,16 +991,17 @@
   mirror::Class* referrer_class;
   mirror::DexCache* dex_cache;
   {
-    SirtRef<mirror::DexCache> dex_cache_sirt(soa.Self(),
-        mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile()));
-    SirtRef<mirror::ClassLoader> class_loader_sirt(soa.Self(),
-        soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
-    SirtRef<mirror::ArtField> resolved_field_sirt(soa.Self(),
-        ResolveField(soa, dex_cache_sirt, class_loader_sirt, mUnit, field_idx, false));
-    referrer_class = (resolved_field_sirt.get() != nullptr)
-        ? ResolveCompilingMethodsClass(soa, dex_cache_sirt, class_loader_sirt, mUnit) : nullptr;
-    resolved_field = resolved_field_sirt.get();
-    dex_cache = dex_cache_sirt.get();
+    StackHandleScope<3> hs(soa.Self());
+    Handle<mirror::DexCache> dex_cache_handle(
+        hs.NewHandle(mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile())));
+    Handle<mirror::ClassLoader> class_loader_handle(
+        hs.NewHandle(soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader())));
+    Handle<mirror::ArtField> resolved_field_handle(hs.NewHandle(
+        ResolveField(soa, dex_cache_handle, class_loader_handle, mUnit, field_idx, false)));
+    referrer_class = (resolved_field_handle.Get() != nullptr)
+        ? ResolveCompilingMethodsClass(soa, dex_cache_handle, class_loader_handle, mUnit) : nullptr;
+    resolved_field = resolved_field_handle.Get();
+    dex_cache = dex_cache_handle.Get();
   }
   bool result = false;
   if (resolved_field != nullptr && referrer_class != nullptr) {
@@ -1017,16 +1029,17 @@
   mirror::Class* referrer_class;
   mirror::DexCache* dex_cache;
   {
-    SirtRef<mirror::DexCache> dex_cache_sirt(soa.Self(),
-        mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile()));
-    SirtRef<mirror::ClassLoader> class_loader_sirt(soa.Self(),
-        soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
-    SirtRef<mirror::ArtField> resolved_field_sirt(soa.Self(),
-        ResolveField(soa, dex_cache_sirt, class_loader_sirt, mUnit, field_idx, true));
-    referrer_class = (resolved_field_sirt.get() != nullptr)
-        ? ResolveCompilingMethodsClass(soa, dex_cache_sirt, class_loader_sirt, mUnit) : nullptr;
-    resolved_field = resolved_field_sirt.get();
-    dex_cache = dex_cache_sirt.get();
+    StackHandleScope<3> hs(soa.Self());
+    Handle<mirror::DexCache> dex_cache_handle(
+        hs.NewHandle(mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile())));
+    Handle<mirror::ClassLoader> class_loader_handle(
+        hs.NewHandle(soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader())));
+    Handle<mirror::ArtField> resolved_field_handle(hs.NewHandle(
+        ResolveField(soa, dex_cache_handle, class_loader_handle, mUnit, field_idx, true)));
+    referrer_class = (resolved_field_handle.Get() != nullptr)
+        ? ResolveCompilingMethodsClass(soa, dex_cache_handle, class_loader_handle, mUnit) : nullptr;
+    resolved_field = resolved_field_handle.Get();
+    dex_cache = dex_cache_handle.Get();
   }
   bool result = false;
   if (resolved_field != nullptr && referrer_class != nullptr) {
@@ -1168,17 +1181,18 @@
   // Try to resolve the method and compiling method's class.
   mirror::ArtMethod* resolved_method;
   mirror::Class* referrer_class;
-  SirtRef<mirror::DexCache> dex_cache(soa.Self(),
-      mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile()));
-  SirtRef<mirror::ClassLoader> class_loader(soa.Self(),
-      soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
+  StackHandleScope<3> hs(soa.Self());
+  Handle<mirror::DexCache> dex_cache(
+      hs.NewHandle(mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile())));
+  Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
+      soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader())));
   {
     uint32_t method_idx = target_method->dex_method_index;
-    SirtRef<mirror::ArtMethod> resolved_method_sirt(soa.Self(),
-        ResolveMethod(soa, dex_cache, class_loader, mUnit, method_idx, orig_invoke_type));
-    referrer_class = (resolved_method_sirt.get() != nullptr)
+    Handle<mirror::ArtMethod> resolved_method_handle(hs.NewHandle(
+        ResolveMethod(soa, dex_cache, class_loader, mUnit, method_idx, orig_invoke_type)));
+    referrer_class = (resolved_method_handle.Get() != nullptr)
         ? ResolveCompilingMethodsClass(soa, dex_cache, class_loader, mUnit) : nullptr;
-    resolved_method = resolved_method_sirt.get();
+    resolved_method = resolved_method_handle.Get();
   }
   bool result = false;
   if (resolved_method != nullptr) {
@@ -1196,7 +1210,7 @@
       // Devirtualization not enabled. Inline IsFastInvoke(), dropping the devirtualization parts.
       if (UNLIKELY(referrer_class == nullptr) ||
           UNLIKELY(!referrer_class->CanAccessResolvedMethod(resolved_method->GetDeclaringClass(),
-                                                            resolved_method, dex_cache.get(),
+                                                            resolved_method, dex_cache.Get(),
                                                             target_method->dex_method_index)) ||
           *invoke_type == kSuper) {
         // Slow path. (Without devirtualization, all super calls go slow path as well.)
@@ -1469,8 +1483,10 @@
   const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
   if (!SkipClass(class_linker, jclass_loader, dex_file, class_def)) {
     ScopedObjectAccess soa(self);
-    SirtRef<mirror::ClassLoader> class_loader(soa.Self(), soa.Decode<mirror::ClassLoader*>(jclass_loader));
-    SirtRef<mirror::DexCache> dex_cache(soa.Self(), class_linker->FindDexCache(dex_file));
+    StackHandleScope<2> hs(soa.Self());
+    Handle<mirror::ClassLoader> class_loader(
+        hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+    Handle<mirror::DexCache> dex_cache(hs.NewHandle(class_linker->FindDexCache(dex_file)));
     // Resolve the class.
     mirror::Class* klass = class_linker->ResolveType(dex_file, class_def.class_idx_, dex_cache,
                                                      class_loader);
@@ -1556,9 +1572,10 @@
   ScopedObjectAccess soa(Thread::Current());
   ClassLinker* class_linker = manager->GetClassLinker();
   const DexFile& dex_file = *manager->GetDexFile();
-  SirtRef<mirror::DexCache> dex_cache(soa.Self(), class_linker->FindDexCache(dex_file));
-  SirtRef<mirror::ClassLoader> class_loader(
-      soa.Self(), soa.Decode<mirror::ClassLoader*>(manager->GetClassLoader()));
+  StackHandleScope<2> hs(soa.Self());
+  Handle<mirror::DexCache> dex_cache(hs.NewHandle(class_linker->FindDexCache(dex_file)));
+  Handle<mirror::ClassLoader> class_loader(
+      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(manager->GetClassLoader())));
   mirror::Class* klass = class_linker->ResolveType(dex_file, type_idx, dex_cache, class_loader);
 
   if (klass == NULL) {
@@ -1611,11 +1628,12 @@
   const char* descriptor = dex_file.GetClassDescriptor(class_def);
   ClassLinker* class_linker = manager->GetClassLinker();
   jobject jclass_loader = manager->GetClassLoader();
-  SirtRef<mirror::ClassLoader> class_loader(
-      soa.Self(), soa.Decode<mirror::ClassLoader*>(jclass_loader));
-  SirtRef<mirror::Class> klass(soa.Self(), class_linker->FindClass(soa.Self(), descriptor,
-                                                                   class_loader));
-  if (klass.get() == nullptr) {
+  StackHandleScope<3> hs(soa.Self());
+  Handle<mirror::ClassLoader> class_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) {
     CHECK(soa.Self()->IsExceptionPending());
     soa.Self()->ClearException();
 
@@ -1624,7 +1642,7 @@
      * This is to ensure the class is structurally sound for compilation. An unsound class
      * will be rejected by the verifier and later skipped during compilation in the compiler.
      */
-    SirtRef<mirror::DexCache> dex_cache(soa.Self(), class_linker->FindDexCache(dex_file));
+    Handle<mirror::DexCache> dex_cache(hs.NewHandle(class_linker->FindDexCache(dex_file)));
     std::string error_msg;
     if (verifier::MethodVerifier::VerifyClass(&dex_file, dex_cache, class_loader, &class_def, true,
                                               &error_msg) ==
@@ -1632,8 +1650,8 @@
       LOG(ERROR) << "Verification failed on class " << PrettyDescriptor(descriptor)
                  << " because: " << error_msg;
     }
-  } else if (!SkipClass(jclass_loader, dex_file, klass.get())) {
-    CHECK(klass->IsResolved()) << PrettyClass(klass.get());
+  } else if (!SkipClass(jclass_loader, dex_file, klass.Get())) {
+    CHECK(klass->IsResolved()) << PrettyClass(klass.Get());
     class_linker->VerifyClass(klass);
 
     if (klass->IsErroneous()) {
@@ -1643,7 +1661,7 @@
     }
 
     CHECK(klass->IsCompileTimeVerified() || klass->IsErroneous())
-        << PrettyDescriptor(klass.get()) << ": state=" << klass->GetStatus();
+        << PrettyDescriptor(klass.Get()) << ": state=" << klass->GetStatus();
   }
   soa.Self()->AssertNoPendingException();
 }
@@ -1666,13 +1684,13 @@
   const char* descriptor = dex_file.StringDataByIdx(class_type_id.descriptor_idx_);
 
   ScopedObjectAccess soa(Thread::Current());
-  SirtRef<mirror::ClassLoader> class_loader(soa.Self(),
-                                            soa.Decode<mirror::ClassLoader*>(jclass_loader));
-  SirtRef<mirror::Class> klass(soa.Self(),
-                               manager->GetClassLinker()->FindClass(soa.Self(), descriptor,
-                                                                    class_loader));
+  StackHandleScope<3> hs(soa.Self());
+  Handle<mirror::ClassLoader> class_loader(
+      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+  Handle<mirror::Class> klass(
+      hs.NewHandle(manager->GetClassLinker()->FindClass(soa.Self(), descriptor, class_loader)));
 
-  if (klass.get() != nullptr && !SkipClass(jclass_loader, dex_file, klass.get())) {
+  if (klass.Get() != nullptr && !SkipClass(jclass_loader, dex_file, klass.Get())) {
     // Only try to initialize classes that were successfully verified.
     if (klass->IsVerified()) {
       // Attempt to initialize the class but bail if we either need to initialize the super-class
@@ -1687,8 +1705,8 @@
         // parent-to-child and a child-to-parent lock ordering and consequent potential deadlock.
         // We need to use an ObjectLock due to potential suspension in the interpreting code. Rather
         // than use a special Object for the purpose we use the Class of java.lang.Class.
-        SirtRef<mirror::Class> sirt_klass(soa.Self(), klass->GetClass());
-        ObjectLock<mirror::Class> lock(soa.Self(), &sirt_klass);
+        Handle<mirror::Class> h_klass(hs.NewHandle(klass->GetClass()));
+        ObjectLock<mirror::Class> lock(soa.Self(), &h_klass);
         // Attempt to initialize allowing initialization of parent classes but still not static
         // fields.
         manager->GetClassLinker()->EnsureInitialized(klass, false, true);
@@ -1803,8 +1821,9 @@
   DexToDexCompilationLevel dex_to_dex_compilation_level = kDontDexToDexCompile;
   {
     ScopedObjectAccess soa(Thread::Current());
-    SirtRef<mirror::ClassLoader> class_loader(soa.Self(),
-                                              soa.Decode<mirror::ClassLoader*>(jclass_loader));
+    StackHandleScope<1> hs(soa.Self());
+    Handle<mirror::ClassLoader> class_loader(
+        hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
     dex_to_dex_compilation_level = GetDexToDexCompilationlevel(soa.Self(), class_loader, dex_file,
                                                                class_def);
   }
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 6ac9cf7..f3db41f 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -52,7 +52,7 @@
 class OatWriter;
 class ParallelCompilationManager;
 class ScopedObjectAccess;
-template<class T> class SirtRef;
+template<class T> class Handle;
 class TimingLogger;
 class VerificationResults;
 class VerifiedMethod;
@@ -221,15 +221,15 @@
 
   // Resolve compiling method's class. Returns nullptr on failure.
   mirror::Class* ResolveCompilingMethodsClass(
-      ScopedObjectAccess& soa, const SirtRef<mirror::DexCache>& dex_cache,
-      const SirtRef<mirror::ClassLoader>& class_loader, const DexCompilationUnit* mUnit)
+      ScopedObjectAccess& soa, const Handle<mirror::DexCache>& dex_cache,
+      const Handle<mirror::ClassLoader>& class_loader, const DexCompilationUnit* mUnit)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Resolve a field. Returns nullptr on failure, including incompatible class change.
   // NOTE: Unlike ClassLinker's ResolveField(), this method enforces is_static.
   mirror::ArtField* ResolveField(
-      ScopedObjectAccess& soa, const SirtRef<mirror::DexCache>& dex_cache,
-      const SirtRef<mirror::ClassLoader>& class_loader, const DexCompilationUnit* mUnit,
+      ScopedObjectAccess& soa, const Handle<mirror::DexCache>& dex_cache,
+      const Handle<mirror::ClassLoader>& class_loader, const DexCompilationUnit* mUnit,
       uint32_t field_idx, bool is_static)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -258,8 +258,8 @@
 
   // Resolve a method. Returns nullptr on failure, including incompatible class change.
   mirror::ArtMethod* ResolveMethod(
-      ScopedObjectAccess& soa, const SirtRef<mirror::DexCache>& dex_cache,
-      const SirtRef<mirror::ClassLoader>& class_loader, const DexCompilationUnit* mUnit,
+      ScopedObjectAccess& soa, const Handle<mirror::DexCache>& dex_cache,
+      const Handle<mirror::ClassLoader>& class_loader, const DexCompilationUnit* mUnit,
       uint32_t method_idx, InvokeType invoke_type)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -277,8 +277,8 @@
   // Can we fast-path an INVOKE? If no, returns 0. If yes, returns a non-zero opaque flags value
   // for ProcessedInvoke() and computes the necessary lowering info.
   int IsFastInvoke(
-      ScopedObjectAccess& soa, const SirtRef<mirror::DexCache>& dex_cache,
-      const SirtRef<mirror::ClassLoader>& class_loader, const DexCompilationUnit* mUnit,
+      ScopedObjectAccess& soa, const Handle<mirror::DexCache>& dex_cache,
+      const Handle<mirror::ClassLoader>& class_loader, const DexCompilationUnit* mUnit,
       mirror::Class* referrer_class, mirror::ArtMethod* resolved_method, InvokeType* invoke_type,
       MethodReference* target_method, const MethodReference* devirt_target,
       uintptr_t* direct_code, uintptr_t* direct_method)
diff --git a/compiler/driver/compiler_driver_test.cc b/compiler/driver/compiler_driver_test.cc
index 86034c8..113594a 100644
--- a/compiler/driver/compiler_driver_test.cc
+++ b/compiler/driver/compiler_driver_test.cc
@@ -30,7 +30,7 @@
 #include "mirror/dex_cache-inl.h"
 #include "mirror/object_array-inl.h"
 #include "mirror/object-inl.h"
-#include "sirt_ref-inl.h"
+#include "handle_scope-inl.h"
 
 namespace art {
 
@@ -80,7 +80,9 @@
       const DexFile::ClassDef& class_def = dex_file.GetClassDef(i);
       const char* descriptor = dex_file.GetClassDescriptor(class_def);
       ScopedObjectAccess soa(Thread::Current());
-      SirtRef<mirror::ClassLoader> loader(soa.Self(), soa.Decode<mirror::ClassLoader*>(class_loader));
+      StackHandleScope<1> hs(soa.Self());
+      Handle<mirror::ClassLoader> loader(
+          hs.NewHandle(soa.Decode<mirror::ClassLoader*>(class_loader)));
       mirror::Class* c = class_linker->FindClass(soa.Self(), descriptor, loader);
       CHECK(c != NULL);
       for (size_t i = 0; i < c->NumDirectMethods(); i++) {
@@ -150,7 +152,8 @@
   jobject class_loader;
   {
     ScopedObjectAccess soa(Thread::Current());
-    SirtRef<mirror::ClassLoader> null_loader(soa.Self(), nullptr);
+    StackHandleScope<1> hs(soa.Self());
+    auto null_loader(hs.NewHandle<mirror::ClassLoader>(nullptr));
     CompileVirtualMethod(null_loader, "java.lang.Class", "isFinalizable", "()Z");
     CompileDirectMethod(null_loader, "java.lang.Object", "<init>", "()V");
     class_loader = LoadDex("AbstractMethod");
diff --git a/compiler/elf_writer_mclinker.cc b/compiler/elf_writer_mclinker.cc
index f688103..aa4a5b2 100644
--- a/compiler/elf_writer_mclinker.cc
+++ b/compiler/elf_writer_mclinker.cc
@@ -361,8 +361,9 @@
       ClassLinker* linker = Runtime::Current()->GetClassLinker();
       // Unchecked as we hold mutator_lock_ on entry.
       ScopedObjectAccessUnchecked soa(Thread::Current());
-      SirtRef<mirror::DexCache> dex_cache(soa.Self(), linker->FindDexCache(dex_file));
-      SirtRef<mirror::ClassLoader> class_loader(soa.Self(), nullptr);
+      StackHandleScope<2> hs(soa.Self());
+      Handle<mirror::DexCache> dex_cache(hs.NewHandle(linker->FindDexCache(dex_file)));
+      auto class_loader(hs.NewHandle<mirror::ClassLoader>(nullptr));
       method = linker->ResolveMethod(dex_file, method_idx, dex_cache, class_loader, NULL, invoke_type);
       CHECK(method != NULL);
     }
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index 62817e7..d855eee 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -51,7 +51,7 @@
 #include "object_utils.h"
 #include "runtime.h"
 #include "scoped_thread_state_change.h"
-#include "sirt_ref-inl.h"
+#include "handle_scope-inl.h"
 #include "UniquePtr.h"
 #include "utils.h"
 
@@ -382,16 +382,14 @@
       DCHECK_EQ(obj, obj->AsString()->Intern());
       return;
     }
-    Thread* self = Thread::Current();
-    SirtRef<Object> sirt_obj(self, obj);
-    mirror::String* interned = obj->AsString()->Intern();
-    if (sirt_obj.get() != interned) {
+    mirror::String* const interned = obj->AsString()->Intern();
+    if (obj != interned) {
       if (!IsImageOffsetAssigned(interned)) {
         // interned obj is after us, allocate its location early
         AssignImageOffset(interned);
       }
       // point those looking for this object to the interned version.
-      SetImageOffset(sirt_obj.get(), GetImageOffset(interned));
+      SetImageOffset(obj, GetImageOffset(interned));
       return;
     }
     // else (obj == interned), nothing to do but fall through to the normal case
@@ -404,20 +402,22 @@
   Runtime* runtime = Runtime::Current();
   ClassLinker* class_linker = runtime->GetClassLinker();
   Thread* self = Thread::Current();
-  SirtRef<Class> object_array_class(self, class_linker->FindSystemClass(self,
-                                                                        "[Ljava/lang/Object;"));
+  StackHandleScope<3> hs(self);
+  Handle<Class> object_array_class(hs.NewHandle(
+      class_linker->FindSystemClass(self, "[Ljava/lang/Object;")));
 
   // build an Object[] of all the DexCaches used in the source_space_
-  ObjectArray<Object>* dex_caches = ObjectArray<Object>::Alloc(self, object_array_class.get(),
-                                                               class_linker->GetDexCaches().size());
+  Handle<ObjectArray<Object>> dex_caches(
+      hs.NewHandle(ObjectArray<Object>::Alloc(self, object_array_class.Get(),
+                                              class_linker->GetDexCaches().size())));
   int i = 0;
   for (DexCache* dex_cache : class_linker->GetDexCaches()) {
     dex_caches->Set<false>(i++, dex_cache);
   }
 
   // build an Object[] of the roots needed to restore the runtime
-  SirtRef<ObjectArray<Object> > image_roots(
-      self, ObjectArray<Object>::Alloc(self, object_array_class.get(), ImageHeader::kImageRootsMax));
+  Handle<ObjectArray<Object> > image_roots(hs.NewHandle(
+      ObjectArray<Object>::Alloc(self, object_array_class.Get(), ImageHeader::kImageRootsMax)));
   image_roots->Set<false>(ImageHeader::kResolutionMethod, runtime->GetResolutionMethod());
   image_roots->Set<false>(ImageHeader::kImtConflictMethod, runtime->GetImtConflictMethod());
   image_roots->Set<false>(ImageHeader::kDefaultImt, runtime->GetDefaultImt());
@@ -427,27 +427,28 @@
                           runtime->GetCalleeSaveMethod(Runtime::kRefsOnly));
   image_roots->Set<false>(ImageHeader::kRefsAndArgsSaveMethod,
                           runtime->GetCalleeSaveMethod(Runtime::kRefsAndArgs));
-  image_roots->Set<false>(ImageHeader::kDexCaches, dex_caches);
+  image_roots->Set<false>(ImageHeader::kDexCaches, dex_caches.Get());
   image_roots->Set<false>(ImageHeader::kClassRoots, class_linker->GetClassRoots());
   for (int i = 0; i < ImageHeader::kImageRootsMax; i++) {
     CHECK(image_roots->Get(i) != NULL);
   }
-  return image_roots.get();
+  return image_roots.Get();
 }
 
 // Walk instance fields of the given Class. Separate function to allow recursion on the super
 // class.
 void ImageWriter::WalkInstanceFields(mirror::Object* obj, mirror::Class* klass) {
   // Visit fields of parent classes first.
-  SirtRef<mirror::Class> sirt_class(Thread::Current(), klass);
-  mirror::Class* super = sirt_class->GetSuperClass();
+  StackHandleScope<1> hs(Thread::Current());
+  Handle<mirror::Class> h_class(hs.NewHandle(klass));
+  mirror::Class* super = h_class->GetSuperClass();
   if (super != nullptr) {
     WalkInstanceFields(obj, super);
   }
   //
-  size_t num_reference_fields = sirt_class->NumReferenceInstanceFields();
+  size_t num_reference_fields = h_class->NumReferenceInstanceFields();
   for (size_t i = 0; i < num_reference_fields; ++i) {
-    mirror::ArtField* field = sirt_class->GetInstanceField(i);
+    mirror::ArtField* field = h_class->GetInstanceField(i);
     MemberOffset field_offset = field->GetOffset();
     mirror::Object* value = obj->GetFieldObject<mirror::Object>(field_offset);
     if (value != nullptr) {
@@ -460,28 +461,28 @@
 void ImageWriter::WalkFieldsInOrder(mirror::Object* obj) {
   if (!IsImageOffsetAssigned(obj)) {
     // Walk instance fields of all objects
-    Thread* self = Thread::Current();
-    SirtRef<mirror::Object> sirt_obj(self, obj);
-    SirtRef<mirror::Class> klass(self, obj->GetClass());
+    StackHandleScope<2> hs(Thread::Current());
+    Handle<mirror::Object> h_obj(hs.NewHandle(obj));
+    Handle<mirror::Class> klass(hs.NewHandle(obj->GetClass()));
     // visit the object itself.
-    CalculateObjectOffsets(sirt_obj.get());
-    WalkInstanceFields(sirt_obj.get(), klass.get());
+    CalculateObjectOffsets(h_obj.Get());
+    WalkInstanceFields(h_obj.Get(), klass.Get());
     // Walk static fields of a Class.
-    if (sirt_obj->IsClass()) {
+    if (h_obj->IsClass()) {
       size_t num_static_fields = klass->NumReferenceStaticFields();
       for (size_t i = 0; i < num_static_fields; ++i) {
         mirror::ArtField* field = klass->GetStaticField(i);
         MemberOffset field_offset = field->GetOffset();
-        mirror::Object* value = sirt_obj->GetFieldObject<mirror::Object>(field_offset);
+        mirror::Object* value = h_obj->GetFieldObject<mirror::Object>(field_offset);
         if (value != nullptr) {
           WalkFieldsInOrder(value);
         }
       }
-    } else if (sirt_obj->IsObjectArray()) {
+    } else if (h_obj->IsObjectArray()) {
       // Walk elements of an object array.
-      int32_t length = sirt_obj->AsObjectArray<mirror::Object>()->GetLength();
+      int32_t length = h_obj->AsObjectArray<mirror::Object>()->GetLength();
       for (int32_t i = 0; i < length; i++) {
-        mirror::ObjectArray<mirror::Object>* obj_array = sirt_obj->AsObjectArray<mirror::Object>();
+        mirror::ObjectArray<mirror::Object>* obj_array = h_obj->AsObjectArray<mirror::Object>();
         mirror::Object* value = obj_array->Get(i);
         if (value != nullptr) {
           WalkFieldsInOrder(value);
@@ -500,7 +501,8 @@
 void ImageWriter::CalculateNewObjectOffsets(size_t oat_loaded_size, size_t oat_data_offset) {
   CHECK_NE(0U, oat_loaded_size);
   Thread* self = Thread::Current();
-  SirtRef<ObjectArray<Object> > image_roots(self, CreateImageRoots());
+  StackHandleScope<1> hs(self);
+  Handle<ObjectArray<Object>> image_roots(hs.NewHandle(CreateImageRoots()));
 
   gc::Heap* heap = Runtime::Current()->GetHeap();
   DCHECK_EQ(0U, image_end_);
@@ -533,7 +535,7 @@
                            static_cast<uint32_t>(image_end_),
                            RoundUp(image_end_, kPageSize),
                            RoundUp(bitmap_bytes, kPageSize),
-                           PointerToLowMemUInt32(GetImageAddress(image_roots.get())),
+                           PointerToLowMemUInt32(GetImageAddress(image_roots.Get())),
                            oat_file_->GetOatHeader().GetChecksum(),
                            PointerToLowMemUInt32(oat_file_begin),
                            PointerToLowMemUInt32(oat_data_begin_),
@@ -691,9 +693,10 @@
 static ArtMethod* GetTargetMethod(const CompilerDriver::CallPatchInformation* patch)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  Thread* self = Thread::Current();
-  SirtRef<mirror::DexCache> dex_cache(self, class_linker->FindDexCache(*patch->GetTargetDexFile()));
-  SirtRef<mirror::ClassLoader> class_loader(self, nullptr);
+  StackHandleScope<2> hs(Thread::Current());
+  Handle<mirror::DexCache> dex_cache(
+      hs.NewHandle(class_linker->FindDexCache(*patch->GetTargetDexFile())));
+  auto class_loader(hs.NewHandle<mirror::ClassLoader>(nullptr));
   ArtMethod* method = class_linker->ResolveMethod(*patch->GetTargetDexFile(),
                                                   patch->GetTargetMethodIdx(),
                                                   dex_cache,
@@ -714,9 +717,9 @@
 static Class* GetTargetType(const CompilerDriver::TypePatchInformation* patch)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  Thread* self = Thread::Current();
-  SirtRef<mirror::DexCache> dex_cache(self, class_linker->FindDexCache(patch->GetDexFile()));
-  SirtRef<mirror::ClassLoader> class_loader(self, nullptr);
+  StackHandleScope<2> hs(Thread::Current());
+  Handle<mirror::DexCache> dex_cache(hs.NewHandle(class_linker->FindDexCache(patch->GetDexFile())));
+  auto class_loader(hs.NewHandle<mirror::ClassLoader>(nullptr));
   Class* klass = class_linker->ResolveType(patch->GetDexFile(),
                                            patch->GetTargetTypeIdx(),
                                            dex_cache,
diff --git a/compiler/jni/jni_compiler_test.cc b/compiler/jni/jni_compiler_test.cc
index 6b5e55e..6035689 100644
--- a/compiler/jni/jni_compiler_test.cc
+++ b/compiler/jni/jni_compiler_test.cc
@@ -48,7 +48,9 @@
   void CompileForTest(jobject class_loader, bool direct,
                       const char* method_name, const char* method_sig) {
     ScopedObjectAccess soa(Thread::Current());
-    SirtRef<mirror::ClassLoader> loader(soa.Self(), soa.Decode<mirror::ClassLoader*>(class_loader));
+    StackHandleScope<1> hs(soa.Self());
+    Handle<mirror::ClassLoader> 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);
     mirror::ArtMethod* method;
@@ -153,8 +155,9 @@
 
   ScopedObjectAccess soa(Thread::Current());
   std::string reason;
-  SirtRef<mirror::ClassLoader> class_loader(soa.Self(),
-                                            soa.Decode<mirror::ClassLoader*>(class_loader_));
+  StackHandleScope<1> hs(soa.Self());
+  Handle<mirror::ClassLoader> class_loader(
+      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(class_loader_)));
   ASSERT_TRUE(
       Runtime::Current()->GetJavaVM()->LoadNativeLibrary("", class_loader, &reason)) << reason;
 
@@ -169,8 +172,9 @@
 
   ScopedObjectAccess soa(Thread::Current());
   std::string reason;
-  SirtRef<mirror::ClassLoader> class_loader(soa.Self(),
-                                            soa.Decode<mirror::ClassLoader*>(class_loader_));
+  StackHandleScope<1> hs(soa.Self());
+  Handle<mirror::ClassLoader> class_loader(
+      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(class_loader_)));
   ASSERT_TRUE(
       Runtime::Current()->GetJavaVM()->LoadNativeLibrary("", class_loader, &reason)) << reason;
 
diff --git a/compiler/jni/portable/jni_compiler.cc b/compiler/jni/portable/jni_compiler.cc
index 0c14346..d2f54f8 100644
--- a/compiler/jni/portable/jni_compiler.cc
+++ b/compiler/jni/portable/jni_compiler.cc
@@ -98,7 +98,7 @@
   arg_begin = arg_iter;
 
   // Count the number of Object* arguments
-  uint32_t sirt_size = 1;
+  uint32_t handle_scope_size = 1;
   // "this" object pointer for non-static
   // "class" object pointer for static
   for (unsigned i = 0; arg_iter != arg_end; ++i, ++arg_iter) {
@@ -106,12 +106,12 @@
     arg_iter->setName(StringPrintf("a%u", i));
 #endif
     if (arg_iter->getType() == irb_.getJObjectTy()) {
-      ++sirt_size;
+      ++handle_scope_size;
     }
   }
 
   // Shadow stack
-  ::llvm::StructType* shadow_frame_type = irb_.getShadowFrameTy(sirt_size);
+  ::llvm::StructType* shadow_frame_type = irb_.getShadowFrameTy(handle_scope_size);
   ::llvm::AllocaInst* shadow_frame_ = irb_.CreateAlloca(shadow_frame_type);
 
   // Store the dex pc
@@ -123,7 +123,7 @@
   // Push the shadow frame
   ::llvm::Value* shadow_frame_upcast = irb_.CreateConstGEP2_32(shadow_frame_, 0, 0);
   ::llvm::Value* old_shadow_frame =
-      irb_.Runtime().EmitPushShadowFrame(shadow_frame_upcast, method_object_addr, sirt_size);
+      irb_.Runtime().EmitPushShadowFrame(shadow_frame_upcast, method_object_addr, handle_scope_size);
 
   // Get JNIEnv
   ::llvm::Value* jni_env_object_addr =
@@ -148,35 +148,35 @@
   // Variables for GetElementPtr
   ::llvm::Value* gep_index[] = {
     irb_.getInt32(0),  // No displacement for shadow frame pointer
-    irb_.getInt32(1),  // SIRT
+    irb_.getInt32(1),  // handle scope
     NULL,
   };
 
-  size_t sirt_member_index = 0;
+  size_t handle_scope_member_index = 0;
 
-  // Store the "this object or class object" to SIRT
-  gep_index[2] = irb_.getInt32(sirt_member_index++);
-  ::llvm::Value* sirt_field_addr = irb_.CreateBitCast(irb_.CreateGEP(shadow_frame_, gep_index),
+  // Store the "this object or class object" to handle scope
+  gep_index[2] = irb_.getInt32(handle_scope_member_index++);
+  ::llvm::Value* handle_scope_field_addr = irb_.CreateBitCast(irb_.CreateGEP(shadow_frame_, gep_index),
                                                     irb_.getJObjectTy()->getPointerTo());
-  irb_.CreateStore(this_object_or_class_object, sirt_field_addr, kTBAAShadowFrame);
+  irb_.CreateStore(this_object_or_class_object, handle_scope_field_addr, kTBAAShadowFrame);
   // Push the "this object or class object" to out args
-  this_object_or_class_object = irb_.CreateBitCast(sirt_field_addr, irb_.getJObjectTy());
+  this_object_or_class_object = irb_.CreateBitCast(handle_scope_field_addr, irb_.getJObjectTy());
   args.push_back(this_object_or_class_object);
-  // Store arguments to SIRT, and push back to args
+  // Store arguments to handle scope, and push back to args
   for (arg_iter = arg_begin; arg_iter != arg_end; ++arg_iter) {
     if (arg_iter->getType() == irb_.getJObjectTy()) {
-      // Store the reference type arguments to SIRT
-      gep_index[2] = irb_.getInt32(sirt_member_index++);
-      ::llvm::Value* sirt_field_addr = irb_.CreateBitCast(irb_.CreateGEP(shadow_frame_, gep_index),
+      // Store the reference type arguments to handle scope
+      gep_index[2] = irb_.getInt32(handle_scope_member_index++);
+      ::llvm::Value* handle_scope_field_addr = irb_.CreateBitCast(irb_.CreateGEP(shadow_frame_, gep_index),
                                                         irb_.getJObjectTy()->getPointerTo());
-      irb_.CreateStore(arg_iter, sirt_field_addr, kTBAAShadowFrame);
-      // Note null is placed in the SIRT but the jobject passed to the native code must be null
-      // (not a pointer into the SIRT as with regular references).
+      irb_.CreateStore(arg_iter, handle_scope_field_addr, kTBAAShadowFrame);
+      // Note null is placed in the handle scope but the jobject passed to the native code must be null
+      // (not a pointer into the handle scope as with regular references).
       ::llvm::Value* equal_null = irb_.CreateICmpEQ(arg_iter, irb_.getJNull());
       ::llvm::Value* arg =
           irb_.CreateSelect(equal_null,
                             irb_.getJNull(),
-                            irb_.CreateBitCast(sirt_field_addr, irb_.getJObjectTy()));
+                            irb_.CreateBitCast(handle_scope_field_addr, irb_.getJObjectTy()));
       args.push_back(arg);
     } else {
       args.push_back(arg_iter);
diff --git a/compiler/jni/quick/arm/calling_convention_arm.cc b/compiler/jni/quick/arm/calling_convention_arm.cc
index ae18d2e..649a80f 100644
--- a/compiler/jni/quick/arm/calling_convention_arm.cc
+++ b/compiler/jni/quick/arm/calling_convention_arm.cc
@@ -144,10 +144,10 @@
 size_t ArmJniCallingConvention::FrameSize() {
   // Method*, LR and callee save area size, local reference segment state
   size_t frame_data_size = (3 + CalleeSaveRegisters().size()) * kFramePointerSize;
-  // References plus 2 words for SIRT header
-  size_t sirt_size = StackIndirectReferenceTable::GetAlignedSirtSizeTarget(kFramePointerSize, ReferenceCount());
+  // References plus 2 words for HandleScope header
+  size_t handle_scope_size = HandleScope::GetAlignedHandleScopeSizeTarget(kFramePointerSize, ReferenceCount());
   // Plus return value spill area size
-  return RoundUp(frame_data_size + sirt_size + SizeOfReturnValue(), kStackAlignment);
+  return RoundUp(frame_data_size + handle_scope_size + SizeOfReturnValue(), kStackAlignment);
 }
 
 size_t ArmJniCallingConvention::OutArgSize() {
diff --git a/compiler/jni/quick/arm64/calling_convention_arm64.cc b/compiler/jni/quick/arm64/calling_convention_arm64.cc
index 6212a23..ffd27ee 100644
--- a/compiler/jni/quick/arm64/calling_convention_arm64.cc
+++ b/compiler/jni/quick/arm64/calling_convention_arm64.cc
@@ -197,10 +197,10 @@
 size_t Arm64JniCallingConvention::FrameSize() {
   // Method*, callee save area size, local reference segment state
   size_t frame_data_size = ((1 + CalleeSaveRegisters().size()) * kFramePointerSize) + sizeof(uint32_t);
-  // References plus 2 words for SIRT header
-  size_t sirt_size = StackIndirectReferenceTable::GetAlignedSirtSizeTarget(kFramePointerSize, ReferenceCount());
+  // References plus 2 words for HandleScope header
+  size_t handle_scope_size = HandleScope::GetAlignedHandleScopeSizeTarget(kFramePointerSize, ReferenceCount());
   // Plus return value spill area size
-  return RoundUp(frame_data_size + sirt_size + SizeOfReturnValue(), kStackAlignment);
+  return RoundUp(frame_data_size + handle_scope_size + SizeOfReturnValue(), kStackAlignment);
 }
 
 size_t Arm64JniCallingConvention::OutArgSize() {
diff --git a/compiler/jni/quick/calling_convention.cc b/compiler/jni/quick/calling_convention.cc
index a99a4c2..95c2d40 100644
--- a/compiler/jni/quick/calling_convention.cc
+++ b/compiler/jni/quick/calling_convention.cc
@@ -126,8 +126,8 @@
 }
 
 FrameOffset JniCallingConvention::SavedLocalReferenceCookieOffset() const {
-  size_t references_size = sirt_pointer_size_ * ReferenceCount();  // size excluding header
-  return FrameOffset(SirtReferencesOffset().Int32Value() + references_size);
+  size_t references_size = handle_scope_pointer_size_ * ReferenceCount();  // size excluding header
+  return FrameOffset(HandleerencesOffset().Int32Value() + references_size);
 }
 
 FrameOffset JniCallingConvention::ReturnValueSaveLocation() const {
@@ -219,13 +219,13 @@
   }
 }
 
-// Return position of SIRT entry holding reference at the current iterator
+// Return position of handle scope entry holding reference at the current iterator
 // position
-FrameOffset JniCallingConvention::CurrentParamSirtEntryOffset() {
+FrameOffset JniCallingConvention::CurrentParamHandleScopeEntryOffset() {
   CHECK(IsCurrentParamAReference());
-  CHECK_LT(SirtLinkOffset(), SirtNumRefsOffset());
-  int result = SirtReferencesOffset().Int32Value() + itr_refs_ * sirt_pointer_size_;
-  CHECK_GT(result, SirtNumRefsOffset().Int32Value());
+  CHECK_LT(HandleScopeLinkOffset(), HandleScopeNumRefsOffset());
+  int result = HandleerencesOffset().Int32Value() + itr_refs_ * handle_scope_pointer_size_;
+  CHECK_GT(result, HandleScopeNumRefsOffset().Int32Value());
   return FrameOffset(result);
 }
 
diff --git a/compiler/jni/quick/calling_convention.h b/compiler/jni/quick/calling_convention.h
index 18afd58..2a6e7d9 100644
--- a/compiler/jni/quick/calling_convention.h
+++ b/compiler/jni/quick/calling_convention.h
@@ -18,7 +18,7 @@
 #define ART_COMPILER_JNI_QUICK_CALLING_CONVENTION_H_
 
 #include <vector>
-#include "stack_indirect_reference_table.h"
+#include "handle_scope.h"
 #include "thread.h"
 #include "utils/managed_register.h"
 
@@ -73,7 +73,7 @@
       : itr_slots_(0), itr_refs_(0), itr_args_(0), itr_longs_and_doubles_(0),
         itr_float_and_doubles_(0), displacement_(0),
         frame_pointer_size_(frame_pointer_size),
-        sirt_pointer_size_(sizeof(StackReference<mirror::Object>)),
+        handle_scope_pointer_size_(sizeof(StackReference<mirror::Object>)),
         is_static_(is_static), is_synchronized_(is_synchronized),
         shorty_(shorty) {
     num_args_ = (is_static ? 0 : 1) + strlen(shorty) - 1;
@@ -197,8 +197,8 @@
   FrameOffset displacement_;
   // The size of a reference.
   const size_t frame_pointer_size_;
-  // The size of a reference entry within the SIRT.
-  const size_t sirt_pointer_size_;
+  // The size of a reference entry within the handle scope.
+  const size_t handle_scope_pointer_size_;
 
  private:
   const bool is_static_;
@@ -315,26 +315,25 @@
   virtual FrameOffset CurrentParamStackOffset() = 0;
 
   // Iterator interface extension for JNI
-  FrameOffset CurrentParamSirtEntryOffset();
+  FrameOffset CurrentParamHandleScopeEntryOffset();
 
-  // Position of SIRT and interior fields
-  FrameOffset SirtOffset() const {
+  // Position of handle scope and interior fields
+  FrameOffset HandleScopeOffset() const {
     return FrameOffset(this->displacement_.Int32Value() + frame_pointer_size_);  // above Method*
   }
 
-  FrameOffset SirtLinkOffset() const {
-    return FrameOffset(SirtOffset().Int32Value() +
-                       StackIndirectReferenceTable::LinkOffset(frame_pointer_size_));
+  FrameOffset HandleScopeLinkOffset() const {
+    return FrameOffset(HandleScopeOffset().Int32Value() + HandleScope::LinkOffset(frame_pointer_size_));
   }
 
-  FrameOffset SirtNumRefsOffset() const {
-    return FrameOffset(SirtOffset().Int32Value() +
-                       StackIndirectReferenceTable::NumberOfReferencesOffset(frame_pointer_size_));
+  FrameOffset HandleScopeNumRefsOffset() const {
+    return FrameOffset(HandleScopeOffset().Int32Value() +
+                       HandleScope::NumberOfReferencesOffset(frame_pointer_size_));
   }
 
-  FrameOffset SirtReferencesOffset() const {
-    return FrameOffset(SirtOffset().Int32Value() +
-                       StackIndirectReferenceTable::ReferencesOffset(frame_pointer_size_));
+  FrameOffset HandleerencesOffset() const {
+    return FrameOffset(HandleScopeOffset().Int32Value() +
+                       HandleScope::ReferencesOffset(frame_pointer_size_));
   }
 
   virtual ~JniCallingConvention() {}
@@ -350,7 +349,7 @@
                                 size_t frame_pointer_size)
       : CallingConvention(is_static, is_synchronized, shorty, frame_pointer_size) {}
 
-  // Number of stack slots for outgoing arguments, above which the SIRT is
+  // Number of stack slots for outgoing arguments, above which the handle scope is
   // located
   virtual size_t NumberOfOutgoingStackArgs() = 0;
 
diff --git a/compiler/jni/quick/jni_compiler.cc b/compiler/jni/quick/jni_compiler.cc
index 5a22170..20f9f4b 100644
--- a/compiler/jni/quick/jni_compiler.cc
+++ b/compiler/jni/quick/jni_compiler.cc
@@ -103,54 +103,54 @@
   const std::vector<ManagedRegister>& callee_save_regs = main_jni_conv->CalleeSaveRegisters();
   __ BuildFrame(frame_size, mr_conv->MethodRegister(), callee_save_regs, mr_conv->EntrySpills());
 
-  // 2. Set up the StackIndirectReferenceTable
+  // 2. Set up the HandleScope
   mr_conv->ResetIterator(FrameOffset(frame_size));
   main_jni_conv->ResetIterator(FrameOffset(0));
-  __ StoreImmediateToFrame(main_jni_conv->SirtNumRefsOffset(),
+  __ StoreImmediateToFrame(main_jni_conv->HandleScopeNumRefsOffset(),
                            main_jni_conv->ReferenceCount(),
                            mr_conv->InterproceduralScratchRegister());
 
   if (is_64_bit_target) {
-    __ CopyRawPtrFromThread64(main_jni_conv->SirtLinkOffset(),
-                            Thread::TopSirtOffset<8>(),
+    __ CopyRawPtrFromThread64(main_jni_conv->HandleScopeLinkOffset(),
+                            Thread::TopHandleScopeOffset<8>(),
                             mr_conv->InterproceduralScratchRegister());
-    __ StoreStackOffsetToThread64(Thread::TopSirtOffset<8>(),
-                                main_jni_conv->SirtOffset(),
+    __ StoreStackOffsetToThread64(Thread::TopHandleScopeOffset<8>(),
+                                main_jni_conv->HandleScopeOffset(),
                                 mr_conv->InterproceduralScratchRegister());
   } else {
-    __ CopyRawPtrFromThread32(main_jni_conv->SirtLinkOffset(),
-                            Thread::TopSirtOffset<4>(),
+    __ CopyRawPtrFromThread32(main_jni_conv->HandleScopeLinkOffset(),
+                            Thread::TopHandleScopeOffset<4>(),
                             mr_conv->InterproceduralScratchRegister());
-    __ StoreStackOffsetToThread32(Thread::TopSirtOffset<4>(),
-                                main_jni_conv->SirtOffset(),
+    __ StoreStackOffsetToThread32(Thread::TopHandleScopeOffset<4>(),
+                                main_jni_conv->HandleScopeOffset(),
                                 mr_conv->InterproceduralScratchRegister());
   }
 
-  // 3. Place incoming reference arguments into SIRT
+  // 3. Place incoming reference arguments into handle scope
   main_jni_conv->Next();  // Skip JNIEnv*
   // 3.5. Create Class argument for static methods out of passed method
   if (is_static) {
-    FrameOffset sirt_offset = main_jni_conv->CurrentParamSirtEntryOffset();
-    // Check sirt offset is within frame
-    CHECK_LT(sirt_offset.Uint32Value(), frame_size);
+    FrameOffset handle_scope_offset = main_jni_conv->CurrentParamHandleScopeEntryOffset();
+    // Check handle scope offset is within frame
+    CHECK_LT(handle_scope_offset.Uint32Value(), frame_size);
     __ LoadRef(main_jni_conv->InterproceduralScratchRegister(),
                mr_conv->MethodRegister(), mirror::ArtMethod::DeclaringClassOffset());
     __ VerifyObject(main_jni_conv->InterproceduralScratchRegister(), false);
-    __ StoreRef(sirt_offset, main_jni_conv->InterproceduralScratchRegister());
-    main_jni_conv->Next();  // in SIRT so move to next argument
+    __ StoreRef(handle_scope_offset, main_jni_conv->InterproceduralScratchRegister());
+    main_jni_conv->Next();  // in handle scope so move to next argument
   }
   while (mr_conv->HasNext()) {
     CHECK(main_jni_conv->HasNext());
     bool ref_param = main_jni_conv->IsCurrentParamAReference();
     CHECK(!ref_param || mr_conv->IsCurrentParamAReference());
-    // References need placing in SIRT and the entry value passing
+    // References need placing in handle scope and the entry value passing
     if (ref_param) {
-      // Compute SIRT entry, note null is placed in the SIRT but its boxed value
+      // Compute handle scope entry, note null is placed in the handle scope but its boxed value
       // must be NULL
-      FrameOffset sirt_offset = main_jni_conv->CurrentParamSirtEntryOffset();
-      // Check SIRT offset is within frame and doesn't run into the saved segment state
-      CHECK_LT(sirt_offset.Uint32Value(), frame_size);
-      CHECK_NE(sirt_offset.Uint32Value(),
+      FrameOffset handle_scope_offset = main_jni_conv->CurrentParamHandleScopeEntryOffset();
+      // Check handle scope offset is within frame and doesn't run into the saved segment state
+      CHECK_LT(handle_scope_offset.Uint32Value(), frame_size);
+      CHECK_NE(handle_scope_offset.Uint32Value(),
                main_jni_conv->SavedLocalReferenceCookieOffset().Uint32Value());
       bool input_in_reg = mr_conv->IsCurrentParamInRegister();
       bool input_on_stack = mr_conv->IsCurrentParamOnStack();
@@ -159,11 +159,11 @@
       if (input_in_reg) {
         ManagedRegister in_reg  =  mr_conv->CurrentParamRegister();
         __ VerifyObject(in_reg, mr_conv->IsCurrentArgPossiblyNull());
-        __ StoreRef(sirt_offset, in_reg);
+        __ StoreRef(handle_scope_offset, in_reg);
       } else if (input_on_stack) {
         FrameOffset in_off  = mr_conv->CurrentParamStackOffset();
         __ VerifyObject(in_off, mr_conv->IsCurrentArgPossiblyNull());
-        __ CopyRef(sirt_offset, in_off,
+        __ CopyRef(handle_scope_offset, in_off,
                    mr_conv->InterproceduralScratchRegister());
       }
     }
@@ -197,20 +197,20 @@
   ThreadOffset<8> jni_start64 = is_synchronized ? QUICK_ENTRYPOINT_OFFSET(8, pJniMethodStartSynchronized)
                                                 : QUICK_ENTRYPOINT_OFFSET(8, pJniMethodStart);
   main_jni_conv->ResetIterator(FrameOffset(main_out_arg_size));
-  FrameOffset locked_object_sirt_offset(0);
+  FrameOffset locked_object_handle_scope_offset(0);
   if (is_synchronized) {
     // Pass object for locking.
     main_jni_conv->Next();  // Skip JNIEnv.
-    locked_object_sirt_offset = main_jni_conv->CurrentParamSirtEntryOffset();
+    locked_object_handle_scope_offset = main_jni_conv->CurrentParamHandleScopeEntryOffset();
     main_jni_conv->ResetIterator(FrameOffset(main_out_arg_size));
     if (main_jni_conv->IsCurrentParamOnStack()) {
       FrameOffset out_off = main_jni_conv->CurrentParamStackOffset();
-      __ CreateSirtEntry(out_off, locked_object_sirt_offset,
+      __ CreateHandleScopeEntry(out_off, locked_object_handle_scope_offset,
                          mr_conv->InterproceduralScratchRegister(),
                          false);
     } else {
       ManagedRegister out_reg = main_jni_conv->CurrentParamRegister();
-      __ CreateSirtEntry(out_reg, locked_object_sirt_offset,
+      __ CreateHandleScopeEntry(out_reg, locked_object_handle_scope_offset,
                          ManagedRegister::NoRegister(), false);
     }
     main_jni_conv->Next();
@@ -274,15 +274,15 @@
     mr_conv->ResetIterator(FrameOffset(frame_size+main_out_arg_size));
     main_jni_conv->ResetIterator(FrameOffset(main_out_arg_size));
     main_jni_conv->Next();  // Skip JNIEnv*
-    FrameOffset sirt_offset = main_jni_conv->CurrentParamSirtEntryOffset();
+    FrameOffset handle_scope_offset = main_jni_conv->CurrentParamHandleScopeEntryOffset();
     if (main_jni_conv->IsCurrentParamOnStack()) {
       FrameOffset out_off = main_jni_conv->CurrentParamStackOffset();
-      __ CreateSirtEntry(out_off, sirt_offset,
+      __ CreateHandleScopeEntry(out_off, handle_scope_offset,
                          mr_conv->InterproceduralScratchRegister(),
                          false);
     } else {
       ManagedRegister out_reg = main_jni_conv->CurrentParamRegister();
-      __ CreateSirtEntry(out_reg, sirt_offset,
+      __ CreateHandleScopeEntry(out_reg, handle_scope_offset,
                          ManagedRegister::NoRegister(), false);
     }
   }
@@ -369,12 +369,12 @@
     // Pass object for unlocking.
     if (end_jni_conv->IsCurrentParamOnStack()) {
       FrameOffset out_off = end_jni_conv->CurrentParamStackOffset();
-      __ CreateSirtEntry(out_off, locked_object_sirt_offset,
+      __ CreateHandleScopeEntry(out_off, locked_object_handle_scope_offset,
                          end_jni_conv->InterproceduralScratchRegister(),
                          false);
     } else {
       ManagedRegister out_reg = end_jni_conv->CurrentParamRegister();
-      __ CreateSirtEntry(out_reg, locked_object_sirt_offset,
+      __ CreateHandleScopeEntry(out_reg, locked_object_handle_scope_offset,
                          ManagedRegister::NoRegister(), false);
     }
     end_jni_conv->Next();
@@ -438,7 +438,7 @@
                           size_t frame_size, size_t out_arg_size) {
   bool input_in_reg = mr_conv->IsCurrentParamInRegister();
   bool output_in_reg = jni_conv->IsCurrentParamInRegister();
-  FrameOffset sirt_offset(0);
+  FrameOffset handle_scope_offset(0);
   bool null_allowed = false;
   bool ref_param = jni_conv->IsCurrentParamAReference();
   CHECK(!ref_param || mr_conv->IsCurrentParamAReference());
@@ -449,21 +449,21 @@
   } else {
     CHECK(jni_conv->IsCurrentParamOnStack());
   }
-  // References need placing in SIRT and the entry address passing
+  // References need placing in handle scope and the entry address passing
   if (ref_param) {
     null_allowed = mr_conv->IsCurrentArgPossiblyNull();
-    // Compute SIRT offset. Note null is placed in the SIRT but the jobject
-    // passed to the native code must be null (not a pointer into the SIRT
+    // Compute handle scope offset. Note null is placed in the handle scope but the jobject
+    // passed to the native code must be null (not a pointer into the handle scope
     // as with regular references).
-    sirt_offset = jni_conv->CurrentParamSirtEntryOffset();
-    // Check SIRT offset is within frame.
-    CHECK_LT(sirt_offset.Uint32Value(), (frame_size + out_arg_size));
+    handle_scope_offset = jni_conv->CurrentParamHandleScopeEntryOffset();
+    // Check handle scope offset is within frame.
+    CHECK_LT(handle_scope_offset.Uint32Value(), (frame_size + out_arg_size));
   }
   if (input_in_reg && output_in_reg) {
     ManagedRegister in_reg = mr_conv->CurrentParamRegister();
     ManagedRegister out_reg = jni_conv->CurrentParamRegister();
     if (ref_param) {
-      __ CreateSirtEntry(out_reg, sirt_offset, in_reg, null_allowed);
+      __ CreateHandleScopeEntry(out_reg, handle_scope_offset, in_reg, null_allowed);
     } else {
       if (!mr_conv->IsCurrentParamOnStack()) {
         // regular non-straddling move
@@ -475,7 +475,7 @@
   } else if (!input_in_reg && !output_in_reg) {
     FrameOffset out_off = jni_conv->CurrentParamStackOffset();
     if (ref_param) {
-      __ CreateSirtEntry(out_off, sirt_offset, mr_conv->InterproceduralScratchRegister(),
+      __ CreateHandleScopeEntry(out_off, handle_scope_offset, mr_conv->InterproceduralScratchRegister(),
                          null_allowed);
     } else {
       FrameOffset in_off = mr_conv->CurrentParamStackOffset();
@@ -489,7 +489,7 @@
     // Check that incoming stack arguments are above the current stack frame.
     CHECK_GT(in_off.Uint32Value(), frame_size);
     if (ref_param) {
-      __ CreateSirtEntry(out_reg, sirt_offset, ManagedRegister::NoRegister(), null_allowed);
+      __ CreateHandleScopeEntry(out_reg, handle_scope_offset, ManagedRegister::NoRegister(), null_allowed);
     } else {
       size_t param_size = mr_conv->CurrentParamSize();
       CHECK_EQ(param_size, jni_conv->CurrentParamSize());
@@ -502,8 +502,8 @@
     // Check outgoing argument is within frame
     CHECK_LT(out_off.Uint32Value(), frame_size);
     if (ref_param) {
-      // TODO: recycle value in in_reg rather than reload from SIRT
-      __ CreateSirtEntry(out_off, sirt_offset, mr_conv->InterproceduralScratchRegister(),
+      // TODO: recycle value in in_reg rather than reload from handle scope
+      __ CreateHandleScopeEntry(out_off, handle_scope_offset, mr_conv->InterproceduralScratchRegister(),
                          null_allowed);
     } else {
       size_t param_size = mr_conv->CurrentParamSize();
diff --git a/compiler/jni/quick/mips/calling_convention_mips.cc b/compiler/jni/quick/mips/calling_convention_mips.cc
index 8e1c0c7..0402fe6 100644
--- a/compiler/jni/quick/mips/calling_convention_mips.cc
+++ b/compiler/jni/quick/mips/calling_convention_mips.cc
@@ -148,10 +148,10 @@
 size_t MipsJniCallingConvention::FrameSize() {
   // Method*, LR and callee save area size, local reference segment state
   size_t frame_data_size = (3 + CalleeSaveRegisters().size()) * kFramePointerSize;
-  // References plus 2 words for SIRT header
-  size_t sirt_size = StackIndirectReferenceTable::GetAlignedSirtSizeTarget(kFramePointerSize, ReferenceCount());
+  // References plus 2 words for HandleScope header
+  size_t handle_scope_size = HandleScope::GetAlignedHandleScopeSizeTarget(kFramePointerSize, ReferenceCount());
   // Plus return value spill area size
-  return RoundUp(frame_data_size + sirt_size + SizeOfReturnValue(), kStackAlignment);
+  return RoundUp(frame_data_size + handle_scope_size + SizeOfReturnValue(), kStackAlignment);
 }
 
 size_t MipsJniCallingConvention::OutArgSize() {
diff --git a/compiler/jni/quick/x86/calling_convention_x86.cc b/compiler/jni/quick/x86/calling_convention_x86.cc
index 153f953..97b4cdf 100644
--- a/compiler/jni/quick/x86/calling_convention_x86.cc
+++ b/compiler/jni/quick/x86/calling_convention_x86.cc
@@ -125,10 +125,10 @@
 size_t X86JniCallingConvention::FrameSize() {
   // Method*, return address and callee save area size, local reference segment state
   size_t frame_data_size = (3 + CalleeSaveRegisters().size()) * kFramePointerSize;
-  // References plus 2 words for SIRT header
-  size_t sirt_size = StackIndirectReferenceTable::GetAlignedSirtSizeTarget(kFramePointerSize, ReferenceCount());
+  // References plus 2 words for HandleScope header
+  size_t handle_scope_size = HandleScope::GetAlignedHandleScopeSizeTarget(kFramePointerSize, ReferenceCount());
   // Plus return value spill area size
-  return RoundUp(frame_data_size + sirt_size + SizeOfReturnValue(), kStackAlignment);
+  return RoundUp(frame_data_size + handle_scope_size + SizeOfReturnValue(), kStackAlignment);
 }
 
 size_t X86JniCallingConvention::OutArgSize() {
diff --git a/compiler/jni/quick/x86_64/calling_convention_x86_64.cc b/compiler/jni/quick/x86_64/calling_convention_x86_64.cc
index 4dfa29a..4871c87 100644
--- a/compiler/jni/quick/x86_64/calling_convention_x86_64.cc
+++ b/compiler/jni/quick/x86_64/calling_convention_x86_64.cc
@@ -133,17 +133,17 @@
 }
 
 uint32_t X86_64JniCallingConvention::CoreSpillMask() const {
-  return 1 << RBX | 1 << RBP | 1 << R12 | 1 << R13 | 1 << R14 | 1 << R15 | 1 << R13 |
+  return 1 << RBX | 1 << RBP | 1 << R12 | 1 << R13 | 1 << R14 | 1 << R15 |
       1 << kNumberOfCpuRegisters;
 }
 
 size_t X86_64JniCallingConvention::FrameSize() {
   // Method*, return address and callee save area size, local reference segment state
   size_t frame_data_size = (3 + CalleeSaveRegisters().size()) * kFramePointerSize;
-  // References plus link_ (pointer) and number_of_references_ (uint32_t) for SIRT header
-  size_t sirt_size = StackIndirectReferenceTable::GetAlignedSirtSizeTarget(kFramePointerSize, ReferenceCount());
+  // References plus link_ (pointer) and number_of_references_ (uint32_t) for HandleScope header
+  size_t handle_scope_size = HandleScope::GetAlignedHandleScopeSizeTarget(kFramePointerSize, ReferenceCount());
   // Plus return value spill area size
-  return RoundUp(frame_data_size + sirt_size + SizeOfReturnValue(), kStackAlignment);
+  return RoundUp(frame_data_size + handle_scope_size + SizeOfReturnValue(), kStackAlignment);
 }
 
 size_t X86_64JniCallingConvention::OutArgSize() {
diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc
index b5d3923..ce35d0f 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -17,11 +17,12 @@
 #include "common_compiler_test.h"
 #include "compiler/compiler.h"
 #include "compiler/oat_writer.h"
+#include "entrypoints/quick/quick_entrypoints.h"
 #include "mirror/art_method-inl.h"
 #include "mirror/class-inl.h"
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
-#include "oat_file.h"
+#include "oat_file-inl.h"
 #include "vector_output_stream.h"
 
 namespace art {
@@ -152,7 +153,8 @@
       num_virtual_methods = it.NumVirtualMethods();
     }
     const char* descriptor = dex_file->GetClassDescriptor(class_def);
-    SirtRef<mirror::ClassLoader> loader(soa.Self(), nullptr);
+    StackHandleScope<1> hs(soa.Self());
+    auto loader(hs.NewHandle<mirror::ClassLoader>(nullptr));
     mirror::Class* klass = class_linker->FindClass(soa.Self(), descriptor, loader);
 
     const OatFile::OatClass oat_class = oat_dex_file->GetOatClass(i);
@@ -176,8 +178,9 @@
   // If this test is failing and you have to update these constants,
   // it is time to update OatHeader::kOatVersion
   EXPECT_EQ(80U, sizeof(OatHeader));
-  EXPECT_EQ(20U, sizeof(OatMethodOffsets));
-  EXPECT_EQ(12U, sizeof(OatMethodHeader));
+  EXPECT_EQ(8U, sizeof(OatMethodOffsets));
+  EXPECT_EQ(24U, sizeof(OatQuickMethodHeader));
+  EXPECT_EQ(80 * GetInstructionSetPointerSize(kRuntimeISA), sizeof(QuickEntryPoints));
 }
 
 TEST_F(OatTest, OatHeaderIsValid) {
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index bbc9c3e..bace25c 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -33,7 +33,7 @@
 #include "output_stream.h"
 #include "safe_map.h"
 #include "scoped_thread_state_change.h"
-#include "sirt_ref-inl.h"
+#include "handle_scope-inl.h"
 #include "verifier/method_verifier.h"
 
 namespace art {
@@ -331,9 +331,6 @@
     if (compiled_method != nullptr) {
       // Derived from CompiledMethod.
       uint32_t quick_code_offset = 0;
-      uint32_t frame_size_in_bytes = kStackAlignment;
-      uint32_t core_spill_mask = 0;
-      uint32_t fp_spill_mask = 0;
 
       const std::vector<uint8_t>* portable_code = compiled_method->GetPortableCode();
       const std::vector<uint8_t>* quick_code = compiled_method->GetQuickCode();
@@ -351,7 +348,7 @@
         uint32_t code_size = quick_code->size() * sizeof(uint8_t);
         CHECK_NE(code_size, 0U);
         uint32_t thumb_offset = compiled_method->CodeDelta();
-        quick_code_offset = offset_ + sizeof(OatMethodHeader) + thumb_offset;
+        quick_code_offset = offset_ + sizeof(OatQuickMethodHeader) + thumb_offset;
 
         std::vector<uint8_t>* cfi_info = writer_->compiler_driver_->GetCallFrameInformation();
         if (cfi_info != nullptr) {
@@ -374,27 +371,45 @@
           }
         }
 
-        DCHECK_LT(method_offsets_index_, oat_class->method_headers_.size());
-        OatMethodHeader* method_header = &oat_class->method_headers_[method_offsets_index_];
-        method_header->code_size_ = code_size;
-
         // Deduplicate code arrays.
         auto code_iter = dedupe_map_.find(compiled_method);
         if (code_iter != dedupe_map_.end()) {
           quick_code_offset = code_iter->second;
-          FixupMethodHeader(method_header, quick_code_offset - thumb_offset);
         } else {
           dedupe_map_.Put(compiled_method, quick_code_offset);
-          FixupMethodHeader(method_header, quick_code_offset - thumb_offset);
+        }
+
+        // Update quick method header.
+        DCHECK_LT(method_offsets_index_, oat_class->method_headers_.size());
+        OatQuickMethodHeader* method_header = &oat_class->method_headers_[method_offsets_index_];
+        uint32_t mapping_table_offset = method_header->mapping_table_offset_;
+        uint32_t vmap_table_offset = method_header->vmap_table_offset_;
+        // The code offset was 0 when the mapping/vmap table offset was set, so it's set
+        // to 0-offset and we need to adjust it by code_offset.
+        uint32_t code_offset = quick_code_offset - thumb_offset;
+        if (mapping_table_offset != 0u) {
+          mapping_table_offset += code_offset;
+          DCHECK_LT(mapping_table_offset, code_offset);
+        }
+        if (vmap_table_offset != 0u) {
+          vmap_table_offset += code_offset;
+          DCHECK_LT(vmap_table_offset, code_offset);
+        }
+        uint32_t frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
+        uint32_t core_spill_mask = compiled_method->GetCoreSpillMask();
+        uint32_t fp_spill_mask = compiled_method->GetFpSpillMask();
+        *method_header = OatQuickMethodHeader(mapping_table_offset, vmap_table_offset,
+                                              frame_size_in_bytes, core_spill_mask, fp_spill_mask,
+                                              code_size);
+
+        // Update checksum if this wasn't a duplicate.
+        if (code_iter == dedupe_map_.end()) {
           writer_->oat_header_->UpdateChecksum(method_header, sizeof(*method_header));
           offset_ += sizeof(*method_header);  // Method header is prepended before code.
           writer_->oat_header_->UpdateChecksum(&(*quick_code)[0], code_size);
           offset_ += code_size;
         }
       }
-      frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
-      core_spill_mask = compiled_method->GetCoreSpillMask();
-      fp_spill_mask = compiled_method->GetFpSpillMask();
 
       if (kIsDebugBuild) {
         // We expect GC maps except when the class hasn't been verified or the method is native.
@@ -421,9 +436,6 @@
       DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
       OatMethodOffsets* offsets = &oat_class->method_offsets_[method_offsets_index_];
       offsets->code_offset_ = quick_code_offset;
-      offsets->frame_size_in_bytes_ = frame_size_in_bytes;
-      offsets->core_spill_mask_ = core_spill_mask;
-      offsets->fp_spill_mask_ = fp_spill_mask;
       ++method_offsets_index_;
     }
 
@@ -431,19 +443,6 @@
   }
 
  private:
-  static void FixupMethodHeader(OatMethodHeader* method_header, uint32_t code_offset) {
-    // The code offset was 0 when the mapping/vmap table offset was set, so it's set
-    // to 0-offset and we need to adjust it by code_offset.
-    if (method_header->mapping_table_offset_ != 0u) {
-      method_header->mapping_table_offset_ += code_offset;
-      DCHECK_LT(method_header->mapping_table_offset_, code_offset);
-    }
-    if (method_header->vmap_table_offset_ != 0u) {
-      method_header->vmap_table_offset_ += code_offset;
-      DCHECK_LT(method_header->vmap_table_offset_, code_offset);
-    }
-  }
-
   // Deduplication is already done on a pointer basis by the compiler driver,
   // so we can simply compare the pointers to find out if things are duplicated.
   SafeMap<const CompiledMethod*, uint32_t, CodeOffsetsKeyComparator> dedupe_map_;
@@ -501,55 +500,23 @@
     OatClass* oat_class = writer_->oat_classes_[oat_class_index_];
     CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
 
-    OatMethodOffsets offsets(0u, kStackAlignment, 0u, 0u, 0u);
+    OatMethodOffsets offsets(0u, 0u);
     if (compiled_method != nullptr) {
       DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
       offsets = oat_class->method_offsets_[method_offsets_index_];
       ++method_offsets_index_;
     }
 
-    // Derive frame size and spill masks for native methods without code:
-    // These are generic JNI methods...
-    uint32_t method_idx = it.GetMemberIndex();
-    bool is_native = (it.GetMemberAccessFlags() & kAccNative) != 0;
-    if (is_native && compiled_method == nullptr) {
-      // Compute Sirt size as putting _every_ reference into it, even null ones.
-      uint32_t s_len;
-      const char* shorty = dex_file_->GetMethodShorty(dex_file_->GetMethodId(method_idx),
-                                                      &s_len);
-      DCHECK(shorty != nullptr);
-      uint32_t refs = 1;    // Native method always has "this" or class.
-      for (uint32_t i = 1; i < s_len; ++i) {
-        if (shorty[i] == 'L') {
-          refs++;
-        }
-      }
-      size_t pointer_size = GetInstructionSetPointerSize(
-          writer_->compiler_driver_->GetInstructionSet());
-      size_t sirt_size = StackIndirectReferenceTable::GetAlignedSirtSizeTarget(pointer_size, refs);
-
-      // Get the generic spill masks and base frame size.
-      mirror::ArtMethod* callee_save_method =
-          Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs);
-
-      offsets.frame_size_in_bytes_ = callee_save_method->GetFrameSizeInBytes() + sirt_size;
-      offsets.core_spill_mask_ = callee_save_method->GetCoreSpillMask();
-      offsets.fp_spill_mask_ = callee_save_method->GetFpSpillMask();
-      DCHECK_EQ(offsets.gc_map_offset_, 0u);
-    }
-
     ClassLinker* linker = Runtime::Current()->GetClassLinker();
     InvokeType invoke_type = it.GetMethodInvokeType(dex_file_->GetClassDef(class_def_index_));
     // Unchecked as we hold mutator_lock_ on entry.
     ScopedObjectAccessUnchecked soa(Thread::Current());
-    SirtRef<mirror::DexCache> dex_cache(soa.Self(), linker->FindDexCache(*dex_file_));
-    SirtRef<mirror::ClassLoader> class_loader(soa.Self(), nullptr);
-    mirror::ArtMethod* method = linker->ResolveMethod(*dex_file_, method_idx, dex_cache,
+    StackHandleScope<2> hs(soa.Self());
+    Handle<mirror::DexCache> dex_cache(hs.NewHandle(linker->FindDexCache(*dex_file_)));
+    auto class_loader = hs.NewHandle<mirror::ClassLoader>(nullptr);
+    mirror::ArtMethod* method = linker->ResolveMethod(*dex_file_, it.GetMemberIndex(), dex_cache,
                                                       class_loader, nullptr, invoke_type);
     CHECK(method != NULL);
-    method->SetFrameSizeInBytes(offsets.frame_size_in_bytes_);
-    method->SetCoreSpillMask(offsets.core_spill_mask_);
-    method->SetFpSpillMask(offsets.fp_spill_mask_);
     // Portable code offsets are set by ElfWriterMclinker::FixupCompiledCodeOffset after linking.
     method->SetQuickOatCodeOffset(offsets.code_offset_);
     method->SetOatNativeGcMapOffset(offsets.gc_map_offset_);
@@ -601,10 +568,10 @@
         // Deduplicate code arrays.
         const OatMethodOffsets& method_offsets = oat_class->method_offsets_[method_offsets_index_];
         DCHECK(method_offsets.code_offset_ < offset_ || method_offsets.code_offset_ ==
-                   offset_ + sizeof(OatMethodHeader) + compiled_method->CodeDelta())
+                   offset_ + sizeof(OatQuickMethodHeader) + compiled_method->CodeDelta())
             << PrettyMethod(it.GetMemberIndex(), *dex_file_);
         if (method_offsets.code_offset_ >= offset_) {
-          const OatMethodHeader& method_header = oat_class->method_headers_[method_offsets_index_];
+          const OatQuickMethodHeader& method_header = oat_class->method_headers_[method_offsets_index_];
           if (!out->WriteFully(&method_header, sizeof(method_header))) {
             ReportWriteFailure("method header", it);
             return false;
diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h
index 7cdd532..85c9b47 100644
--- a/compiler/oat_writer.h
+++ b/compiler/oat_writer.h
@@ -231,7 +231,7 @@
     // oat_method_offsets_offsets_from_oat_class_ should contain 0
     // values in this case).
     std::vector<OatMethodOffsets> method_offsets_;
-    std::vector<OatMethodHeader> method_headers_;
+    std::vector<OatQuickMethodHeader> method_headers_;
 
    private:
     DISALLOW_COPY_AND_ASSIGN(OatClass);
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index b0aa63b..2c2564d 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -311,6 +311,10 @@
     }
   }
 
+  if (return_type == Primitive::kPrimDouble || return_type == Primitive::kPrimFloat) {
+    return false;
+  }
+
   DCHECK_EQ(argument_index, number_of_arguments);
   current_block_->AddInstruction(invoke);
   return true;
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index bbebd3a..beafbcc 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -47,7 +47,7 @@
   Bind(GetLabelOf(block));
   HGraphVisitor* location_builder = GetLocationBuilder();
   HGraphVisitor* instruction_visitor = GetInstructionVisitor();
-  for (HInstructionIterator it(*block->GetInstructions()); !it.Done(); it.Advance()) {
+  for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
     HInstruction* current = it.Current();
     current->Accept(location_builder);
     InitLocations(current);
diff --git a/compiler/optimizing/dominator_test.cc b/compiler/optimizing/dominator_test.cc
index 0417050..3062e37 100644
--- a/compiler/optimizing/dominator_test.cc
+++ b/compiler/optimizing/dominator_test.cc
@@ -167,7 +167,8 @@
     0,
     1,
     1,
-    3
+    3,
+    1,  // Synthesized block to avoid critical edge.
   };
 
   TestCode(data, dominators, sizeof(dominators) / sizeof(int));
@@ -185,7 +186,9 @@
     0,
     1,
     1,
-    -1  // exit block is not dominated by any block due to the spin loop.
+    -1,  // exit block is not dominated by any block due to the spin loop.
+    1,   // block to avoid critical edge.
+    1    // block to avoid critical edge.
   };
 
   TestCode(data, dominators, sizeof(dominators) / sizeof(int));
@@ -205,7 +208,8 @@
     1,
     1,
     1,
-    -1  // exit block is not dominated by any block due to the spin loop.
+    -1,  // exit block is not dominated by any block due to the spin loop.
+    1    // block to avoid critical edge.
   };
 
   TestCode(data, dominators, sizeof(dominators) / sizeof(int));
@@ -225,7 +229,8 @@
     1,
     1,
     1,
-    -1  // exit block is not dominated by any block due to the spin loop.
+    -1,  // exit block is not dominated by any block due to the spin loop.
+    1    // block to avoid critical edge.
   };
 
   TestCode(data, dominators, sizeof(dominators) / sizeof(int));
@@ -247,7 +252,9 @@
     2,
     2,
     1,
-    5  // Block number 5 dominates exit block
+    5,    // Block number 5 dominates exit block
+    1,    // block to avoid critical edge.
+    2     // block to avoid critical edge.
   };
 
   TestCode(data, dominators, sizeof(dominators) / sizeof(int));
diff --git a/compiler/optimizing/find_loops_test.cc b/compiler/optimizing/find_loops_test.cc
new file mode 100644
index 0000000..fab9f7a
--- /dev/null
+++ b/compiler/optimizing/find_loops_test.cc
@@ -0,0 +1,362 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#include "builder.h"
+#include "dex_file.h"
+#include "dex_instruction.h"
+#include "nodes.h"
+#include "optimizing_unit_test.h"
+#include "ssa_liveness_analysis.h"
+#include "utils/arena_allocator.h"
+#include "pretty_printer.h"
+
+#include "gtest/gtest.h"
+
+namespace art {
+
+static HGraph* TestCode(const uint16_t* data, ArenaPool* pool) {
+  ArenaAllocator allocator(pool);
+  HGraphBuilder builder(&allocator);
+  const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
+  HGraph* graph = builder.BuildGraph(*item);
+  graph->BuildDominatorTree();
+  graph->FindNaturalLoops();
+  return graph;
+}
+
+TEST(FindLoopsTest, CFG1) {
+  // Constant is not used.
+  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+    Instruction::CONST_4 | 0 | 0,
+    Instruction::RETURN_VOID);
+
+  ArenaPool arena;
+  HGraph* graph = TestCode(data, &arena);
+  for (size_t i = 0, e = graph->GetBlocks().Size(); i < e; ++i) {
+    ASSERT_EQ(graph->GetBlocks().Get(i)->GetLoopInformation(), nullptr);
+  }
+}
+
+TEST(FindLoopsTest, CFG2) {
+  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+    Instruction::CONST_4 | 0 | 0,
+    Instruction::RETURN);
+
+  ArenaPool arena;
+  HGraph* graph = TestCode(data, &arena);
+  for (size_t i = 0, e = graph->GetBlocks().Size(); i < e; ++i) {
+    ASSERT_EQ(graph->GetBlocks().Get(i)->GetLoopInformation(), nullptr);
+  }
+}
+
+TEST(FindLoopsTest, CFG3) {
+  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+    Instruction::CONST_4 | 3 << 12 | 0,
+    Instruction::CONST_4 | 4 << 12 | 1 << 8,
+    Instruction::ADD_INT_2ADDR | 1 << 12,
+    Instruction::GOTO | 0x100,
+    Instruction::RETURN);
+
+  ArenaPool arena;
+  HGraph* graph = TestCode(data, &arena);
+  for (size_t i = 0, e = graph->GetBlocks().Size(); i < e; ++i) {
+    ASSERT_EQ(graph->GetBlocks().Get(i)->GetLoopInformation(), nullptr);
+  }
+}
+
+TEST(FindLoopsTest, CFG4) {
+  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+    Instruction::CONST_4 | 0 | 0,
+    Instruction::IF_EQ, 4,
+    Instruction::CONST_4 | 4 << 12 | 0,
+    Instruction::GOTO | 0x200,
+    Instruction::CONST_4 | 5 << 12 | 0,
+    Instruction::RETURN | 0 << 8);
+
+  ArenaPool arena;
+  HGraph* graph = TestCode(data, &arena);
+  for (size_t i = 0, e = graph->GetBlocks().Size(); i < e; ++i) {
+    ASSERT_EQ(graph->GetBlocks().Get(i)->GetLoopInformation(), nullptr);
+  }
+}
+
+TEST(FindLoopsTest, CFG5) {
+  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+    Instruction::CONST_4 | 0 | 0,
+    Instruction::IF_EQ, 3,
+    Instruction::CONST_4 | 4 << 12 | 0,
+    Instruction::RETURN | 0 << 8);
+
+  ArenaPool arena;
+  HGraph* graph = TestCode(data, &arena);
+  for (size_t i = 0, e = graph->GetBlocks().Size(); i < e; ++i) {
+    ASSERT_EQ(graph->GetBlocks().Get(i)->GetLoopInformation(), nullptr);
+  }
+}
+
+static void TestBlock(HGraph* graph,
+                      int block_id,
+                      bool is_loop_header,
+                      int parent_loop_header_id,
+                      const int* blocks_in_loop = nullptr,
+                      size_t number_of_blocks = 0) {
+  HBasicBlock* block = graph->GetBlocks().Get(block_id);
+  ASSERT_EQ(block->IsLoopHeader(), is_loop_header);
+  if (parent_loop_header_id == -1) {
+    ASSERT_EQ(block->GetLoopInformation(), nullptr);
+  } else {
+    ASSERT_EQ(block->GetLoopInformation()->GetHeader()->GetBlockId(), parent_loop_header_id);
+  }
+
+  if (blocks_in_loop != nullptr) {
+    HLoopInformation* info = block->GetLoopInformation();
+    const BitVector& blocks = info->GetBlocks();
+    ASSERT_EQ(blocks.NumSetBits(), number_of_blocks);
+    for (size_t i = 0; i < number_of_blocks; ++i) {
+      ASSERT_TRUE(blocks.IsBitSet(blocks_in_loop[i]));
+    }
+  } else {
+    ASSERT_FALSE(block->IsLoopHeader());
+  }
+}
+
+TEST(FindLoopsTest, Loop1) {
+  // Simple loop with one preheader and one back edge.
+  // var a = 0;
+  // while (a == a) {
+  // }
+  // return;
+  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+    Instruction::CONST_4 | 0 | 0,
+    Instruction::IF_EQ, 3,
+    Instruction::GOTO | 0xFE00,
+    Instruction::RETURN_VOID);
+
+  ArenaPool arena;
+  HGraph* graph = TestCode(data, &arena);
+
+  TestBlock(graph, 0, false, -1);            // entry block
+  TestBlock(graph, 1, false, -1);            // pre header
+  const int blocks2[] = {2, 3};
+  TestBlock(graph, 2, true, 2, blocks2, 2);  // loop header
+  TestBlock(graph, 3, false, 2);             // block in loop
+  TestBlock(graph, 4, false, -1);            // return block
+  TestBlock(graph, 5, false, -1);            // exit block
+}
+
+TEST(FindLoopsTest, Loop2) {
+  // Make sure we support a preheader of a loop not being the first predecessor
+  // in the predecessor list of the header.
+  // var a = 0;
+  // while (a == a) {
+  // }
+  // return a;
+  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+    Instruction::CONST_4 | 0 | 0,
+    Instruction::GOTO | 0x400,
+    Instruction::IF_EQ, 4,
+    Instruction::GOTO | 0xFE00,
+    Instruction::GOTO | 0xFD00,
+    Instruction::RETURN | 0 << 8);
+
+  ArenaPool arena;
+  HGraph* graph = TestCode(data, &arena);
+
+  TestBlock(graph, 0, false, -1);            // entry block
+  TestBlock(graph, 1, false, -1);            // goto block
+  const int blocks2[] = {2, 3};
+  TestBlock(graph, 2, true, 2, blocks2, 2);  // loop header
+  TestBlock(graph, 3, false, 2);             // block in loop
+  TestBlock(graph, 4, false, -1);            // pre header
+  TestBlock(graph, 5, false, -1);            // return block
+  TestBlock(graph, 6, false, -1);            // exit block
+}
+
+TEST(FindLoopsTest, Loop3) {
+  // Make sure we create a preheader of a loop when a header originally has two
+  // incoming blocks and one back edge.
+  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+    Instruction::CONST_4 | 0 | 0,
+    Instruction::IF_EQ, 3,
+    Instruction::GOTO | 0x100,
+    Instruction::IF_EQ, 3,
+    Instruction::GOTO | 0xFE00,
+    Instruction::RETURN | 0 << 8);
+
+  ArenaPool arena;
+  HGraph* graph = TestCode(data, &arena);
+
+  TestBlock(graph, 0, false, -1);            // entry block
+  TestBlock(graph, 1, false, -1);            // goto block
+  TestBlock(graph, 2, false, -1);
+  const int blocks2[] = {3, 4};
+  TestBlock(graph, 3, true, 3, blocks2, 2);  // loop header
+  TestBlock(graph, 4, false, 3);             // block in loop
+  TestBlock(graph, 5, false, -1);            // pre header
+  TestBlock(graph, 6, false, -1);            // return block
+  TestBlock(graph, 7, false, -1);            // exit block
+  TestBlock(graph, 8, false, -1);            // synthesized pre header
+}
+
+TEST(FindLoopsTest, Loop4) {
+  // Test loop with originally two back edges.
+  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+    Instruction::CONST_4 | 0 | 0,
+    Instruction::IF_EQ, 6,
+    Instruction::IF_EQ, 3,
+    Instruction::GOTO | 0xFC00,
+    Instruction::GOTO | 0xFB00,
+    Instruction::RETURN | 0 << 8);
+
+  ArenaPool arena;
+  HGraph* graph = TestCode(data, &arena);
+
+  TestBlock(graph, 0, false, -1);            // entry block
+  TestBlock(graph, 1, false, -1);            // pre header
+  const int blocks2[] = {2, 3, 4, 5, 8};
+  TestBlock(graph, 2, true, 2, blocks2, 5);  // loop header
+  TestBlock(graph, 3, false, 2);             // block in loop
+  TestBlock(graph, 4, false, 2);             // original back edge
+  TestBlock(graph, 5, false, 2);             // original back edge
+  TestBlock(graph, 6, false, -1);            // return block
+  TestBlock(graph, 7, false, -1);            // exit block
+  TestBlock(graph, 8, false, 2);             // synthesized back edge
+}
+
+
+TEST(FindLoopsTest, Loop5) {
+  // Test loop with two exit edges.
+  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+    Instruction::CONST_4 | 0 | 0,
+    Instruction::IF_EQ, 6,
+    Instruction::IF_EQ, 3,
+    Instruction::GOTO | 0x0200,
+    Instruction::GOTO | 0xFB00,
+    Instruction::RETURN | 0 << 8);
+
+  ArenaPool arena;
+  HGraph* graph = TestCode(data, &arena);
+
+  TestBlock(graph, 0, false, -1);            // entry block
+  TestBlock(graph, 1, false, -1);            // pre header
+  const int blocks2[] = {2, 3, 5};
+  TestBlock(graph, 2, true, 2, blocks2, 3);  // loop header
+  TestBlock(graph, 3, false, 2);             // block in loop
+  TestBlock(graph, 4, false, -1);            // loop exit
+  TestBlock(graph, 5, false, 2);             // back edge
+  TestBlock(graph, 6, false, -1);            // return block
+  TestBlock(graph, 7, false, -1);            // exit block
+  TestBlock(graph, 8, false, -1);            // synthesized block at the loop exit
+}
+
+TEST(FindLoopsTest, InnerLoop) {
+  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+    Instruction::CONST_4 | 0 | 0,
+    Instruction::IF_EQ, 6,
+    Instruction::IF_EQ, 3,
+    Instruction::GOTO | 0xFE00,  // inner loop
+    Instruction::GOTO | 0xFB00,
+    Instruction::RETURN | 0 << 8);
+
+
+  ArenaPool arena;
+  HGraph* graph = TestCode(data, &arena);
+
+  TestBlock(graph, 0, false, -1);            // entry block
+  TestBlock(graph, 1, false, -1);            // pre header of outer loop
+  const int blocks2[] = {2, 3, 4, 5, 8};
+  TestBlock(graph, 2, true, 2, blocks2, 5);  // outer loop header
+  const int blocks3[] = {3, 4};
+  TestBlock(graph, 3, true, 3, blocks3, 2);  // inner loop header
+  TestBlock(graph, 4, false, 3);             // back edge on inner loop
+  TestBlock(graph, 5, false, 2);             // back edge on outer loop
+  TestBlock(graph, 6, false, -1);            // return block
+  TestBlock(graph, 7, false, -1);            // exit block
+  TestBlock(graph, 8, false, 2);             // synthesized block as pre header of inner loop
+
+  ASSERT_TRUE(graph->GetBlocks().Get(3)->GetLoopInformation()->IsIn(
+                    *graph->GetBlocks().Get(2)->GetLoopInformation()));
+  ASSERT_FALSE(graph->GetBlocks().Get(2)->GetLoopInformation()->IsIn(
+                    *graph->GetBlocks().Get(3)->GetLoopInformation()));
+}
+
+TEST(FindLoopsTest, TwoLoops) {
+  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+    Instruction::CONST_4 | 0 | 0,
+    Instruction::IF_EQ, 3,
+    Instruction::GOTO | 0xFE00,  // first loop
+    Instruction::IF_EQ, 3,
+    Instruction::GOTO | 0xFE00,  // second loop
+    Instruction::RETURN | 0 << 8);
+
+
+  ArenaPool arena;
+  HGraph* graph = TestCode(data, &arena);
+
+  TestBlock(graph, 0, false, -1);            // entry block
+  TestBlock(graph, 1, false, -1);            // pre header of first loop
+  const int blocks2[] = {2, 3};
+  TestBlock(graph, 2, true, 2, blocks2, 2);  // first loop header
+  TestBlock(graph, 3, false, 2);             // back edge of first loop
+  const int blocks4[] = {4, 5};
+  TestBlock(graph, 4, true, 4, blocks4, 2);  // second loop header
+  TestBlock(graph, 5, false, 4);             // back edge of second loop
+  TestBlock(graph, 6, false, -1);            // return block
+  TestBlock(graph, 7, false, -1);            // exit block
+
+  ASSERT_FALSE(graph->GetBlocks().Get(4)->GetLoopInformation()->IsIn(
+                    *graph->GetBlocks().Get(2)->GetLoopInformation()));
+  ASSERT_FALSE(graph->GetBlocks().Get(2)->GetLoopInformation()->IsIn(
+                    *graph->GetBlocks().Get(4)->GetLoopInformation()));
+}
+
+TEST(FindLoopsTest, NonNaturalLoop) {
+  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+    Instruction::CONST_4 | 0 | 0,
+    Instruction::IF_EQ, 3,
+    Instruction::GOTO | 0x0100,
+    Instruction::IF_EQ, 3,
+    Instruction::GOTO | 0xFD00,
+    Instruction::RETURN | 0 << 8);
+
+  ArenaPool arena;
+  HGraph* graph = TestCode(data, &arena);
+  ASSERT_TRUE(graph->GetBlocks().Get(3)->IsLoopHeader());
+  HLoopInformation* info = graph->GetBlocks().Get(3)->GetLoopInformation();
+  ASSERT_FALSE(info->GetHeader()->Dominates(info->GetBackEdges().Get(0)));
+}
+
+TEST(FindLoopsTest, DoWhileLoop) {
+  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+    Instruction::CONST_4 | 0 | 0,
+    Instruction::GOTO | 0x0100,
+    Instruction::IF_EQ, 0xFFFF,
+    Instruction::RETURN | 0 << 8);
+
+  ArenaPool arena;
+  HGraph* graph = TestCode(data, &arena);
+
+  TestBlock(graph, 0, false, -1);            // entry block
+  TestBlock(graph, 1, false, -1);            // pre header of first loop
+  const int blocks2[] = {2, 3, 6};
+  TestBlock(graph, 2, true, 2, blocks2, 3);  // loop header
+  TestBlock(graph, 3, false, 2);             // back edge of first loop
+  TestBlock(graph, 4, false, -1);            // return block
+  TestBlock(graph, 5, false, -1);            // exit block
+  TestBlock(graph, 6, false, 2);             // synthesized block to avoid a critical edge
+}
+
+}  // namespace art
diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc
new file mode 100644
index 0000000..a7604be
--- /dev/null
+++ b/compiler/optimizing/graph_visualizer.cc
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#include "graph_visualizer.h"
+
+#include "driver/dex_compilation_unit.h"
+#include "nodes.h"
+
+namespace art {
+
+/**
+ * HGraph visitor to generate a file suitable for the c1visualizer tool and IRHydra.
+ */
+class HGraphVisualizerPrinter : public HGraphVisitor {
+ public:
+  HGraphVisualizerPrinter(HGraph* graph, std::ostream& output)
+      : HGraphVisitor(graph), output_(output), indent_(0) {}
+
+  void StartTag(const char* name) {
+    AddIndent();
+    output_ << "begin_" << name << std::endl;
+    indent_++;
+  }
+
+  void EndTag(const char* name) {
+    indent_--;
+    AddIndent();
+    output_ << "end_" << name << std::endl;
+  }
+
+  void PrintProperty(const char* name, const char* property) {
+    AddIndent();
+    output_ << name << " \"" << property << "\"" << std::endl;
+  }
+
+  void PrintProperty(const char* name, const char* property, int id) {
+    AddIndent();
+    output_ << name << " \"" << property << id << "\"" << std::endl;
+  }
+
+  void PrintEmptyProperty(const char* name) {
+    AddIndent();
+    output_ << name << std::endl;
+  }
+
+  void PrintTime(const char* name) {
+    AddIndent();
+    output_ << name << " " << time(NULL) << std::endl;
+  }
+
+  void PrintInt(const char* name, int value) {
+    AddIndent();
+    output_ << name << " " << value << std::endl;
+  }
+
+  void AddIndent() {
+    for (size_t i = 0; i < indent_; ++i) {
+      output_ << "  ";
+    }
+  }
+
+  void PrintPredecessors(HBasicBlock* block) {
+    AddIndent();
+    output_ << "predecessors";
+    for (size_t i = 0, e = block->GetPredecessors().Size(); i < e; ++i) {
+      HBasicBlock* predecessor = block->GetPredecessors().Get(i);
+      output_ << " \"B" << predecessor->GetBlockId() << "\" ";
+    }
+    output_<< std::endl;
+  }
+
+  void PrintSuccessors(HBasicBlock* block) {
+    AddIndent();
+    output_ << "successors";
+    for (size_t i = 0, e = block->GetSuccessors().Size(); i < e; ++i) {
+      HBasicBlock* successor = block->GetSuccessors().Get(i);
+      output_ << " \"B" << successor->GetBlockId() << "\" ";
+    }
+    output_<< std::endl;
+  }
+
+
+  void VisitInstruction(HInstruction* instruction) {
+    output_ << instruction->DebugName();
+    if (instruction->InputCount() > 0) {
+      output_ << " [ ";
+      for (HInputIterator inputs(instruction); !inputs.Done(); inputs.Advance()) {
+        output_ << "v" << inputs.Current()->GetId() << " ";
+      }
+      output_ << "]";
+    }
+  }
+
+  void PrintInstructions(const HInstructionList& list) {
+    const char* kEndInstructionMarker = "<|@";
+    for (HInstructionIterator it(list); !it.Done(); it.Advance()) {
+      HInstruction* instruction = it.Current();
+      AddIndent();
+      int bci = 0;
+      output_ << bci << " " << instruction->NumberOfUses() << " v" << instruction->GetId() << " ";
+      instruction->Accept(this);
+      output_ << kEndInstructionMarker << std::endl;
+    }
+  }
+
+  void Run(const char* pass_name) {
+    StartTag("cfg");
+    PrintProperty("name", pass_name);
+    VisitInsertionOrder();
+    EndTag("cfg");
+  }
+
+  void VisitBasicBlock(HBasicBlock* block) {
+    StartTag("block");
+    PrintProperty("name", "B", block->GetBlockId());
+    PrintInt("from_bci", -1);
+    PrintInt("to_bci", -1);
+    PrintPredecessors(block);
+    PrintSuccessors(block);
+    PrintEmptyProperty("xhandlers");
+    PrintEmptyProperty("flags");
+    if (block->GetDominator() != nullptr) {
+      PrintProperty("dominator", "B", block->GetDominator()->GetBlockId());
+    }
+
+    StartTag("states");
+    StartTag("locals");
+    PrintInt("size", 0);
+    PrintProperty("method", "None");
+    for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
+      AddIndent();
+      HInstruction* instruction = it.Current();
+      output_ << instruction->GetId() << " v" << instruction->GetId() << "[ ";
+      for (HInputIterator inputs(instruction); !inputs.Done(); inputs.Advance()) {
+        output_ << inputs.Current()->GetId() << " ";
+      }
+      output_ << "]" << std::endl;
+    }
+    EndTag("locals");
+    EndTag("states");
+
+    StartTag("HIR");
+    PrintInstructions(block->GetPhis());
+    PrintInstructions(block->GetInstructions());
+    EndTag("HIR");
+    EndTag("block");
+  }
+
+ private:
+  std::ostream& output_;
+  size_t indent_;
+
+  DISALLOW_COPY_AND_ASSIGN(HGraphVisualizerPrinter);
+};
+
+HGraphVisualizer::HGraphVisualizer(std::ostream* output,
+                                   HGraph* graph,
+                                   const char* string_filter,
+                                   const DexCompilationUnit& cu)
+    : output_(output), graph_(graph), is_enabled_(false) {
+  if (output == nullptr) {
+    return;
+  }
+  std::string pretty_name = PrettyMethod(cu.GetDexMethodIndex(), *cu.GetDexFile());
+  if (pretty_name.find(string_filter) == std::string::npos) {
+    return;
+  }
+
+  is_enabled_ = true;
+  HGraphVisualizerPrinter printer(graph, *output_);
+  printer.StartTag("compilation");
+  printer.PrintProperty("name", pretty_name.c_str());
+  printer.PrintProperty("method", pretty_name.c_str());
+  printer.PrintTime("date");
+  printer.EndTag("compilation");
+}
+
+void HGraphVisualizer::DumpGraph(const char* pass_name) {
+  if (!is_enabled_) {
+    return;
+  }
+  HGraphVisualizerPrinter printer(graph_, *output_);
+  printer.Run(pass_name);
+}
+
+}  // namespace art
diff --git a/compiler/optimizing/graph_visualizer.h b/compiler/optimizing/graph_visualizer.h
new file mode 100644
index 0000000..433d55d
--- /dev/null
+++ b/compiler/optimizing/graph_visualizer.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2014 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_COMPILER_OPTIMIZING_GRAPH_VISUALIZER_H_
+#define ART_COMPILER_OPTIMIZING_GRAPH_VISUALIZER_H_
+
+#include "utils/allocation.h"
+
+namespace art {
+
+class DexCompilationUnit;
+class HGraph;
+
+/**
+ * If enabled, emits compilation information suitable for the c1visualizer tool
+ * and IRHydra.
+ * Currently only works if the compiler is single threaded.
+ */
+class HGraphVisualizer : public ValueObject {
+ public:
+  /**
+   * If output is not null, and the method name of the dex compilation
+   * unit contains `string_filter`, the compilation information will be
+   * emitted.
+   */
+  HGraphVisualizer(std::ostream* output,
+                   HGraph* graph,
+                   const char* string_filter,
+                   const DexCompilationUnit& cu);
+
+  /**
+   * If this visualizer is enabled, emit the compilation information
+   * in `output_`.
+   */
+  void DumpGraph(const char* pass_name);
+
+ private:
+  std::ostream* const output_;
+  HGraph* const graph_;
+
+  // Is true when `output_` is not null, and the compiled method's name
+  // contains the string_filter given in the constructor.
+  bool is_enabled_;
+
+  DISALLOW_COPY_AND_ASSIGN(HGraphVisualizer);
+};
+
+}  // namespace art
+
+#endif  // ART_COMPILER_OPTIMIZING_GRAPH_VISUALIZER_H_
diff --git a/compiler/optimizing/liveness_test.cc b/compiler/optimizing/liveness_test.cc
index aa4d35e..d665ab9 100644
--- a/compiler/optimizing/liveness_test.cc
+++ b/compiler/optimizing/liveness_test.cc
@@ -188,7 +188,7 @@
     "  kill: (1100)\n"
     "Block 1\n"  // block with if
     "  live in: (1100)\n"
-    "  live out: (0100)\n"
+    "  live out: (1100)\n"
     "  kill: (0010)\n"
     "Block 2\n"  // else block
     "  live in: (0100)\n"
@@ -201,6 +201,10 @@
     "Block 4\n"  // exit block
     "  live in: (0000)\n"
     "  live out: (0000)\n"
+    "  kill: (0000)\n"
+    "Block 5\n"  // block to avoid critical edge. Predecessor is 1, successor is 3.
+    "  live in: (1000)\n"
+    "  live out: (0000)\n"
     "  kill: (0000)\n";
 
   const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
@@ -412,40 +416,45 @@
 
 TEST(LivenessTest, Loop6) {
   // Bitsets are made of:
-  // (constant0, constant4, constant5, phi in block 2, equal in block 2, equal in block 3)
+  // (constant0, constant4, constant5, phi in block 2, equal in block 2, equal in block 3,
+  //  phi in block 8)
   const char* expected =
     "Block 0\n"
-    "  live in: (000000)\n"
-    "  live out: (111000)\n"
-    "  kill: (111000)\n"
+    "  live in: (0000000)\n"
+    "  live out: (1110000)\n"
+    "  kill: (1110000)\n"
     "Block 1\n"
-    "  live in: (111000)\n"
-    "  live out: (011000)\n"
-    "  kill: (000000)\n"
+    "  live in: (1110000)\n"
+    "  live out: (0110000)\n"
+    "  kill: (0000000)\n"
     "Block 2\n"  // loop header
-    "  live in: (011000)\n"
-    "  live out: (011100)\n"
-    "  kill: (000110)\n"
+    "  live in: (0110000)\n"
+    "  live out: (0111000)\n"
+    "  kill: (0001100)\n"
     "Block 3\n"
-    "  live in: (011000)\n"
-    "  live out: (011000)\n"
-    "  kill: (000001)\n"
-    "Block 4\n"  // back edge
-    "  live in: (011000)\n"
-    "  live out: (011000)\n"
-    "  kill: (000000)\n"
-    "Block 5\n"  // back edge
-    "  live in: (011000)\n"
-    "  live out: (011000)\n"
-    "  kill: (000000)\n"
+    "  live in: (0110000)\n"
+    "  live out: (0110000)\n"
+    "  kill: (0000010)\n"
+    "Block 4\n"  // original back edge
+    "  live in: (0110000)\n"
+    "  live out: (0110000)\n"
+    "  kill: (0000000)\n"
+    "Block 5\n"  // original back edge
+    "  live in: (0110000)\n"
+    "  live out: (0110000)\n"
+    "  kill: (0000000)\n"
     "Block 6\n"  // return block
-    "  live in: (000100)\n"
-    "  live out: (000000)\n"
-    "  kill: (000000)\n"
+    "  live in: (0001000)\n"
+    "  live out: (0000000)\n"
+    "  kill: (0000000)\n"
     "Block 7\n"  // exit block
-    "  live in: (000000)\n"
-    "  live out: (000000)\n"
-    "  kill: (000000)\n";
+    "  live in: (0000000)\n"
+    "  live out: (0000000)\n"
+    "  kill: (0000000)\n"
+    "Block 8\n"  // synthesized back edge
+    "  live in: (0110000)\n"
+    "  live out: (0110000)\n"
+    "  kill: (0000001)\n";
 
   const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
@@ -476,7 +485,7 @@
     "  kill: (0000000)\n"
     "Block 2\n"  // loop header
     "  live in: (0110000)\n"
-    "  live out: (0110000)\n"
+    "  live out: (0111000)\n"
     "  kill: (0001100)\n"
     "Block 3\n"
     "  live in: (0110000)\n"
@@ -497,6 +506,10 @@
     "Block 7\n"  // exit block
     "  live in: (0000000)\n"
     "  live out: (0000000)\n"
+    "  kill: (0000000)\n"
+    "Block 8\n"  // synthesized block to avoid critical edge.
+    "  live in: (0001000)\n"
+    "  live out: (0000000)\n"
     "  kill: (0000000)\n";
 
   const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index d153bf7..afaedd7 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -31,16 +31,16 @@
 }
 
 void HGraph::RemoveDeadBlocks(const ArenaBitVector& visited) const {
-  for (size_t i = 0; i < blocks_.Size(); i++) {
+  for (size_t i = 0; i < blocks_.Size(); ++i) {
     if (!visited.IsBitSet(i)) {
       HBasicBlock* block = blocks_.Get(i);
-      for (size_t j = 0; j < block->GetSuccessors()->Size(); j++) {
-        block->GetSuccessors()->Get(j)->RemovePredecessor(block, false);
+      for (size_t j = 0; j < block->GetSuccessors().Size(); ++j) {
+        block->GetSuccessors().Get(j)->RemovePredecessor(block, false);
       }
-      for (HInstructionIterator it(*block->GetPhis()); !it.Done(); it.Advance()) {
+      for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
         block->RemovePhi(it.Current()->AsPhi());
       }
-      for (HInstructionIterator it(*block->GetInstructions()); !it.Done(); it.Advance()) {
+      for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
         block->RemoveInstruction(it.Current());
       }
     }
@@ -55,15 +55,14 @@
 
   visited->SetBit(id);
   visiting->SetBit(id);
-  for (size_t i = 0; i < block->GetSuccessors()->Size(); i++) {
-    HBasicBlock* successor = block->GetSuccessors()->Get(i);
+  for (size_t i = 0; i < block->GetSuccessors().Size(); i++) {
+    HBasicBlock* successor = block->GetSuccessors().Get(i);
     if (visiting->IsBitSet(successor->GetBlockId())) {
       successor->AddBackEdge(block);
     } else {
       VisitBlockForBackEdges(successor, visited, visiting);
     }
   }
-  post_order_.Add(block);
   visiting->ClearBit(id);
 }
 
@@ -78,13 +77,18 @@
   //     predecessors list of live blocks.
   RemoveDeadBlocks(visited);
 
-  // (3) Compute the immediate dominator of each block. We visit
+  // (3) Simplify the CFG now, so that we don't need to recompute
+  //     dominators and the reverse post order.
+  SimplifyCFG();
+
+  // (4) Compute the immediate dominator of each block. We visit
   //     the successors of a block only when all its forward branches
   //     have been processed.
   GrowableArray<size_t> visits(arena_, blocks_.Size());
   visits.SetSize(blocks_.Size());
-  for (size_t i = 0; i < entry_block_->GetSuccessors()->Size(); i++) {
-    VisitBlockForDominatorTree(entry_block_->GetSuccessors()->Get(i), entry_block_, &visits);
+  reverse_post_order_.Add(entry_block_);
+  for (size_t i = 0; i < entry_block_->GetSuccessors().Size(); i++) {
+    VisitBlockForDominatorTree(entry_block_->GetSuccessors().Get(i), entry_block_, &visits);
   }
 }
 
@@ -119,59 +123,172 @@
   // Once all the forward edges have been visited, we know the immediate
   // dominator of the block. We can then start visiting its successors.
   if (visits->Get(block->GetBlockId()) ==
-      block->GetPredecessors()->Size() - block->NumberOfBackEdges()) {
-    for (size_t i = 0; i < block->GetSuccessors()->Size(); i++) {
-      VisitBlockForDominatorTree(block->GetSuccessors()->Get(i), block, visits);
+      block->GetPredecessors().Size() - block->NumberOfBackEdges()) {
+    reverse_post_order_.Add(block);
+    for (size_t i = 0; i < block->GetSuccessors().Size(); i++) {
+      VisitBlockForDominatorTree(block->GetSuccessors().Get(i), block, visits);
     }
   }
 }
 
 void HGraph::TransformToSSA() {
-  DCHECK(!post_order_.IsEmpty());
-  SimplifyCFG();
+  DCHECK(!reverse_post_order_.IsEmpty());
   SsaBuilder ssa_builder(this);
   ssa_builder.BuildSsa();
 }
 
-void HGraph::SimplifyCFG() {
-  for (size_t i = post_order_.Size(); i > 0; --i) {
-    HBasicBlock* current = post_order_.Get(i - 1);
-    if (current->IsLoopHeader()) {
-      // Make sure the loop has only one pre header. This simplifies SSA building by having
-      // to just look at the pre header to know which locals are initialized at entry of the
-      // loop.
-      HLoopInformation* info = current->GetLoopInformation();
-      size_t number_of_incomings = current->GetPredecessors()->Size() - info->NumberOfBackEdges();
-      if (number_of_incomings != 1) {
-        HBasicBlock* pre_header = new (arena_) HBasicBlock(this);
-        AddBlock(pre_header);
-        pre_header->AddInstruction(new (arena_) HGoto());
-        pre_header->SetDominator(current->GetDominator());
-        current->SetDominator(pre_header);
-        post_order_.InsertAt(i, pre_header);
-
-        ArenaBitVector back_edges(arena_, GetBlocks().Size(), false);
-        for (size_t pred = 0; pred < info->GetBackEdges()->Size(); pred++) {
-          back_edges.SetBit(info->GetBackEdges()->Get(pred)->GetBlockId());
-        }
-        for (size_t pred = 0; pred < current->GetPredecessors()->Size(); pred++) {
-          HBasicBlock* predecessor = current->GetPredecessors()->Get(pred);
-          if (!back_edges.IsBitSet(predecessor->GetBlockId())) {
-            current->RemovePredecessor(predecessor);
-            pred--;
-            predecessor->AddSuccessor(pre_header);
-          }
-        }
-        pre_header->AddSuccessor(current);
-      }
-      info->SetPreHeader(current->GetDominator());
+void HGraph::SplitCriticalEdge(HBasicBlock* block, HBasicBlock* successor) {
+  // Insert a new node between `block` and `successor` to split the
+  // critical edge.
+  HBasicBlock* new_block = new (arena_) HBasicBlock(this);
+  AddBlock(new_block);
+  new_block->AddInstruction(new (arena_) HGoto());
+  block->RemoveSuccessor(successor);
+  block->AddSuccessor(new_block);
+  new_block->AddSuccessor(successor);
+  if (successor->IsLoopHeader()) {
+    // If we split at a back edge boundary, make the new block the back edge.
+    HLoopInformation* info = successor->GetLoopInformation();
+    if (info->IsBackEdge(block)) {
+      info->RemoveBackEdge(block);
+      info->AddBackEdge(new_block);
     }
   }
 }
 
-void HLoopInformation::SetPreHeader(HBasicBlock* block) {
-  DCHECK_EQ(header_->GetDominator(), block);
-  pre_header_ = block;
+void HGraph::SimplifyLoop(HBasicBlock* header) {
+  HLoopInformation* info = header->GetLoopInformation();
+
+  // If there are more than one back edge, make them branch to the same block that
+  // will become the only back edge. This simplifies finding natural loops in the
+  // graph.
+  if (info->NumberOfBackEdges() > 1) {
+    HBasicBlock* new_back_edge = new (arena_) HBasicBlock(this);
+    AddBlock(new_back_edge);
+    new_back_edge->AddInstruction(new (arena_) HGoto());
+    for (size_t pred = 0, e = info->GetBackEdges().Size(); pred < e; ++pred) {
+      HBasicBlock* back_edge = info->GetBackEdges().Get(pred);
+      header->RemovePredecessor(back_edge);
+      back_edge->AddSuccessor(new_back_edge);
+    }
+    info->ClearBackEdges();
+    info->AddBackEdge(new_back_edge);
+    new_back_edge->AddSuccessor(header);
+  }
+
+  // Make sure the loop has only one pre header. This simplifies SSA building by having
+  // to just look at the pre header to know which locals are initialized at entry of the
+  // loop.
+  size_t number_of_incomings = header->GetPredecessors().Size() - info->NumberOfBackEdges();
+  if (number_of_incomings != 1) {
+    HBasicBlock* pre_header = new (arena_) HBasicBlock(this);
+    AddBlock(pre_header);
+    pre_header->AddInstruction(new (arena_) HGoto());
+
+    ArenaBitVector back_edges(arena_, GetBlocks().Size(), false);
+    HBasicBlock* back_edge = info->GetBackEdges().Get(0);
+    for (size_t pred = 0; pred < header->GetPredecessors().Size(); ++pred) {
+      HBasicBlock* predecessor = header->GetPredecessors().Get(pred);
+      if (predecessor != back_edge) {
+        header->RemovePredecessor(predecessor);
+        pred--;
+        predecessor->AddSuccessor(pre_header);
+      }
+    }
+    pre_header->AddSuccessor(header);
+  }
+}
+
+void HGraph::SimplifyCFG() {
+  // Simplify the CFG for future analysis, and code generation:
+  // (1): Split critical edges.
+  // (2): Simplify loops by having only one back edge, and one preheader.
+  for (size_t i = 0; i < blocks_.Size(); ++i) {
+    HBasicBlock* block = blocks_.Get(i);
+    if (block->GetSuccessors().Size() > 1) {
+      for (size_t j = 0; j < block->GetSuccessors().Size(); ++j) {
+        HBasicBlock* successor = block->GetSuccessors().Get(j);
+        if (successor->GetPredecessors().Size() > 1) {
+          SplitCriticalEdge(block, successor);
+          --j;
+        }
+      }
+    }
+    if (block->IsLoopHeader()) {
+      SimplifyLoop(block);
+    }
+  }
+}
+
+bool HGraph::FindNaturalLoops() const {
+  for (size_t i = 0; i < blocks_.Size(); ++i) {
+    HBasicBlock* block = blocks_.Get(i);
+    if (block->IsLoopHeader()) {
+      HLoopInformation* info = block->GetLoopInformation();
+      if (!info->Populate()) {
+        // Abort if the loop is non natural. We currently bailout in such cases.
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+void HLoopInformation::PopulateRecursive(HBasicBlock* block) {
+  if (blocks_.IsBitSet(block->GetBlockId())) {
+    return;
+  }
+
+  blocks_.SetBit(block->GetBlockId());
+  block->SetInLoop(this);
+  for (size_t i = 0, e = block->GetPredecessors().Size(); i < e; ++i) {
+    PopulateRecursive(block->GetPredecessors().Get(i));
+  }
+}
+
+bool HLoopInformation::Populate() {
+  DCHECK_EQ(GetBackEdges().Size(), 1u);
+  HBasicBlock* back_edge = GetBackEdges().Get(0);
+  DCHECK(back_edge->GetDominator() != nullptr);
+  if (!header_->Dominates(back_edge)) {
+    // This loop is not natural. Do not bother going further.
+    return false;
+  }
+
+  // Populate this loop: starting with the back edge, recursively add predecessors
+  // that are not already part of that loop. Set the header as part of the loop
+  // to end the recursion.
+  // This is a recursive implementation of the algorithm described in
+  // "Advanced Compiler Design & Implementation" (Muchnick) p192.
+  blocks_.SetBit(header_->GetBlockId());
+  PopulateRecursive(back_edge);
+  return true;
+}
+
+HBasicBlock* HLoopInformation::GetPreHeader() const {
+  DCHECK_EQ(header_->GetPredecessors().Size(), 2u);
+  return header_->GetDominator();
+}
+
+bool HLoopInformation::Contains(const HBasicBlock& block) const {
+  return blocks_.IsBitSet(block.GetBlockId());
+}
+
+bool HLoopInformation::IsIn(const HLoopInformation& other) const {
+  return other.blocks_.IsBitSet(header_->GetBlockId());
+}
+
+bool HBasicBlock::Dominates(HBasicBlock* other) const {
+  // Walk up the dominator tree from `other`, to find out if `this`
+  // is an ancestor.
+  HBasicBlock* current = other;
+  while (current != nullptr) {
+    if (current == this) {
+      return true;
+    }
+    current = current->GetDominator();
+  }
+  return false;
 }
 
 static void Add(HInstructionList* instruction_list,
@@ -303,10 +420,10 @@
 }
 
 void HGraphVisitor::VisitBasicBlock(HBasicBlock* block) {
-  for (HInstructionIterator it(*block->GetPhis()); !it.Done(); it.Advance()) {
+  for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
     it.Current()->Accept(this);
   }
-  for (HInstructionIterator it(*block->GetInstructions()); !it.Done(); it.Advance()) {
+  for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
     it.Current()->Accept(this);
   }
 }
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index bd3d703..27b87ca 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -60,7 +60,7 @@
   explicit HGraph(ArenaAllocator* arena)
       : arena_(arena),
         blocks_(arena, kDefaultNumberOfBlocks),
-        post_order_(arena, kDefaultNumberOfBlocks),
+        reverse_post_order_(arena, kDefaultNumberOfBlocks),
         maximum_number_of_out_vregs_(0),
         number_of_vregs_(0),
         number_of_in_vregs_(0),
@@ -81,6 +81,14 @@
   void TransformToSSA();
   void SimplifyCFG();
 
+  // Find all natural loops in this graph. Aborts computation and returns false
+  // if one loop is not natural, that is the header does not dominate the back
+  // edge.
+  bool FindNaturalLoops() const;
+
+  void SplitCriticalEdge(HBasicBlock* block, HBasicBlock* successor);
+  void SimplifyLoop(HBasicBlock* header);
+
   int GetNextInstructionId() {
     return current_instruction_id_++;
   }
@@ -109,8 +117,8 @@
     return number_of_in_vregs_;
   }
 
-  const GrowableArray<HBasicBlock*>& GetPostOrder() const {
-    return post_order_;
+  const GrowableArray<HBasicBlock*>& GetReversePostOrder() const {
+    return reverse_post_order_;
   }
 
  private:
@@ -129,8 +137,8 @@
   // List of blocks in insertion order.
   GrowableArray<HBasicBlock*> blocks_;
 
-  // List of blocks to perform a post order tree traversal.
-  GrowableArray<HBasicBlock*> post_order_;
+  // List of blocks to perform a reverse post order tree traversal.
+  GrowableArray<HBasicBlock*> reverse_post_order_;
 
   HBasicBlock* entry_block_;
   HBasicBlock* exit_block_;
@@ -154,30 +162,63 @@
  public:
   HLoopInformation(HBasicBlock* header, HGraph* graph)
       : header_(header),
-        back_edges_(graph->GetArena(), kDefaultNumberOfBackEdges) { }
+        back_edges_(graph->GetArena(), kDefaultNumberOfBackEdges),
+        blocks_(graph->GetArena(), graph->GetBlocks().Size(), false) {}
+
+  HBasicBlock* GetHeader() const {
+    return header_;
+  }
 
   void AddBackEdge(HBasicBlock* back_edge) {
     back_edges_.Add(back_edge);
   }
 
+  void RemoveBackEdge(HBasicBlock* back_edge) {
+    back_edges_.Delete(back_edge);
+  }
+
+  bool IsBackEdge(HBasicBlock* block) {
+    for (size_t i = 0, e = back_edges_.Size(); i < e; ++i) {
+      if (back_edges_.Get(i) == block) return true;
+    }
+    return false;
+  }
+
   int NumberOfBackEdges() const {
     return back_edges_.Size();
   }
 
-  void SetPreHeader(HBasicBlock* block);
+  HBasicBlock* GetPreHeader() const;
 
-  HBasicBlock* GetPreHeader() const {
-    return pre_header_;
+  const GrowableArray<HBasicBlock*>& GetBackEdges() const {
+    return back_edges_;
   }
 
-  const GrowableArray<HBasicBlock*>* GetBackEdges() const {
-    return &back_edges_;
+  void ClearBackEdges() {
+    back_edges_.Reset();
   }
 
+  // Find blocks that are part of this loop. Returns whether the loop is a natural loop,
+  // that is the header dominates the back edge.
+  bool Populate();
+
+  // Returns whether this loop information contains `block`.
+  // Note that this loop information *must* be populated before entering this function.
+  bool Contains(const HBasicBlock& block) const;
+
+  // Returns whether this loop information is an inner loop of `other`.
+  // Note that `other` *must* be populated before entering this function.
+  bool IsIn(const HLoopInformation& other) const;
+
+  const ArenaBitVector& GetBlocks() const { return blocks_; }
+
  private:
-  HBasicBlock* pre_header_;
+  // Internal recursive implementation of `Populate`.
+  void PopulateRecursive(HBasicBlock* block);
+
   HBasicBlock* header_;
   GrowableArray<HBasicBlock*> back_edges_;
+  ArenaBitVector blocks_;
 
   DISALLOW_COPY_AND_ASSIGN(HLoopInformation);
 };
@@ -195,18 +236,19 @@
         dominator_(nullptr),
         block_id_(-1) { }
 
-  const GrowableArray<HBasicBlock*>* GetPredecessors() const {
-    return &predecessors_;
+  const GrowableArray<HBasicBlock*>& GetPredecessors() const {
+    return predecessors_;
   }
 
-  const GrowableArray<HBasicBlock*>* GetSuccessors() const {
-    return &successors_;
+  const GrowableArray<HBasicBlock*>& GetSuccessors() const {
+    return successors_;
   }
 
   void AddBackEdge(HBasicBlock* back_edge) {
     if (loop_information_ == nullptr) {
       loop_information_ = new (graph_->GetArena()) HLoopInformation(this, graph_);
     }
+    DCHECK_EQ(loop_information_->GetHeader(), this);
     loop_information_->AddBackEdge(back_edge);
   }
 
@@ -226,8 +268,8 @@
 
   HInstruction* GetFirstInstruction() const { return instructions_.first_instruction_; }
   HInstruction* GetLastInstruction() const { return instructions_.last_instruction_; }
-  HInstructionList const* GetInstructions() const { return &instructions_; }
-  HInstructionList const* GetPhis() const { return &phis_; }
+  const HInstructionList& GetInstructions() const { return instructions_; }
+  const HInstructionList& GetPhis() const { return phis_; }
 
   void AddSuccessor(HBasicBlock* block) {
     successors_.Add(block);
@@ -241,19 +283,57 @@
     }
   }
 
+  void RemoveSuccessor(HBasicBlock* block, bool remove_in_predecessor = true) {
+    successors_.Delete(block);
+    if (remove_in_predecessor) {
+      block->predecessors_.Delete(this);
+    }
+  }
+
+  void ClearAllPredecessors() {
+    predecessors_.Reset();
+  }
+
+  void AddPredecessor(HBasicBlock* block) {
+    predecessors_.Add(block);
+    block->successors_.Add(this);
+  }
+
   void AddInstruction(HInstruction* instruction);
   void RemoveInstruction(HInstruction* instruction);
   void AddPhi(HPhi* phi);
   void RemovePhi(HPhi* phi);
 
   bool IsLoopHeader() const {
-    return loop_information_ != nullptr;
+    return (loop_information_ != nullptr) && (loop_information_->GetHeader() == this);
   }
 
   HLoopInformation* GetLoopInformation() const {
     return loop_information_;
   }
 
+  // Set the loop_information_ on this block. This method overrides the current
+  // loop_information if it is an outer loop of the passed loop information.
+  void SetInLoop(HLoopInformation* info) {
+    if (IsLoopHeader()) {
+      // Nothing to do. This just means `info` is an outer loop.
+    } else if (loop_information_ == nullptr) {
+      loop_information_ = info;
+    } else if (loop_information_->Contains(*info->GetHeader())) {
+      // Block is currently part of an outer loop. Make it part of this inner loop.
+      // Note that a non loop header having a loop information means this loop information
+      // has already been populated
+      loop_information_ = info;
+    } else {
+      // Block is part of an inner loop. Do not update the loop information.
+      // Note that we cannot do the check `info->Contains(loop_information_)->GetHeader()`
+      // at this point, because this method is being called while populating `info`.
+    }
+  }
+
+  // Returns wheter this block dominates the blocked passed as parameter.
+  bool Dominates(HBasicBlock* block) const;
+
  private:
   HGraph* const graph_;
   GrowableArray<HBasicBlock*> predecessors_;
@@ -364,6 +444,17 @@
 
   bool HasUses() const { return uses_ != nullptr || env_uses_ != nullptr; }
 
+  size_t NumberOfUses() const {
+    // TODO: Optimize this method if it is used outside of the HGraphTracer.
+    size_t result = 0;
+    HUseListNode<HInstruction>* current = uses_;
+    while (current != nullptr) {
+      current = current->GetTail();
+      ++result;
+    }
+    return result;
+  }
+
   int GetId() const { return id_; }
   void SetId(int id) { id_ = id; }
 
@@ -638,7 +729,7 @@
   HGoto() { }
 
   HBasicBlock* GetSuccessor() const {
-    return GetBlock()->GetSuccessors()->Get(0);
+    return GetBlock()->GetSuccessors().Get(0);
   }
 
   DECLARE_INSTRUCTION(Goto)
@@ -656,11 +747,11 @@
   }
 
   HBasicBlock* IfTrueSuccessor() const {
-    return GetBlock()->GetSuccessors()->Get(0);
+    return GetBlock()->GetSuccessors().Get(0);
   }
 
   HBasicBlock* IfFalseSuccessor() const {
-    return GetBlock()->GetSuccessors()->Get(1);
+    return GetBlock()->GetSuccessors().Get(1);
   }
 
   DECLARE_INSTRUCTION(If)
@@ -1011,35 +1102,35 @@
   DISALLOW_COPY_AND_ASSIGN(HInsertionOrderIterator);
 };
 
-class HPostOrderIterator : public ValueObject {
+class HReversePostOrderIterator : public ValueObject {
  public:
-  explicit HPostOrderIterator(const HGraph& graph) : graph_(graph), index_(0) {}
+  explicit HReversePostOrderIterator(const HGraph& graph) : graph_(graph), index_(0) {}
 
-  bool Done() const { return index_ == graph_.GetPostOrder().Size(); }
-  HBasicBlock* Current() const { return graph_.GetPostOrder().Get(index_); }
+  bool Done() const { return index_ == graph_.GetReversePostOrder().Size(); }
+  HBasicBlock* Current() const { return graph_.GetReversePostOrder().Get(index_); }
   void Advance() { ++index_; }
 
  private:
   const HGraph& graph_;
   size_t index_;
 
-  DISALLOW_COPY_AND_ASSIGN(HPostOrderIterator);
+  DISALLOW_COPY_AND_ASSIGN(HReversePostOrderIterator);
 };
 
-class HReversePostOrderIterator : public ValueObject {
+class HPostOrderIterator : public ValueObject {
  public:
-  explicit HReversePostOrderIterator(const HGraph& graph)
-      : graph_(graph), index_(graph_.GetPostOrder().Size()) {}
+  explicit HPostOrderIterator(const HGraph& graph)
+      : graph_(graph), index_(graph_.GetReversePostOrder().Size()) {}
 
   bool Done() const { return index_ == 0; }
-  HBasicBlock* Current() const { return graph_.GetPostOrder().Get(index_ - 1); }
+  HBasicBlock* Current() const { return graph_.GetReversePostOrder().Get(index_ - 1); }
   void Advance() { --index_; }
 
  private:
   const HGraph& graph_;
   size_t index_;
 
-  DISALLOW_COPY_AND_ASSIGN(HReversePostOrderIterator);
+  DISALLOW_COPY_AND_ASSIGN(HPostOrderIterator);
 };
 
 }  // namespace art
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 8594c69..f435cb0 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <fstream>
 #include <stdint.h>
 
 #include "builder.h"
@@ -21,6 +22,7 @@
 #include "compilers.h"
 #include "driver/compiler_driver.h"
 #include "driver/dex_compilation_unit.h"
+#include "graph_visualizer.h"
 #include "nodes.h"
 #include "ssa_liveness_analysis.h"
 #include "utils/arena_allocator.h"
@@ -50,6 +52,22 @@
   DISALLOW_COPY_AND_ASSIGN(CodeVectorAllocator);
 };
 
+/**
+ * If set to true, generates a file suitable for the c1visualizer tool and IRHydra.
+ */
+static bool kIsVisualizerEnabled = false;
+
+/**
+ * Filter to apply to the visualizer. Methods whose name contain that filter will
+ * be in the file.
+ */
+static const char* kStringFilter = "";
+
+OptimizingCompiler::OptimizingCompiler(CompilerDriver* driver) : QuickCompiler(driver) {
+  if (kIsVisualizerEnabled) {
+    visualizer_output_.reset(new std::ofstream("art.cfg"));
+  }
+}
 
 CompiledMethod* OptimizingCompiler::TryCompile(const DexFile::CodeItem* code_item,
                                                uint32_t access_flags,
@@ -70,6 +88,7 @@
   ArenaPool pool;
   ArenaAllocator arena(&pool);
   HGraphBuilder builder(&arena, &dex_compilation_unit, &dex_file);
+
   HGraph* graph = builder.BuildGraph(*code_item);
   if (graph == nullptr) {
     if (shouldCompile) {
@@ -77,6 +96,8 @@
     }
     return nullptr;
   }
+  HGraphVisualizer visualizer(visualizer_output_.get(), graph, kStringFilter, dex_compilation_unit);
+  visualizer.DumpGraph("builder");
 
   InstructionSet instruction_set = GetCompilerDriver()->GetInstructionSet();
   // The optimizing compiler currently does not have a Thumb2 assembler.
@@ -104,6 +125,9 @@
   // Run these phases to get some test coverage.
   graph->BuildDominatorTree();
   graph->TransformToSSA();
+  visualizer.DumpGraph("ssa");
+
+  graph->FindNaturalLoops();
   SsaLivenessAnalysis(*graph).Analyze();
 
   return new CompiledMethod(GetCompilerDriver(),
diff --git a/compiler/optimizing/pretty_printer.h b/compiler/optimizing/pretty_printer.h
index c82d0cc..dfeafe7 100644
--- a/compiler/optimizing/pretty_printer.h
+++ b/compiler/optimizing/pretty_printer.h
@@ -70,23 +70,23 @@
   virtual void VisitBasicBlock(HBasicBlock* block) {
     PrintString("BasicBlock ");
     PrintInt(block->GetBlockId());
-    const GrowableArray<HBasicBlock*>* blocks = block->GetPredecessors();
-    if (!blocks->IsEmpty()) {
+    const GrowableArray<HBasicBlock*>& predecessors = block->GetPredecessors();
+    if (!predecessors.IsEmpty()) {
       PrintString(", pred: ");
-      for (size_t i = 0; i < blocks->Size() -1; i++) {
-        PrintInt(blocks->Get(i)->GetBlockId());
+      for (size_t i = 0; i < predecessors.Size() -1; i++) {
+        PrintInt(predecessors.Get(i)->GetBlockId());
         PrintString(", ");
       }
-      PrintInt(blocks->Peek()->GetBlockId());
+      PrintInt(predecessors.Peek()->GetBlockId());
     }
-    blocks = block->GetSuccessors();
-    if (!blocks->IsEmpty()) {
+    const GrowableArray<HBasicBlock*>& successors = block->GetSuccessors();
+    if (!successors.IsEmpty()) {
       PrintString(", succ: ");
-      for (size_t i = 0; i < blocks->Size() - 1; i++) {
-        PrintInt(blocks->Get(i)->GetBlockId());
+      for (size_t i = 0; i < successors.Size() - 1; i++) {
+        PrintInt(successors.Get(i)->GetBlockId());
         PrintString(", ");
       }
-      PrintInt(blocks->Peek()->GetBlockId());
+      PrintInt(successors.Peek()->GetBlockId());
     }
     PrintNewLine();
     HGraphVisitor::VisitBasicBlock(block);
diff --git a/compiler/optimizing/pretty_printer_test.cc b/compiler/optimizing/pretty_printer_test.cc
index 04db7a6..006349c 100644
--- a/compiler/optimizing/pretty_printer_test.cc
+++ b/compiler/optimizing/pretty_printer_test.cc
@@ -57,7 +57,7 @@
     PrintString("  ");
     PrintInt(gota->GetId());
     PrintString(": Goto ");
-    PrintInt(current_block_->GetSuccessors()->Get(0)->GetBlockId());
+    PrintInt(current_block_->GetSuccessors().Get(0)->GetBlockId());
     PrintNewLine();
   }
 
diff --git a/compiler/optimizing/ssa_builder.cc b/compiler/optimizing/ssa_builder.cc
index ee1e1e4..50e3254 100644
--- a/compiler/optimizing/ssa_builder.cc
+++ b/compiler/optimizing/ssa_builder.cc
@@ -30,17 +30,17 @@
   // 2) Set inputs of loop phis.
   for (size_t i = 0; i < loop_headers_.Size(); i++) {
     HBasicBlock* block = loop_headers_.Get(i);
-    for (HInstructionIterator it(*block->GetPhis()); !it.Done(); it.Advance()) {
+    for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
       HPhi* phi = it.Current()->AsPhi();
-      for (size_t pred = 0; pred < block->GetPredecessors()->Size(); pred++) {
-        phi->AddInput(ValueOfLocal(block->GetPredecessors()->Get(pred), phi->GetRegNumber()));
+      for (size_t pred = 0; pred < block->GetPredecessors().Size(); pred++) {
+        phi->AddInput(ValueOfLocal(block->GetPredecessors().Get(pred), phi->GetRegNumber()));
       }
     }
   }
 
   // 3) Clear locals.
   // TODO: Move this to a dead code eliminator phase.
-  for (HInstructionIterator it(*GetGraph()->GetEntryBlock()->GetInstructions());
+  for (HInstructionIterator it(GetGraph()->GetEntryBlock()->GetInstructions());
        !it.Done();
        it.Advance()) {
     HInstruction* current = it.Current();
@@ -75,14 +75,14 @@
     // Save the loop header so that the last phase of the analysis knows which
     // blocks need to be updated.
     loop_headers_.Add(block);
-  } else if (block->GetPredecessors()->Size() > 0) {
+  } else if (block->GetPredecessors().Size() > 0) {
     // All predecessors have already been visited because we are visiting in reverse post order.
     // We merge the values of all locals, creating phis if those values differ.
     for (size_t local = 0; local < current_locals_->Size(); local++) {
       bool is_different = false;
-      HInstruction* value = ValueOfLocal(block->GetPredecessors()->Get(0), local);
-      for (size_t i = 1; i < block->GetPredecessors()->Size(); i++) {
-        if (ValueOfLocal(block->GetPredecessors()->Get(i), local) != value) {
+      HInstruction* value = ValueOfLocal(block->GetPredecessors().Get(0), local);
+      for (size_t i = 1; i < block->GetPredecessors().Size(); i++) {
+        if (ValueOfLocal(block->GetPredecessors().Get(i), local) != value) {
           is_different = true;
           break;
         }
@@ -90,9 +90,9 @@
       if (is_different) {
         // TODO: Compute union type.
         HPhi* phi = new (GetGraph()->GetArena()) HPhi(
-            GetGraph()->GetArena(), local, block->GetPredecessors()->Size(), Primitive::kPrimVoid);
-        for (size_t i = 0; i < block->GetPredecessors()->Size(); i++) {
-          phi->SetRawInputAt(i, ValueOfLocal(block->GetPredecessors()->Get(i), local));
+            GetGraph()->GetArena(), local, block->GetPredecessors().Size(), Primitive::kPrimVoid);
+        for (size_t i = 0; i < block->GetPredecessors().Size(); i++) {
+          phi->SetRawInputAt(i, ValueOfLocal(block->GetPredecessors().Get(i), local));
         }
         block->AddPhi(phi);
         value = phi;
@@ -106,7 +106,7 @@
   // - HStoreLocal: update current value of the local and remove the instruction.
   // - Instructions that require an environment: populate their environment
   //   with the current values of the locals.
-  for (HInstructionIterator it(*block->GetInstructions()); !it.Done(); it.Advance()) {
+  for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
     it.Current()->Accept(this);
   }
 }
diff --git a/compiler/optimizing/ssa_liveness_analysis.cc b/compiler/optimizing/ssa_liveness_analysis.cc
index 838597d..7c2ec39 100644
--- a/compiler/optimizing/ssa_liveness_analysis.cc
+++ b/compiler/optimizing/ssa_liveness_analysis.cc
@@ -29,14 +29,14 @@
   for (HReversePostOrderIterator it(graph_); !it.Done(); it.Advance()) {
     HBasicBlock* block = it.Current();
 
-    for (HInstructionIterator it(*block->GetPhis()); !it.Done(); it.Advance()) {
+    for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
       HInstruction* current = it.Current();
       if (current->HasUses()) {
         current->SetSsaIndex(ssa_index++);
       }
     }
 
-    for (HInstructionIterator it(*block->GetInstructions()); !it.Done(); it.Advance()) {
+    for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
       HInstruction* current = it.Current();
       if (current->HasUses()) {
         current->SetSsaIndex(ssa_index++);
@@ -73,7 +73,7 @@
     BitVector* kill = GetKillSet(*block);
     BitVector* live_in = GetLiveInSet(*block);
 
-    for (HBackwardInstructionIterator it(*block->GetInstructions()); !it.Done(); it.Advance()) {
+    for (HBackwardInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
       HInstruction* current = it.Current();
       if (current->HasSsaIndex()) {
         kill->SetBit(current->GetSsaIndex());
@@ -99,7 +99,7 @@
       }
     }
 
-    for (HInstructionIterator it(*block->GetPhis()); !it.Done(); it.Advance()) {
+    for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
       HInstruction* current = it.Current();
       if (current->HasSsaIndex()) {
         kill->SetBit(current->GetSsaIndex());
@@ -110,7 +110,7 @@
       for (size_t i = 0, e = current->InputCount(); i < e; ++i) {
         HInstruction* input = current->InputAt(i);
 
-        HBasicBlock* predecessor = block->GetPredecessors()->Get(i);
+        HBasicBlock* predecessor = block->GetPredecessors().Get(i);
         size_t ssa_index = input->GetSsaIndex();
         BitVector* predecessor_kill = GetKillSet(*predecessor);
         BitVector* predecessor_live_in = GetLiveInSet(*predecessor);
@@ -147,8 +147,8 @@
   BitVector* live_out = GetLiveOutSet(block);
   bool changed = false;
   // The live_out set of a block is the union of live_in sets of its successors.
-  for (size_t i = 0, e = block.GetSuccessors()->Size(); i < e; ++i) {
-    HBasicBlock* successor = block.GetSuccessors()->Get(i);
+  for (size_t i = 0, e = block.GetSuccessors().Size(); i < e; ++i) {
+    HBasicBlock* successor = block.GetSuccessors().Get(i);
     if (live_out->Union(GetLiveInSet(*successor))) {
       changed = true;
     }
diff --git a/compiler/optimizing/ssa_test.cc b/compiler/optimizing/ssa_test.cc
index e4aafb7..415d146 100644
--- a/compiler/optimizing/ssa_test.cc
+++ b/compiler/optimizing/ssa_test.cc
@@ -66,10 +66,10 @@
   int id = 0;
   for (size_t i = 0, e = graph->GetBlocks().Size(); i < e; ++i) {
     HBasicBlock* block = graph->GetBlocks().Get(i);
-    for (HInstructionIterator it(*block->GetPhis()); !it.Done(); it.Advance()) {
+    for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
       it.Current()->SetId(id++);
     }
-    for (HInstructionIterator it(*block->GetInstructions()); !it.Done(); it.Advance()) {
+    for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
       it.Current()->SetId(id++);
     }
   }
@@ -98,15 +98,18 @@
     "BasicBlock 0, succ: 1\n"
     "  0: IntConstant 0 [2, 2]\n"
     "  1: Goto\n"
-    "BasicBlock 1, pred: 0, succ: 3, 2\n"
+    "BasicBlock 1, pred: 0, succ: 2, 5\n"
     "  2: Equal(0, 0) [3]\n"
     "  3: If(2)\n"
     "BasicBlock 2, pred: 1, succ: 3\n"
     "  4: Goto\n"
-    "BasicBlock 3, pred: 1, 2, succ: 4\n"
+    "BasicBlock 3, pred: 2, 5, succ: 4\n"
     "  5: ReturnVoid\n"
     "BasicBlock 4, pred: 3\n"
-    "  6: Exit\n";
+    "  6: Exit\n"
+    // Synthesized block to avoid critical edge.
+    "BasicBlock 5, pred: 1, succ: 3\n"
+    "  7: Goto\n";
 
   const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
@@ -125,16 +128,19 @@
     "  0: IntConstant 0 [6, 3, 3]\n"
     "  1: IntConstant 4 [6]\n"
     "  2: Goto\n"
-    "BasicBlock 1, pred: 0, succ: 3, 2\n"
+    "BasicBlock 1, pred: 0, succ: 2, 5\n"
     "  3: Equal(0, 0) [4]\n"
     "  4: If(3)\n"
     "BasicBlock 2, pred: 1, succ: 3\n"
     "  5: Goto\n"
-    "BasicBlock 3, pred: 1, 2, succ: 4\n"
-    "  6: Phi(0, 1) [7]\n"
+    "BasicBlock 3, pred: 2, 5, succ: 4\n"
+    "  6: Phi(1, 0) [7]\n"
     "  7: Return(6)\n"
     "BasicBlock 4, pred: 3\n"
-    "  8: Exit\n";
+    "  8: Exit\n"
+    // Synthesized block to avoid critical edge.
+    "BasicBlock 5, pred: 1, succ: 3\n"
+    "  9: Goto\n";
 
   const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
@@ -184,16 +190,21 @@
     "BasicBlock 0, succ: 1\n"
     "  0: IntConstant 0 [6, 4, 2, 2]\n"
     "  1: Goto\n"
-    "BasicBlock 1, pred: 0, succ: 3, 2\n"
+    "BasicBlock 1, pred: 0, succ: 5, 6\n"
     "  2: Equal(0, 0) [3]\n"
     "  3: If(2)\n"
-    "BasicBlock 2, pred: 1, 3, succ: 3\n"
-    "  4: Phi(0, 6) [6]\n"
+    "BasicBlock 2, pred: 3, 6, succ: 3\n"
+    "  4: Phi(6, 0) [6]\n"
     "  5: Goto\n"
-    "BasicBlock 3, pred: 1, 2, succ: 2\n"
-    "  6: Phi(0, 4) [4]\n"
+    "BasicBlock 3, pred: 2, 5, succ: 2\n"
+    "  6: Phi(4, 0) [4]\n"
     "  7: Goto\n"
-    "BasicBlock 4\n";
+    "BasicBlock 4\n"
+    // Synthesized blocks to avoid critical edge.
+    "BasicBlock 5, pred: 1, succ: 3\n"
+    "  8: Goto\n"
+    "BasicBlock 6, pred: 1, succ: 2\n"
+    "  9: Goto\n";
 
   const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
@@ -349,26 +360,30 @@
   const char* expected =
     "BasicBlock 0, succ: 1\n"
     "  0: IntConstant 0 [5]\n"
-    "  1: IntConstant 4 [5, 8, 8]\n"
-    "  2: IntConstant 5 [5]\n"
+    "  1: IntConstant 4 [14, 8, 8]\n"
+    "  2: IntConstant 5 [14]\n"
     "  3: Goto\n"
     "BasicBlock 1, pred: 0, succ: 2\n"
     "  4: Goto\n"
-    "BasicBlock 2, pred: 1, 4, 5, succ: 6, 3\n"
-    "  5: Phi(0, 2, 1) [12, 6, 6]\n"
+    "BasicBlock 2, pred: 1, 8, succ: 6, 3\n"
+    "  5: Phi(0, 14) [12, 6, 6]\n"
     "  6: Equal(5, 5) [7]\n"
     "  7: If(6)\n"
     "BasicBlock 3, pred: 2, succ: 5, 4\n"
     "  8: Equal(1, 1) [9]\n"
     "  9: If(8)\n"
-    "BasicBlock 4, pred: 3, succ: 2\n"
+    "BasicBlock 4, pred: 3, succ: 8\n"
     "  10: Goto\n"
-    "BasicBlock 5, pred: 3, succ: 2\n"
+    "BasicBlock 5, pred: 3, succ: 8\n"
     "  11: Goto\n"
     "BasicBlock 6, pred: 2, succ: 7\n"
     "  12: Return(5)\n"
     "BasicBlock 7, pred: 6\n"
-    "  13: Exit\n";
+    "  13: Exit\n"
+    // Synthesized single back edge of loop.
+    "BasicBlock 8, pred: 5, 4, succ: 2\n"
+    "  14: Phi(1, 2) [5]\n"
+    "  15: Goto\n";
 
   const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
@@ -393,7 +408,7 @@
     "  3: Goto\n"
     "BasicBlock 1, pred: 0, succ: 2\n"
     "  4: Goto\n"
-    "BasicBlock 2, pred: 1, 5, succ: 6, 3\n"
+    "BasicBlock 2, pred: 1, 5, succ: 3, 8\n"
     "  5: Phi(0, 1) [12, 6, 6]\n"
     "  6: Equal(5, 5) [7]\n"
     "  7: If(6)\n"
@@ -404,11 +419,13 @@
     "  10: Goto\n"
     "BasicBlock 5, pred: 3, succ: 2\n"
     "  11: Goto\n"
-    "BasicBlock 6, pred: 2, 4, succ: 7\n"
-    "  12: Phi(5, 2) [13]\n"
+    "BasicBlock 6, pred: 4, 8, succ: 7\n"
+    "  12: Phi(2, 5) [13]\n"
     "  13: Return(12)\n"
     "BasicBlock 7, pred: 6\n"
-    "  14: Exit\n";
+    "  14: Exit\n"
+    "BasicBlock 8, pred: 2, succ: 6\n"
+    "  15: Goto\n";
 
   const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
diff --git a/compiler/trampolines/trampoline_compiler.cc b/compiler/trampolines/trampoline_compiler.cc
index fb909a8..d03b99f 100644
--- a/compiler/trampolines/trampoline_compiler.cc
+++ b/compiler/trampolines/trampoline_compiler.cc
@@ -62,18 +62,15 @@
 
   switch (abi) {
     case kInterpreterAbi:  // Thread* is first argument (X0) in interpreter ABI.
-      // FIXME IPx used by VIXL - this is unsafe.
       __ JumpTo(Arm64ManagedRegister::FromCoreRegister(X0), Offset(offset.Int32Value()),
           Arm64ManagedRegister::FromCoreRegister(IP1));
 
       break;
     case kJniAbi:  // Load via Thread* held in JNIEnv* in first argument (X0).
-
       __ LoadRawPtr(Arm64ManagedRegister::FromCoreRegister(IP1),
                       Arm64ManagedRegister::FromCoreRegister(X0),
                       Offset(JNIEnvExt::SelfOffset().Int32Value()));
 
-      // FIXME IPx used by VIXL - this is unsafe.
       __ JumpTo(Arm64ManagedRegister::FromCoreRegister(IP1), Offset(offset.Int32Value()),
                 Arm64ManagedRegister::FromCoreRegister(IP0));
 
diff --git a/compiler/utils/arm/assembler_arm.cc b/compiler/utils/arm/assembler_arm.cc
index 5c839dd..64685c1 100644
--- a/compiler/utils/arm/assembler_arm.cc
+++ b/compiler/utils/arm/assembler_arm.cc
@@ -1752,53 +1752,53 @@
 #endif
 }
 
-void ArmAssembler::CreateSirtEntry(ManagedRegister mout_reg,
-                                   FrameOffset sirt_offset,
+void ArmAssembler::CreateHandleScopeEntry(ManagedRegister mout_reg,
+                                   FrameOffset handle_scope_offset,
                                    ManagedRegister min_reg, bool null_allowed) {
   ArmManagedRegister out_reg = mout_reg.AsArm();
   ArmManagedRegister in_reg = min_reg.AsArm();
   CHECK(in_reg.IsNoRegister() || in_reg.IsCoreRegister()) << in_reg;
   CHECK(out_reg.IsCoreRegister()) << out_reg;
   if (null_allowed) {
-    // Null values get a SIRT entry value of 0.  Otherwise, the SIRT entry is
-    // the address in the SIRT holding the reference.
+    // Null values get a handle scope entry value of 0.  Otherwise, the handle scope entry is
+    // the address in the handle scope holding the reference.
     // e.g. out_reg = (handle == 0) ? 0 : (SP+handle_offset)
     if (in_reg.IsNoRegister()) {
       LoadFromOffset(kLoadWord, out_reg.AsCoreRegister(),
-                     SP, sirt_offset.Int32Value());
+                     SP, handle_scope_offset.Int32Value());
       in_reg = out_reg;
     }
     cmp(in_reg.AsCoreRegister(), ShifterOperand(0));
     if (!out_reg.Equals(in_reg)) {
       LoadImmediate(out_reg.AsCoreRegister(), 0, EQ);
     }
-    AddConstant(out_reg.AsCoreRegister(), SP, sirt_offset.Int32Value(), NE);
+    AddConstant(out_reg.AsCoreRegister(), SP, handle_scope_offset.Int32Value(), NE);
   } else {
-    AddConstant(out_reg.AsCoreRegister(), SP, sirt_offset.Int32Value(), AL);
+    AddConstant(out_reg.AsCoreRegister(), SP, handle_scope_offset.Int32Value(), AL);
   }
 }
 
-void ArmAssembler::CreateSirtEntry(FrameOffset out_off,
-                                   FrameOffset sirt_offset,
+void ArmAssembler::CreateHandleScopeEntry(FrameOffset out_off,
+                                   FrameOffset handle_scope_offset,
                                    ManagedRegister mscratch,
                                    bool null_allowed) {
   ArmManagedRegister scratch = mscratch.AsArm();
   CHECK(scratch.IsCoreRegister()) << scratch;
   if (null_allowed) {
     LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP,
-                   sirt_offset.Int32Value());
-    // Null values get a SIRT entry value of 0.  Otherwise, the sirt entry is
-    // the address in the SIRT holding the reference.
-    // e.g. scratch = (scratch == 0) ? 0 : (SP+sirt_offset)
+                   handle_scope_offset.Int32Value());
+    // Null values get a handle scope entry value of 0.  Otherwise, the handle scope entry is
+    // the address in the handle scope holding the reference.
+    // e.g. scratch = (scratch == 0) ? 0 : (SP+handle_scope_offset)
     cmp(scratch.AsCoreRegister(), ShifterOperand(0));
-    AddConstant(scratch.AsCoreRegister(), SP, sirt_offset.Int32Value(), NE);
+    AddConstant(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value(), NE);
   } else {
-    AddConstant(scratch.AsCoreRegister(), SP, sirt_offset.Int32Value(), AL);
+    AddConstant(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value(), AL);
   }
   StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, out_off.Int32Value());
 }
 
-void ArmAssembler::LoadReferenceFromSirt(ManagedRegister mout_reg,
+void ArmAssembler::LoadReferenceFromHandleScope(ManagedRegister mout_reg,
                                          ManagedRegister min_reg) {
   ArmManagedRegister out_reg = mout_reg.AsArm();
   ArmManagedRegister in_reg = min_reg.AsArm();
diff --git a/compiler/utils/arm/assembler_arm.h b/compiler/utils/arm/assembler_arm.h
index f5be04a..396e603 100644
--- a/compiler/utils/arm/assembler_arm.h
+++ b/compiler/utils/arm/assembler_arm.h
@@ -521,20 +521,20 @@
   void GetCurrentThread(ManagedRegister tr) OVERRIDE;
   void GetCurrentThread(FrameOffset dest_offset, ManagedRegister scratch) OVERRIDE;
 
-  // Set up out_reg to hold a Object** into the SIRT, or to be NULL if the
+  // Set up out_reg to hold a Object** into the handle scope, or to be NULL if the
   // value is null and null_allowed. in_reg holds a possibly stale reference
-  // that can be used to avoid loading the SIRT entry to see if the value is
+  // that can be used to avoid loading the handle scope entry to see if the value is
   // NULL.
-  void CreateSirtEntry(ManagedRegister out_reg, FrameOffset sirt_offset, ManagedRegister in_reg,
+  void CreateHandleScopeEntry(ManagedRegister out_reg, FrameOffset handlescope_offset, ManagedRegister in_reg,
                        bool null_allowed) OVERRIDE;
 
-  // Set up out_off to hold a Object** into the SIRT, or to be NULL if the
+  // Set up out_off to hold a Object** into the handle scope, or to be NULL if the
   // value is null and null_allowed.
-  void CreateSirtEntry(FrameOffset out_off, FrameOffset sirt_offset, ManagedRegister scratch,
+  void CreateHandleScopeEntry(FrameOffset out_off, FrameOffset handlescope_offset, ManagedRegister scratch,
                        bool null_allowed) OVERRIDE;
 
-  // src holds a SIRT entry (Object**) load this into dst
-  void LoadReferenceFromSirt(ManagedRegister dst, ManagedRegister src) OVERRIDE;
+  // src holds a handle scope entry (Object**) load this into dst
+  void LoadReferenceFromHandleScope(ManagedRegister dst, ManagedRegister src) OVERRIDE;
 
   // Heap::VerifyObject on src. In some cases (such as a reference to this) we
   // know that src may not be null.
diff --git a/compiler/utils/arm64/assembler_arm64.cc b/compiler/utils/arm64/assembler_arm64.cc
index b4bb979..27188b2 100644
--- a/compiler/utils/arm64/assembler_arm64.cc
+++ b/compiler/utils/arm64/assembler_arm64.cc
@@ -50,11 +50,11 @@
 }
 
 void Arm64Assembler::GetCurrentThread(ManagedRegister tr) {
-  ___ Mov(reg_x(tr.AsArm64().AsCoreRegister()), reg_x(TR1));
+  ___ Mov(reg_x(tr.AsArm64().AsCoreRegister()), reg_x(ETR));
 }
 
 void Arm64Assembler::GetCurrentThread(FrameOffset offset, ManagedRegister /* scratch */) {
-  StoreToOffset(TR1, SP, offset.Int32Value());
+  StoreToOffset(ETR, SP, offset.Int32Value());
 }
 
 // See Arm64 PCS Section 5.2.2.1.
@@ -79,11 +79,13 @@
     // VIXL macro-assembler handles all variants.
     ___ Add(reg_x(rd), reg_x(rn), value);
   } else {
-    // ip1 = rd + value
-    // rd = cond ? ip1 : rn
-    CHECK_NE(rn, IP1);
-    ___ Add(reg_x(IP1), reg_x(rn), value);
-    ___ Csel(reg_x(rd), reg_x(IP1), reg_x(rd), COND_OP(cond));
+    // temp = rd + value
+    // rd = cond ? temp : rn
+    vixl::UseScratchRegisterScope temps(vixl_masm_);
+    temps.Exclude(reg_x(rd), reg_x(rn));
+    vixl::Register temp = temps.AcquireX();
+    ___ Add(temp, reg_x(rn), value);
+    ___ Csel(reg_x(rd), temp, reg_x(rd), COND_OP(cond));
   }
 }
 
@@ -162,7 +164,7 @@
   Arm64ManagedRegister scratch = m_scratch.AsArm64();
   CHECK(scratch.IsCoreRegister()) << scratch;
   LoadImmediate(scratch.AsCoreRegister(), imm);
-  StoreToOffset(scratch.AsCoreRegister(), TR1, offs.Int32Value());
+  StoreToOffset(scratch.AsCoreRegister(), ETR, offs.Int32Value());
 }
 
 void Arm64Assembler::StoreStackOffsetToThread64(ThreadOffset<8> tr_offs,
@@ -171,13 +173,14 @@
   Arm64ManagedRegister scratch = m_scratch.AsArm64();
   CHECK(scratch.IsCoreRegister()) << scratch;
   AddConstant(scratch.AsCoreRegister(), SP, fr_offs.Int32Value());
-  StoreToOffset(scratch.AsCoreRegister(), TR1, tr_offs.Int32Value());
+  StoreToOffset(scratch.AsCoreRegister(), ETR, tr_offs.Int32Value());
 }
 
 void Arm64Assembler::StoreStackPointerToThread64(ThreadOffset<8> tr_offs) {
-  // Arm64 does not support: "str sp, [dest]" therefore we use IP1 as a temp reg.
-  ___ Mov(reg_x(IP1), reg_x(SP));
-  StoreToOffset(IP1, TR1, tr_offs.Int32Value());
+  vixl::UseScratchRegisterScope temps(vixl_masm_);
+  vixl::Register temp = temps.AcquireX();
+  ___ Mov(temp, reg_x(SP));
+  ___ Str(temp, MEM_OP(reg_x(ETR), tr_offs.Int32Value()));
 }
 
 void Arm64Assembler::StoreSpanning(FrameOffset dest_off, ManagedRegister m_source,
@@ -195,12 +198,14 @@
   if ((cond == AL) || (cond == NV)) {
     ___ Mov(reg_x(dest), value);
   } else {
-    // ip1 = value
-    // rd = cond ? ip1 : rd
+    // temp = value
+    // rd = cond ? temp : rd
     if (value != 0) {
-      CHECK_NE(dest, IP1);
-      ___ Mov(reg_x(IP1), value);
-      ___ Csel(reg_x(dest), reg_x(IP1), reg_x(dest), COND_OP(cond));
+      vixl::UseScratchRegisterScope temps(vixl_masm_);
+      temps.Exclude(reg_x(dest));
+      vixl::Register temp = temps.AcquireX();
+      ___ Mov(temp, value);
+      ___ Csel(reg_x(dest), temp, reg_x(dest), COND_OP(cond));
     } else {
       ___ Csel(reg_x(dest), reg_x(XZR), reg_x(dest), COND_OP(cond));
     }
@@ -276,7 +281,7 @@
 }
 
 void Arm64Assembler::LoadFromThread64(ManagedRegister m_dst, ThreadOffset<8> src, size_t size) {
-  return Load(m_dst.AsArm64(), TR1, src.Int32Value(), size);
+  return Load(m_dst.AsArm64(), ETR, src.Int32Value(), size);
 }
 
 void Arm64Assembler::LoadRef(ManagedRegister m_dst, FrameOffset offs) {
@@ -298,13 +303,16 @@
   Arm64ManagedRegister dst = m_dst.AsArm64();
   Arm64ManagedRegister base = m_base.AsArm64();
   CHECK(dst.IsCoreRegister() && base.IsCoreRegister());
-  LoadFromOffset(dst.AsCoreRegister(), base.AsCoreRegister(), offs.Int32Value());
+  // Remove dst and base form the temp list - higher level API uses IP1, IP0.
+  vixl::UseScratchRegisterScope temps(vixl_masm_);
+  temps.Exclude(reg_x(dst.AsCoreRegister()), reg_x(base.AsCoreRegister()));
+  ___ Ldr(reg_x(dst.AsCoreRegister()), MEM_OP(reg_x(base.AsCoreRegister()), offs.Int32Value()));
 }
 
 void Arm64Assembler::LoadRawPtrFromThread64(ManagedRegister m_dst, ThreadOffset<8> offs) {
   Arm64ManagedRegister dst = m_dst.AsArm64();
   CHECK(dst.IsCoreRegister()) << dst;
-  LoadFromOffset(dst.AsCoreRegister(), TR1, offs.Int32Value());
+  LoadFromOffset(dst.AsCoreRegister(), ETR, offs.Int32Value());
 }
 
 // Copying routines.
@@ -342,7 +350,7 @@
                                           ManagedRegister m_scratch) {
   Arm64ManagedRegister scratch = m_scratch.AsArm64();
   CHECK(scratch.IsCoreRegister()) << scratch;
-  LoadFromOffset(scratch.AsCoreRegister(), TR1, tr_offs.Int32Value());
+  LoadFromOffset(scratch.AsCoreRegister(), ETR, tr_offs.Int32Value());
   StoreToOffset(scratch.AsCoreRegister(), SP, fr_offs.Int32Value());
 }
 
@@ -352,7 +360,7 @@
   Arm64ManagedRegister scratch = m_scratch.AsArm64();
   CHECK(scratch.IsCoreRegister()) << scratch;
   LoadFromOffset(scratch.AsCoreRegister(), SP, fr_offs.Int32Value());
-  StoreToOffset(scratch.AsCoreRegister(), TR1, tr_offs.Int32Value());
+  StoreToOffset(scratch.AsCoreRegister(), ETR, tr_offs.Int32Value());
 }
 
 void Arm64Assembler::CopyRef(FrameOffset dest, FrameOffset src,
@@ -511,7 +519,10 @@
   Arm64ManagedRegister scratch = m_scratch.AsArm64();
   CHECK(base.IsCoreRegister()) << base;
   CHECK(scratch.IsCoreRegister()) << scratch;
-  LoadFromOffset(scratch.AsCoreRegister(), base.AsCoreRegister(), offs.Int32Value());
+  // Remove base and scratch form the temp list - higher level API uses IP1, IP0.
+  vixl::UseScratchRegisterScope temps(vixl_masm_);
+  temps.Exclude(reg_x(base.AsCoreRegister()), reg_x(scratch.AsCoreRegister()));
+  ___ Ldr(reg_x(scratch.AsCoreRegister()), MEM_OP(reg_x(base.AsCoreRegister()), offs.Int32Value()));
   ___ Br(reg_x(scratch.AsCoreRegister()));
 }
 
@@ -528,52 +539,52 @@
   UNIMPLEMENTED(FATAL) << "Unimplemented Call() variant";
 }
 
-void Arm64Assembler::CreateSirtEntry(ManagedRegister m_out_reg, FrameOffset sirt_offs,
+void Arm64Assembler::CreateHandleScopeEntry(ManagedRegister m_out_reg, FrameOffset handle_scope_offs,
                                      ManagedRegister m_in_reg, bool null_allowed) {
   Arm64ManagedRegister out_reg = m_out_reg.AsArm64();
   Arm64ManagedRegister in_reg = m_in_reg.AsArm64();
-  // For now we only hold stale sirt entries in x registers.
+  // For now we only hold stale handle scope entries in x registers.
   CHECK(in_reg.IsNoRegister() || in_reg.IsCoreRegister()) << in_reg;
   CHECK(out_reg.IsCoreRegister()) << out_reg;
   if (null_allowed) {
-    // Null values get a SIRT entry value of 0.  Otherwise, the SIRT entry is
-    // the address in the SIRT holding the reference.
+    // Null values get a handle scope entry value of 0.  Otherwise, the handle scope entry is
+    // the address in the handle scope holding the reference.
     // e.g. out_reg = (handle == 0) ? 0 : (SP+handle_offset)
     if (in_reg.IsNoRegister()) {
       LoadWFromOffset(kLoadWord, out_reg.AsOverlappingCoreRegisterLow(), SP,
-                      sirt_offs.Int32Value());
+                      handle_scope_offs.Int32Value());
       in_reg = out_reg;
     }
     ___ Cmp(reg_w(in_reg.AsOverlappingCoreRegisterLow()), 0);
     if (!out_reg.Equals(in_reg)) {
       LoadImmediate(out_reg.AsCoreRegister(), 0, EQ);
     }
-    AddConstant(out_reg.AsCoreRegister(), SP, sirt_offs.Int32Value(), NE);
+    AddConstant(out_reg.AsCoreRegister(), SP, handle_scope_offs.Int32Value(), NE);
   } else {
-    AddConstant(out_reg.AsCoreRegister(), SP, sirt_offs.Int32Value(), AL);
+    AddConstant(out_reg.AsCoreRegister(), SP, handle_scope_offs.Int32Value(), AL);
   }
 }
 
-void Arm64Assembler::CreateSirtEntry(FrameOffset out_off, FrameOffset sirt_offset,
+void Arm64Assembler::CreateHandleScopeEntry(FrameOffset out_off, FrameOffset handle_scope_offset,
                                      ManagedRegister m_scratch, bool null_allowed) {
   Arm64ManagedRegister scratch = m_scratch.AsArm64();
   CHECK(scratch.IsCoreRegister()) << scratch;
   if (null_allowed) {
     LoadWFromOffset(kLoadWord, scratch.AsOverlappingCoreRegisterLow(), SP,
-                    sirt_offset.Int32Value());
-    // Null values get a SIRT entry value of 0.  Otherwise, the sirt entry is
-    // the address in the SIRT holding the reference.
-    // e.g. scratch = (scratch == 0) ? 0 : (SP+sirt_offset)
+                    handle_scope_offset.Int32Value());
+    // Null values get a handle scope entry value of 0.  Otherwise, the handle scope entry is
+    // the address in the handle scope holding the reference.
+    // e.g. scratch = (scratch == 0) ? 0 : (SP+handle_scope_offset)
     ___ Cmp(reg_w(scratch.AsOverlappingCoreRegisterLow()), 0);
     // Move this logic in add constants with flags.
-    AddConstant(scratch.AsCoreRegister(), SP, sirt_offset.Int32Value(), NE);
+    AddConstant(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value(), NE);
   } else {
-    AddConstant(scratch.AsCoreRegister(), SP, sirt_offset.Int32Value(), AL);
+    AddConstant(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value(), AL);
   }
   StoreToOffset(scratch.AsCoreRegister(), SP, out_off.Int32Value());
 }
 
-void Arm64Assembler::LoadReferenceFromSirt(ManagedRegister m_out_reg,
+void Arm64Assembler::LoadReferenceFromHandleScope(ManagedRegister m_out_reg,
                                            ManagedRegister m_in_reg) {
   Arm64ManagedRegister out_reg = m_out_reg.AsArm64();
   Arm64ManagedRegister in_reg = m_in_reg.AsArm64();
@@ -595,13 +606,17 @@
   Arm64ManagedRegister scratch = m_scratch.AsArm64();
   Arm64Exception *current_exception = new Arm64Exception(scratch, stack_adjust);
   exception_blocks_.push_back(current_exception);
-  LoadFromOffset(scratch.AsCoreRegister(), TR1, Thread::ExceptionOffset<8>().Int32Value());
+  LoadFromOffset(scratch.AsCoreRegister(), ETR, Thread::ExceptionOffset<8>().Int32Value());
   ___ Cmp(reg_x(scratch.AsCoreRegister()), 0);
   ___ B(current_exception->Entry(), COND_OP(NE));
 }
 
 void Arm64Assembler::EmitExceptionPoll(Arm64Exception *exception) {
-    // Bind exception poll entry.
+  vixl::UseScratchRegisterScope temps(vixl_masm_);
+  temps.Exclude(reg_x(exception->scratch_.AsCoreRegister()));
+  vixl::Register temp = temps.AcquireX();
+
+  // Bind exception poll entry.
   ___ Bind(exception->Entry());
   if (exception->stack_adjust_ != 0) {  // Fix up the frame.
     DecreaseFrameSize(exception->stack_adjust_);
@@ -609,12 +624,14 @@
   // Pass exception object as argument.
   // Don't care about preserving X0 as this won't return.
   ___ Mov(reg_x(X0), reg_x(exception->scratch_.AsCoreRegister()));
-  LoadFromOffset(IP1, TR1, QUICK_ENTRYPOINT_OFFSET(8, pDeliverException).Int32Value());
+  ___ Ldr(temp, MEM_OP(reg_x(ETR), QUICK_ENTRYPOINT_OFFSET(8, pDeliverException).Int32Value()));
 
-  // FIXME: Temporary fix for TR (XSELF).
-  ___ Mov(reg_x(TR), reg_x(TR1));
+  // Move ETR(Callee saved) back to TR(Caller saved) reg. We use ETR on calls
+  // to external functions that might trash TR. We do not need the original
+  // X19 saved in BuildFrame().
+  ___ Mov(reg_x(TR), reg_x(ETR));
 
-  ___ Blr(reg_x(IP1));
+  ___ Blr(temp);
   // Call should never return.
   ___ Brk();
 }
@@ -634,8 +651,10 @@
   CHECK_EQ(callee_save_regs.size(), kCalleeSavedRegsSize);
   ___ PushCalleeSavedRegisters();
 
-  // FIXME: Temporary fix for TR (XSELF).
-  ___ Mov(reg_x(TR1), reg_x(TR));
+  // Move TR(Caller saved) to ETR(Callee saved). The original X19 has been
+  // saved by PushCalleeSavedRegisters(). This way we make sure that TR is not
+  // trashed by native code.
+  ___ Mov(reg_x(ETR), reg_x(TR));
 
   // Increate frame to required size - must be at least space to push Method*.
   CHECK_GT(frame_size, kCalleeSavedRegsSize * kFramePointerSize);
@@ -681,8 +700,10 @@
   size_t adjust = frame_size - (kCalleeSavedRegsSize * kFramePointerSize);
   DecreaseFrameSize(adjust);
 
-  // FIXME: Temporary fix for TR (XSELF).
-  ___ Mov(reg_x(TR), reg_x(TR1));
+  // We move ETR (Callee Saved) back to TR (Caller Saved) which might have
+  // been trashed in the native call. The original X19 (ETR) is restored as
+  // part of PopCalleeSavedRegisters().
+  ___ Mov(reg_x(TR), reg_x(ETR));
 
   // Pop callee saved and return to LR.
   ___ PopCalleeSavedRegisters();
diff --git a/compiler/utils/arm64/assembler_arm64.h b/compiler/utils/arm64/assembler_arm64.h
index 97fb93a..c866b29 100644
--- a/compiler/utils/arm64/assembler_arm64.h
+++ b/compiler/utils/arm64/assembler_arm64.h
@@ -85,6 +85,7 @@
   vixl_masm_(new vixl::MacroAssembler(vixl_buf_, kBufferSizeArm64)) {}
 
   virtual ~Arm64Assembler() {
+    delete vixl_masm_;
     delete[] vixl_buf_;
   }
 
@@ -160,20 +161,20 @@
   void GetCurrentThread(ManagedRegister tr) OVERRIDE;
   void GetCurrentThread(FrameOffset dest_offset, ManagedRegister scratch) OVERRIDE;
 
-  // Set up out_reg to hold a Object** into the SIRT, or to be NULL if the
+  // Set up out_reg to hold a Object** into the handle scope, or to be NULL if the
   // value is null and null_allowed. in_reg holds a possibly stale reference
-  // that can be used to avoid loading the SIRT entry to see if the value is
+  // that can be used to avoid loading the handle scope entry to see if the value is
   // NULL.
-  void CreateSirtEntry(ManagedRegister out_reg, FrameOffset sirt_offset,
+  void CreateHandleScopeEntry(ManagedRegister out_reg, FrameOffset handlescope_offset,
                        ManagedRegister in_reg, bool null_allowed) OVERRIDE;
 
-  // Set up out_off to hold a Object** into the SIRT, or to be NULL if the
+  // Set up out_off to hold a Object** into the handle scope, or to be NULL if the
   // value is null and null_allowed.
-  void CreateSirtEntry(FrameOffset out_off, FrameOffset sirt_offset,
+  void CreateHandleScopeEntry(FrameOffset out_off, FrameOffset handlescope_offset,
                        ManagedRegister scratch, bool null_allowed) OVERRIDE;
 
-  // src holds a SIRT entry (Object**) load this into dst.
-  void LoadReferenceFromSirt(ManagedRegister dst, ManagedRegister src) OVERRIDE;
+  // src holds a handle scope entry (Object**) load this into dst.
+  void LoadReferenceFromHandleScope(ManagedRegister dst, ManagedRegister src) OVERRIDE;
 
   // Heap::VerifyObject on src. In some cases (such as a reference to this) we
   // know that src may not be null.
@@ -237,8 +238,8 @@
   // Vixl buffer.
   byte* vixl_buf_;
 
-  // Unique ptr - vixl assembler.
-  UniquePtr<vixl::MacroAssembler> vixl_masm_;
+  // Vixl assembler.
+  vixl::MacroAssembler* vixl_masm_;
 
   // List of exception blocks to generate at the end of the code cache.
   std::vector<Arm64Exception*> exception_blocks_;
diff --git a/compiler/utils/assembler.h b/compiler/utils/assembler.h
index 219c87f..19239e1 100644
--- a/compiler/utils/assembler.h
+++ b/compiler/utils/assembler.h
@@ -453,20 +453,20 @@
   virtual void GetCurrentThread(FrameOffset dest_offset,
                                 ManagedRegister scratch) = 0;
 
-  // Set up out_reg to hold a Object** into the SIRT, or to be NULL if the
+  // Set up out_reg to hold a Object** into the handle scope, or to be NULL if the
   // value is null and null_allowed. in_reg holds a possibly stale reference
-  // that can be used to avoid loading the SIRT entry to see if the value is
+  // that can be used to avoid loading the handle scope entry to see if the value is
   // NULL.
-  virtual void CreateSirtEntry(ManagedRegister out_reg, FrameOffset sirt_offset,
+  virtual void CreateHandleScopeEntry(ManagedRegister out_reg, FrameOffset handlescope_offset,
                                ManagedRegister in_reg, bool null_allowed) = 0;
 
-  // Set up out_off to hold a Object** into the SIRT, or to be NULL if the
+  // Set up out_off to hold a Object** into the handle scope, or to be NULL if the
   // value is null and null_allowed.
-  virtual void CreateSirtEntry(FrameOffset out_off, FrameOffset sirt_offset,
+  virtual void CreateHandleScopeEntry(FrameOffset out_off, FrameOffset handlescope_offset,
                                ManagedRegister scratch, bool null_allowed) = 0;
 
-  // src holds a SIRT entry (Object**) load this into dst
-  virtual void LoadReferenceFromSirt(ManagedRegister dst,
+  // src holds a handle scope entry (Object**) load this into dst
+  virtual void LoadReferenceFromHandleScope(ManagedRegister dst,
                                      ManagedRegister src) = 0;
 
   // Heap::VerifyObject on src. In some cases (such as a reference to this) we
diff --git a/compiler/utils/mips/assembler_mips.cc b/compiler/utils/mips/assembler_mips.cc
index 9001f8a..8001dcd 100644
--- a/compiler/utils/mips/assembler_mips.cc
+++ b/compiler/utils/mips/assembler_mips.cc
@@ -827,8 +827,8 @@
   UNIMPLEMENTED(FATAL) << "no mips implementation";
 }
 
-void MipsAssembler::CreateSirtEntry(ManagedRegister mout_reg,
-                                    FrameOffset sirt_offset,
+void MipsAssembler::CreateHandleScopeEntry(ManagedRegister mout_reg,
+                                    FrameOffset handle_scope_offset,
                                     ManagedRegister min_reg, bool null_allowed) {
   MipsManagedRegister out_reg = mout_reg.AsMips();
   MipsManagedRegister in_reg = min_reg.AsMips();
@@ -836,27 +836,27 @@
   CHECK(out_reg.IsCoreRegister()) << out_reg;
   if (null_allowed) {
     Label null_arg;
-    // Null values get a SIRT entry value of 0.  Otherwise, the SIRT entry is
-    // the address in the SIRT holding the reference.
+    // Null values get a handle scope entry value of 0.  Otherwise, the handle scope entry is
+    // the address in the handle scope holding the reference.
     // e.g. out_reg = (handle == 0) ? 0 : (SP+handle_offset)
     if (in_reg.IsNoRegister()) {
       LoadFromOffset(kLoadWord, out_reg.AsCoreRegister(),
-                     SP, sirt_offset.Int32Value());
+                     SP, handle_scope_offset.Int32Value());
       in_reg = out_reg;
     }
     if (!out_reg.Equals(in_reg)) {
       LoadImmediate(out_reg.AsCoreRegister(), 0);
     }
     EmitBranch(in_reg.AsCoreRegister(), ZERO, &null_arg, true);
-    AddConstant(out_reg.AsCoreRegister(), SP, sirt_offset.Int32Value());
+    AddConstant(out_reg.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
     Bind(&null_arg, false);
   } else {
-    AddConstant(out_reg.AsCoreRegister(), SP, sirt_offset.Int32Value());
+    AddConstant(out_reg.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
   }
 }
 
-void MipsAssembler::CreateSirtEntry(FrameOffset out_off,
-                                    FrameOffset sirt_offset,
+void MipsAssembler::CreateHandleScopeEntry(FrameOffset out_off,
+                                    FrameOffset handle_scope_offset,
                                     ManagedRegister mscratch,
                                     bool null_allowed) {
   MipsManagedRegister scratch = mscratch.AsMips();
@@ -864,21 +864,21 @@
   if (null_allowed) {
     Label null_arg;
     LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP,
-                   sirt_offset.Int32Value());
-    // Null values get a SIRT entry value of 0.  Otherwise, the sirt entry is
-    // the address in the SIRT holding the reference.
-    // e.g. scratch = (scratch == 0) ? 0 : (SP+sirt_offset)
+                   handle_scope_offset.Int32Value());
+    // Null values get a handle scope entry value of 0.  Otherwise, the handle scope entry is
+    // the address in the handle scope holding the reference.
+    // e.g. scratch = (scratch == 0) ? 0 : (SP+handle_scope_offset)
     EmitBranch(scratch.AsCoreRegister(), ZERO, &null_arg, true);
-    AddConstant(scratch.AsCoreRegister(), SP, sirt_offset.Int32Value());
+    AddConstant(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
     Bind(&null_arg, false);
   } else {
-    AddConstant(scratch.AsCoreRegister(), SP, sirt_offset.Int32Value());
+    AddConstant(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value());
   }
   StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, out_off.Int32Value());
 }
 
-// Given a SIRT entry, load the associated reference.
-void MipsAssembler::LoadReferenceFromSirt(ManagedRegister mout_reg,
+// Given a handle scope entry, load the associated reference.
+void MipsAssembler::LoadReferenceFromHandleScope(ManagedRegister mout_reg,
                                           ManagedRegister min_reg) {
   MipsManagedRegister out_reg = mout_reg.AsMips();
   MipsManagedRegister in_reg = min_reg.AsMips();
diff --git a/compiler/utils/mips/assembler_mips.h b/compiler/utils/mips/assembler_mips.h
index 75ee8b9..216cb41 100644
--- a/compiler/utils/mips/assembler_mips.h
+++ b/compiler/utils/mips/assembler_mips.h
@@ -238,20 +238,20 @@
   void GetCurrentThread(ManagedRegister tr) OVERRIDE;
   void GetCurrentThread(FrameOffset dest_offset, ManagedRegister mscratch) OVERRIDE;
 
-  // Set up out_reg to hold a Object** into the SIRT, or to be NULL if the
+  // Set up out_reg to hold a Object** into the handle scope, or to be NULL if the
   // value is null and null_allowed. in_reg holds a possibly stale reference
-  // that can be used to avoid loading the SIRT entry to see if the value is
+  // that can be used to avoid loading the handle scope entry to see if the value is
   // NULL.
-  void CreateSirtEntry(ManagedRegister out_reg, FrameOffset sirt_offset, ManagedRegister in_reg,
+  void CreateHandleScopeEntry(ManagedRegister out_reg, FrameOffset handlescope_offset, ManagedRegister in_reg,
                        bool null_allowed) OVERRIDE;
 
-  // Set up out_off to hold a Object** into the SIRT, or to be NULL if the
+  // Set up out_off to hold a Object** into the handle scope, or to be NULL if the
   // value is null and null_allowed.
-  void CreateSirtEntry(FrameOffset out_off, FrameOffset sirt_offset, ManagedRegister mscratch,
+  void CreateHandleScopeEntry(FrameOffset out_off, FrameOffset handlescope_offset, ManagedRegister mscratch,
                        bool null_allowed) OVERRIDE;
 
-  // src holds a SIRT entry (Object**) load this into dst
-  void LoadReferenceFromSirt(ManagedRegister dst, ManagedRegister src) OVERRIDE;
+  // src holds a handle scope entry (Object**) load this into dst
+  void LoadReferenceFromHandleScope(ManagedRegister dst, ManagedRegister src) OVERRIDE;
 
   // Heap::VerifyObject on src. In some cases (such as a reference to this) we
   // know that src may not be null.
diff --git a/compiler/utils/x86/assembler_x86.cc b/compiler/utils/x86/assembler_x86.cc
index 6a3efc5..0791c63 100644
--- a/compiler/utils/x86/assembler_x86.cc
+++ b/compiler/utils/x86/assembler_x86.cc
@@ -1727,8 +1727,8 @@
 #endif
 }
 
-void X86Assembler::CreateSirtEntry(ManagedRegister mout_reg,
-                                   FrameOffset sirt_offset,
+void X86Assembler::CreateHandleScopeEntry(ManagedRegister mout_reg,
+                                   FrameOffset handle_scope_offset,
                                    ManagedRegister min_reg, bool null_allowed) {
   X86ManagedRegister out_reg = mout_reg.AsX86();
   X86ManagedRegister in_reg = min_reg.AsX86();
@@ -1742,34 +1742,34 @@
     }
     testl(in_reg.AsCpuRegister(), in_reg.AsCpuRegister());
     j(kZero, &null_arg);
-    leal(out_reg.AsCpuRegister(), Address(ESP, sirt_offset));
+    leal(out_reg.AsCpuRegister(), Address(ESP, handle_scope_offset));
     Bind(&null_arg);
   } else {
-    leal(out_reg.AsCpuRegister(), Address(ESP, sirt_offset));
+    leal(out_reg.AsCpuRegister(), Address(ESP, handle_scope_offset));
   }
 }
 
-void X86Assembler::CreateSirtEntry(FrameOffset out_off,
-                                   FrameOffset sirt_offset,
+void X86Assembler::CreateHandleScopeEntry(FrameOffset out_off,
+                                   FrameOffset handle_scope_offset,
                                    ManagedRegister mscratch,
                                    bool null_allowed) {
   X86ManagedRegister scratch = mscratch.AsX86();
   CHECK(scratch.IsCpuRegister());
   if (null_allowed) {
     Label null_arg;
-    movl(scratch.AsCpuRegister(), Address(ESP, sirt_offset));
+    movl(scratch.AsCpuRegister(), Address(ESP, handle_scope_offset));
     testl(scratch.AsCpuRegister(), scratch.AsCpuRegister());
     j(kZero, &null_arg);
-    leal(scratch.AsCpuRegister(), Address(ESP, sirt_offset));
+    leal(scratch.AsCpuRegister(), Address(ESP, handle_scope_offset));
     Bind(&null_arg);
   } else {
-    leal(scratch.AsCpuRegister(), Address(ESP, sirt_offset));
+    leal(scratch.AsCpuRegister(), Address(ESP, handle_scope_offset));
   }
   Store(out_off, scratch, 4);
 }
 
-// Given a SIRT entry, load the associated reference.
-void X86Assembler::LoadReferenceFromSirt(ManagedRegister mout_reg,
+// Given a handle scope entry, load the associated reference.
+void X86Assembler::LoadReferenceFromHandleScope(ManagedRegister mout_reg,
                                          ManagedRegister min_reg) {
   X86ManagedRegister out_reg = mout_reg.AsX86();
   X86ManagedRegister in_reg = min_reg.AsX86();
diff --git a/compiler/utils/x86/assembler_x86.h b/compiler/utils/x86/assembler_x86.h
index 057c80a..2fc6049 100644
--- a/compiler/utils/x86/assembler_x86.h
+++ b/compiler/utils/x86/assembler_x86.h
@@ -541,20 +541,20 @@
   void GetCurrentThread(ManagedRegister tr) OVERRIDE;
   void GetCurrentThread(FrameOffset dest_offset, ManagedRegister scratch) OVERRIDE;
 
-  // Set up out_reg to hold a Object** into the SIRT, or to be NULL if the
+  // Set up out_reg to hold a Object** into the handle scope, or to be NULL if the
   // value is null and null_allowed. in_reg holds a possibly stale reference
-  // that can be used to avoid loading the SIRT entry to see if the value is
+  // that can be used to avoid loading the handle scope entry to see if the value is
   // NULL.
-  void CreateSirtEntry(ManagedRegister out_reg, FrameOffset sirt_offset, ManagedRegister in_reg,
+  void CreateHandleScopeEntry(ManagedRegister out_reg, FrameOffset handlescope_offset, ManagedRegister in_reg,
                        bool null_allowed) OVERRIDE;
 
-  // Set up out_off to hold a Object** into the SIRT, or to be NULL if the
+  // Set up out_off to hold a Object** into the handle scope, or to be NULL if the
   // value is null and null_allowed.
-  void CreateSirtEntry(FrameOffset out_off, FrameOffset sirt_offset, ManagedRegister scratch,
+  void CreateHandleScopeEntry(FrameOffset out_off, FrameOffset handlescope_offset, ManagedRegister scratch,
                        bool null_allowed) OVERRIDE;
 
-  // src holds a SIRT entry (Object**) load this into dst
-  void LoadReferenceFromSirt(ManagedRegister dst, ManagedRegister src) OVERRIDE;
+  // src holds a handle scope entry (Object**) load this into dst
+  void LoadReferenceFromHandleScope(ManagedRegister dst, ManagedRegister src) OVERRIDE;
 
   // Heap::VerifyObject on src. In some cases (such as a reference to this) we
   // know that src may not be null.
diff --git a/compiler/utils/x86_64/assembler_x86_64.cc b/compiler/utils/x86_64/assembler_x86_64.cc
index 8eaeae1..0ede875 100644
--- a/compiler/utils/x86_64/assembler_x86_64.cc
+++ b/compiler/utils/x86_64/assembler_x86_64.cc
@@ -1989,8 +1989,8 @@
 #endif
 }
 
-void X86_64Assembler::CreateSirtEntry(ManagedRegister mout_reg,
-                                   FrameOffset sirt_offset,
+void X86_64Assembler::CreateHandleScopeEntry(ManagedRegister mout_reg,
+                                   FrameOffset handle_scope_offset,
                                    ManagedRegister min_reg, bool null_allowed) {
   X86_64ManagedRegister out_reg = mout_reg.AsX86_64();
   X86_64ManagedRegister in_reg = min_reg.AsX86_64();
@@ -1998,7 +1998,7 @@
     // Use out_reg as indicator of NULL
     in_reg = out_reg;
     // TODO: movzwl
-    movl(in_reg.AsCpuRegister(), Address(CpuRegister(RSP), sirt_offset));
+    movl(in_reg.AsCpuRegister(), Address(CpuRegister(RSP), handle_scope_offset));
   }
   CHECK(in_reg.IsCpuRegister());
   CHECK(out_reg.IsCpuRegister());
@@ -2010,34 +2010,34 @@
     }
     testl(in_reg.AsCpuRegister(), in_reg.AsCpuRegister());
     j(kZero, &null_arg);
-    leaq(out_reg.AsCpuRegister(), Address(CpuRegister(RSP), sirt_offset));
+    leaq(out_reg.AsCpuRegister(), Address(CpuRegister(RSP), handle_scope_offset));
     Bind(&null_arg);
   } else {
-    leaq(out_reg.AsCpuRegister(), Address(CpuRegister(RSP), sirt_offset));
+    leaq(out_reg.AsCpuRegister(), Address(CpuRegister(RSP), handle_scope_offset));
   }
 }
 
-void X86_64Assembler::CreateSirtEntry(FrameOffset out_off,
-                                   FrameOffset sirt_offset,
+void X86_64Assembler::CreateHandleScopeEntry(FrameOffset out_off,
+                                   FrameOffset handle_scope_offset,
                                    ManagedRegister mscratch,
                                    bool null_allowed) {
   X86_64ManagedRegister scratch = mscratch.AsX86_64();
   CHECK(scratch.IsCpuRegister());
   if (null_allowed) {
     Label null_arg;
-    movl(scratch.AsCpuRegister(), Address(CpuRegister(RSP), sirt_offset));
+    movl(scratch.AsCpuRegister(), Address(CpuRegister(RSP), handle_scope_offset));
     testl(scratch.AsCpuRegister(), scratch.AsCpuRegister());
     j(kZero, &null_arg);
-    leaq(scratch.AsCpuRegister(), Address(CpuRegister(RSP), sirt_offset));
+    leaq(scratch.AsCpuRegister(), Address(CpuRegister(RSP), handle_scope_offset));
     Bind(&null_arg);
   } else {
-    leaq(scratch.AsCpuRegister(), Address(CpuRegister(RSP), sirt_offset));
+    leaq(scratch.AsCpuRegister(), Address(CpuRegister(RSP), handle_scope_offset));
   }
   Store(out_off, scratch, 8);
 }
 
-// Given a SIRT entry, load the associated reference.
-void X86_64Assembler::LoadReferenceFromSirt(ManagedRegister mout_reg,
+// Given a handle scope entry, load the associated reference.
+void X86_64Assembler::LoadReferenceFromHandleScope(ManagedRegister mout_reg,
                                          ManagedRegister min_reg) {
   X86_64ManagedRegister out_reg = mout_reg.AsX86_64();
   X86_64ManagedRegister in_reg = min_reg.AsX86_64();
diff --git a/compiler/utils/x86_64/assembler_x86_64.h b/compiler/utils/x86_64/assembler_x86_64.h
index 87fb359..548d379 100644
--- a/compiler/utils/x86_64/assembler_x86_64.h
+++ b/compiler/utils/x86_64/assembler_x86_64.h
@@ -566,20 +566,20 @@
   void GetCurrentThread(ManagedRegister tr) OVERRIDE;
   void GetCurrentThread(FrameOffset dest_offset, ManagedRegister scratch) OVERRIDE;
 
-  // Set up out_reg to hold a Object** into the SIRT, or to be NULL if the
+  // Set up out_reg to hold a Object** into the handle scope, or to be NULL if the
   // value is null and null_allowed. in_reg holds a possibly stale reference
-  // that can be used to avoid loading the SIRT entry to see if the value is
+  // that can be used to avoid loading the handle scope entry to see if the value is
   // NULL.
-  void CreateSirtEntry(ManagedRegister out_reg, FrameOffset sirt_offset, ManagedRegister in_reg,
+  void CreateHandleScopeEntry(ManagedRegister out_reg, FrameOffset handlescope_offset, ManagedRegister in_reg,
                        bool null_allowed) OVERRIDE;
 
-  // Set up out_off to hold a Object** into the SIRT, or to be NULL if the
+  // Set up out_off to hold a Object** into the handle scope, or to be NULL if the
   // value is null and null_allowed.
-  void CreateSirtEntry(FrameOffset out_off, FrameOffset sirt_offset, ManagedRegister scratch,
+  void CreateHandleScopeEntry(FrameOffset out_off, FrameOffset handlescope_offset, ManagedRegister scratch,
                        bool null_allowed) OVERRIDE;
 
-  // src holds a SIRT entry (Object**) load this into dst
-  virtual void LoadReferenceFromSirt(ManagedRegister dst,
+  // src holds a handle scope entry (Object**) load this into dst
+  virtual void LoadReferenceFromHandleScope(ManagedRegister dst,
                                      ManagedRegister src);
 
   // Heap::VerifyObject on src. In some cases (such as a reference to this) we
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 3529c27..ad796f8 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -236,7 +236,7 @@
                                            method_inliner_map,
                                            thread_count));
     if (!dex2oat->CreateRuntime(runtime_options, instruction_set)) {
-      *p_dex2oat = NULL;
+      *p_dex2oat = nullptr;
       return false;
     }
     *p_dex2oat = dex2oat.release();
@@ -258,9 +258,9 @@
   CompilerDriver::DescriptorSet* ReadImageClassesFromFile(const char* image_classes_filename) {
     UniquePtr<std::ifstream> image_classes_file(new std::ifstream(image_classes_filename,
                                                                   std::ifstream::in));
-    if (image_classes_file.get() == NULL) {
+    if (image_classes_file.get() == nullptr) {
       LOG(ERROR) << "Failed to open image classes file " << image_classes_filename;
-      return NULL;
+      return nullptr;
     }
     UniquePtr<CompilerDriver::DescriptorSet> result(ReadImageClasses(*image_classes_file.get()));
     image_classes_file->close();
@@ -286,21 +286,21 @@
                                                          const char* image_classes_filename,
                                                          std::string* error_msg) {
     UniquePtr<ZipArchive> zip_archive(ZipArchive::Open(zip_filename, error_msg));
-    if (zip_archive.get() == NULL) {
-      return NULL;
+    if (zip_archive.get() == nullptr) {
+      return nullptr;
     }
     UniquePtr<ZipEntry> zip_entry(zip_archive->Find(image_classes_filename, error_msg));
-    if (zip_entry.get() == NULL) {
+    if (zip_entry.get() == nullptr) {
       *error_msg = StringPrintf("Failed to find '%s' within '%s': %s", image_classes_filename,
                                 zip_filename, error_msg->c_str());
-      return NULL;
+      return nullptr;
     }
     UniquePtr<MemMap> image_classes_file(zip_entry->ExtractToMemMap(image_classes_filename,
                                                                     error_msg));
-    if (image_classes_file.get() == NULL) {
+    if (image_classes_file.get() == nullptr) {
       *error_msg = StringPrintf("Failed to extract '%s' from '%s': %s", image_classes_filename,
                                 zip_filename, error_msg->c_str());
-      return NULL;
+      return nullptr;
     }
     const std::string image_classes_string(reinterpret_cast<char*>(image_classes_file->Begin()),
                                            image_classes_file->Size());
@@ -321,8 +321,8 @@
                                       TimingLogger& timings,
                                       CumulativeLogger& compiler_phases_timings,
                                       std::string profile_file) {
-    // SirtRef and ClassLoader creation needs to come after Runtime::Create
-    jobject class_loader = NULL;
+    // Handle and ClassLoader creation needs to come after Runtime::Create
+    jobject class_loader = nullptr;
     Thread* self = Thread::Current();
     if (!boot_image_option.empty()) {
       ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
@@ -380,7 +380,7 @@
     TimingLogger::ScopedSplit split("Writing ELF", &timings);
     if (!driver->WriteElf(android_root, is_host, dex_files, &oat_writer, oat_file)) {
       LOG(ERROR) << "Failed to write ELF file " << oat_file->GetPath();
-      return NULL;
+      return nullptr;
     }
 
     return driver.release();
@@ -404,7 +404,7 @@
     }
 
     UniquePtr<File> oat_file(OS::OpenFileReadWrite(oat_filename.c_str()));
-    if (oat_file.get() == NULL) {
+    if (oat_file.get() == nullptr) {
       PLOG(ERROR) << "Failed to open ELF file: " << oat_filename;
       return false;
     }
@@ -444,10 +444,11 @@
       return false;
     }
     Runtime* runtime = Runtime::Current();
+    runtime->SetInstructionSet(instruction_set);
     for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
       Runtime::CalleeSaveType type = Runtime::CalleeSaveType(i);
       if (!runtime->HasCalleeSaveMethod(type)) {
-        runtime->SetCalleeSaveMethod(runtime->CreateCalleeSaveMethod(instruction_set, type), type);
+        runtime->SetCalleeSaveMethod(runtime->CreateCalleeSaveMethod(type), type);
       }
     }
     runtime->GetClassLinker()->FixupDexCaches(runtime->GetResolutionMethod());
@@ -469,7 +470,7 @@
       }
       std::string error_msg;
       const DexFile* dex_file = DexFile::Open(parsed[i].c_str(), parsed[i].c_str(), &error_msg);
-      if (dex_file == NULL) {
+      if (dex_file == nullptr) {
         LOG(WARNING) << "Failed to open dex file '" << parsed[i] << "': " << error_msg;
       } else {
         dex_files.push_back(dex_file);
@@ -527,7 +528,7 @@
       continue;
     }
     const DexFile* dex_file = DexFile::Open(dex_filename, dex_location, &error_msg);
-    if (dex_file == NULL) {
+    if (dex_file == nullptr) {
       LOG(WARNING) << "Failed to open .dex from file '" << dex_filename << "': " << error_msg;
       ++failure_count;
     } else {
@@ -564,8 +565,8 @@
     }
     shutting_down_ = false;
     const char* reason = "dex2oat watch dog thread startup";
-    CHECK_WATCH_DOG_PTHREAD_CALL(pthread_mutex_init, (&mutex_, NULL), reason);
-    CHECK_WATCH_DOG_PTHREAD_CALL(pthread_cond_init, (&cond_, NULL), reason);
+    CHECK_WATCH_DOG_PTHREAD_CALL(pthread_mutex_init, (&mutex_, nullptr), reason);
+    CHECK_WATCH_DOG_PTHREAD_CALL(pthread_cond_init, (&cond_, nullptr), reason);
     CHECK_WATCH_DOG_PTHREAD_CALL(pthread_attr_init, (&attr_), reason);
     CHECK_WATCH_DOG_PTHREAD_CALL(pthread_create, (&pthread_, &attr_, &CallBack, this), reason);
     CHECK_WATCH_DOG_PTHREAD_CALL(pthread_attr_destroy, (&attr_), reason);
@@ -580,7 +581,7 @@
     CHECK_WATCH_DOG_PTHREAD_CALL(pthread_cond_signal, (&cond_), reason);
     CHECK_WATCH_DOG_PTHREAD_CALL(pthread_mutex_unlock, (&mutex_), reason);
 
-    CHECK_WATCH_DOG_PTHREAD_CALL(pthread_join, (pthread_, NULL), reason);
+    CHECK_WATCH_DOG_PTHREAD_CALL(pthread_join, (pthread_, nullptr), reason);
 
     CHECK_WATCH_DOG_PTHREAD_CALL(pthread_cond_destroy, (&cond_), reason);
     CHECK_WATCH_DOG_PTHREAD_CALL(pthread_mutex_destroy, (&mutex_), reason);
@@ -591,7 +592,7 @@
     WatchDog* self = reinterpret_cast<WatchDog*>(arg);
     ::art::SetThreadName("dex2oat watch dog");
     self->Wait();
-    return NULL;
+    return nullptr;
   }
 
   static void Message(char severity, const std::string& message) {
@@ -727,8 +728,8 @@
   std::string oat_location;
   int oat_fd = -1;
   std::string bitcode_filename;
-  const char* image_classes_zip_filename = NULL;
-  const char* image_classes_filename = NULL;
+  const char* image_classes_zip_filename = nullptr;
+  const char* image_classes_filename = nullptr;
   std::string image_filename;
   std::string boot_image_filename;
   uintptr_t image_base = 0;
@@ -738,7 +739,7 @@
   Compiler::Kind compiler_kind = kUsePortableCompiler
       ? Compiler::kPortable
       : Compiler::kQuick;
-  const char* compiler_filter_string = NULL;
+  const char* compiler_filter_string = nullptr;
   int huge_method_threshold = CompilerOptions::kDefaultHugeMethodThreshold;
   int large_method_threshold = CompilerOptions::kDefaultLargeMethodThreshold;
   int small_method_threshold = CompilerOptions::kDefaultSmallMethodThreshold;
@@ -764,7 +765,7 @@
 
   for (int i = 0; i < argc; i++) {
     const StringPiece option(argv[i]);
-    bool log_options = false;
+    const bool log_options = false;
     if (log_options) {
       LOG(INFO) << "dex2oat: option[" << i << "]=" << argv[i];
     }
@@ -948,7 +949,7 @@
 
   if (android_root.empty()) {
     const char* android_root_env_var = getenv("ANDROID_ROOT");
-    if (android_root_env_var == NULL) {
+    if (android_root_env_var == nullptr) {
       Usage("--android-root unspecified and ANDROID_ROOT not set");
     }
     android_root += android_root_env_var;
@@ -965,15 +966,15 @@
     boot_image_option += boot_image_filename;
   }
 
-  if (image_classes_filename != NULL && !image) {
+  if (image_classes_filename != nullptr && !image) {
     Usage("--image-classes should only be used with --image");
   }
 
-  if (image_classes_filename != NULL && !boot_image_option.empty()) {
+  if (image_classes_filename != nullptr && !boot_image_option.empty()) {
     Usage("--image-classes should not be used with --boot-image");
   }
 
-  if (image_classes_zip_filename != NULL && image_classes_filename == NULL) {
+  if (image_classes_zip_filename != nullptr && image_classes_filename == nullptr) {
     Usage("--image-classes-zip should be used with --image-classes");
   }
 
@@ -1015,7 +1016,7 @@
     oat_unstripped += oat_filename;
   }
 
-  if (compiler_filter_string == NULL) {
+  if (compiler_filter_string == nullptr) {
     if (instruction_set == kX86_64 || instruction_set == kMips) {
       // TODO: implement/fix compilers for these architectures.
       compiler_filter_string = "interpret-only";
@@ -1074,7 +1075,7 @@
     oat_file.reset(new File(oat_fd, oat_location));
     oat_file->DisableAutoClose();
   }
-  if (oat_file.get() == NULL) {
+  if (oat_file.get() == nullptr) {
     PLOG(ERROR) << "Failed to create oat file: " << oat_location;
     return EXIT_FAILURE;
   }
@@ -1096,11 +1097,10 @@
     }
     runtime_options.push_back(std::make_pair("bootclasspath", &boot_class_path));
   } else {
-    runtime_options.push_back(std::make_pair(boot_image_option.c_str(),
-                                             reinterpret_cast<void*>(NULL)));
+    runtime_options.push_back(std::make_pair(boot_image_option.c_str(), nullptr));
   }
   for (size_t i = 0; i < runtime_args.size(); i++) {
-    runtime_options.push_back(std::make_pair(runtime_args[i], reinterpret_cast<void*>(NULL)));
+    runtime_options.push_back(std::make_pair(runtime_args[i], nullptr));
   }
 
   VerificationResults verification_results(&compiler_options);
@@ -1136,21 +1136,23 @@
   WellKnownClasses::Init(self->GetJniEnv());
 
   // If --image-classes was specified, calculate the full list of classes to include in the image
-  UniquePtr<CompilerDriver::DescriptorSet> image_classes(NULL);
-  if (image_classes_filename != NULL) {
+  UniquePtr<CompilerDriver::DescriptorSet> image_classes(nullptr);
+  if (image_classes_filename != nullptr) {
     std::string error_msg;
-    if (image_classes_zip_filename != NULL) {
+    if (image_classes_zip_filename != nullptr) {
       image_classes.reset(dex2oat->ReadImageClassesFromZip(image_classes_zip_filename,
                                                            image_classes_filename,
                                                            &error_msg));
     } else {
       image_classes.reset(dex2oat->ReadImageClassesFromFile(image_classes_filename));
     }
-    if (image_classes.get() == NULL) {
+    if (image_classes.get() == nullptr) {
       LOG(ERROR) << "Failed to create list of image classes from '" << image_classes_filename <<
           "': " << error_msg;
       return EXIT_FAILURE;
     }
+  } else if (image) {
+    image_classes.reset(new CompilerDriver::DescriptorSet);
   }
 
   std::vector<const DexFile*> dex_files;
@@ -1162,13 +1164,13 @@
       std::string error_msg;
       UniquePtr<ZipArchive> zip_archive(ZipArchive::OpenFromFd(zip_fd, zip_location.c_str(),
                                                                &error_msg));
-      if (zip_archive.get() == NULL) {
+      if (zip_archive.get() == nullptr) {
         LOG(ERROR) << "Failed to open zip from file descriptor for '" << zip_location << "': "
             << error_msg;
         return EXIT_FAILURE;
       }
       const DexFile* dex_file = DexFile::Open(*zip_archive.get(), zip_location, &error_msg);
-      if (dex_file == NULL) {
+      if (dex_file == nullptr) {
         LOG(ERROR) << "Failed to open dex from file descriptor for zip file '" << zip_location
             << "': " << error_msg;
         return EXIT_FAILURE;
@@ -1214,7 +1216,7 @@
     size_t num_methods = 0;
     for (size_t i = 0; i != dex_files.size(); ++i) {
       const DexFile* dex_file = dex_files[i];
-      CHECK(dex_file != NULL);
+      CHECK(dex_file != nullptr);
       num_methods += dex_file->NumMethodIds();
     }
     if (num_methods <= compiler_options.GetNumDexMethodsThreshold()) {
@@ -1237,7 +1239,7 @@
                                                                   compiler_phases_timings,
                                                                   profile_file));
 
-  if (compiler.get() == NULL) {
+  if (compiler.get() == nullptr) {
     LOG(ERROR) << "Failed to create oat file: " << oat_location;
     return EXIT_FAILURE;
   }
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 412a052..fef25e0 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -417,9 +417,10 @@
       Runtime* runtime = Runtime::Current();
       if (runtime != nullptr) {
         ScopedObjectAccess soa(Thread::Current());
-        SirtRef<mirror::DexCache> dex_cache(
-            soa.Self(), runtime->GetClassLinker()->FindDexCache(dex_file));
-        SirtRef<mirror::ClassLoader> class_loader(soa.Self(), nullptr);
+        StackHandleScope<2> hs(soa.Self());
+        Handle<mirror::DexCache> dex_cache(
+            hs.NewHandle(runtime->GetClassLinker()->FindDexCache(dex_file)));
+        auto class_loader(hs.NewHandle<mirror::ClassLoader>(nullptr));
         verifier::MethodVerifier verifier(&dex_file, &dex_cache, &class_loader, &class_def,
                                           code_item, dex_method_idx, nullptr, method_access_flags,
                                           true, true);
@@ -687,11 +688,12 @@
                     uint32_t method_access_flags) {
     if ((method_access_flags & kAccNative) == 0) {
       ScopedObjectAccess soa(Thread::Current());
-      SirtRef<mirror::DexCache> dex_cache(
-          soa.Self(), Runtime::Current()->GetClassLinker()->FindDexCache(*dex_file));
-      SirtRef<mirror::ClassLoader> class_loader(soa.Self(), nullptr);
+      StackHandleScope<2> hs(soa.Self());
+      Handle<mirror::DexCache> dex_cache(
+          hs.NewHandle(Runtime::Current()->GetClassLinker()->FindDexCache(*dex_file)));
+      auto class_loader(hs.NewHandle<mirror::ClassLoader>(nullptr));
       verifier::MethodVerifier::VerifyMethodAndDump(os, dex_method_idx, dex_file, dex_cache,
-                                                    class_loader, &class_def, code_item, NULL,
+                                                    class_loader, &class_def, code_item, nullptr,
                                                     method_access_flags);
     }
   }
@@ -1548,7 +1550,7 @@
   }
   UniquePtr<Runtime> runtime(Runtime::Current());
   // Runtime::Create acquired the mutator_lock_ that is normally given away when we Runtime::Start,
-  // give it away now and then switch to a more managable ScopedObjectAccess.
+  // give it away now and then switch to a more manageable ScopedObjectAccess.
   Thread::Current()->TransitionFromRunnableToSuspended(kNative);
   ScopedObjectAccess soa(Thread::Current());
   gc::Heap* heap = Runtime::Current()->GetHeap();
diff --git a/runtime/arch/arch_test.cc b/runtime/arch/arch_test.cc
index c285088..45ff21f 100644
--- a/runtime/arch/arch_test.cc
+++ b/runtime/arch/arch_test.cc
@@ -17,7 +17,8 @@
 #include <stdint.h>
 
 #include "common_runtime_test.h"
-#include "mirror/art_method.h"
+#include "mirror/art_method-inl.h"
+#include "quick/quick_method_frame_info.h"
 
 namespace art {
 
@@ -30,10 +31,13 @@
     Thread* t = Thread::Current();
     t->TransitionFromSuspendedToRunnable();  // So we can create callee-save methods.
 
-    mirror::ArtMethod* save_method = r->CreateCalleeSaveMethod(isa, type);
-    EXPECT_EQ(save_method->GetFrameSizeInBytes(), save_size) << "Expected and real size differs for "
-        << type << " core spills=" << std::hex << save_method->GetCoreSpillMask() << " fp spills="
-        << save_method->GetFpSpillMask() << std::dec;
+    r->SetInstructionSet(isa);
+    mirror::ArtMethod* save_method = r->CreateCalleeSaveMethod(type);
+    r->SetCalleeSaveMethod(save_method, type);
+    QuickMethodFrameInfo frame_info = save_method->GetQuickFrameInfo();
+    EXPECT_EQ(frame_info.FrameSizeInBytes(), save_size) << "Expected and real size differs for "
+        << type << " core spills=" << std::hex << frame_info.CoreSpillMask() << " fp spills="
+        << frame_info.FpSpillMask() << std::dec;
 
     t->TransitionFromRunnableToSuspended(ThreadState::kNative);  // So we can shut down.
   }
diff --git a/runtime/arch/arm/context_arm.cc b/runtime/arch/arm/context_arm.cc
index 0e1b25e..6a337b3 100644
--- a/runtime/arch/arm/context_arm.cc
+++ b/runtime/arch/arm/context_arm.cc
@@ -16,8 +16,9 @@
 
 #include "context_arm.h"
 
-#include "mirror/art_method.h"
+#include "mirror/art_method-inl.h"
 #include "mirror/object-inl.h"
+#include "quick/quick_method_frame_info.h"
 #include "stack.h"
 #include "thread.h"
 
@@ -42,17 +43,15 @@
 
 void ArmContext::FillCalleeSaves(const StackVisitor& fr) {
   mirror::ArtMethod* method = fr.GetMethod();
-  uint32_t core_spills = method->GetCoreSpillMask();
-  uint32_t fp_core_spills = method->GetFpSpillMask();
-  size_t spill_count = POPCOUNT(core_spills);
-  size_t fp_spill_count = POPCOUNT(fp_core_spills);
-  size_t frame_size = method->GetFrameSizeInBytes();
+  const QuickMethodFrameInfo frame_info = method->GetQuickFrameInfo();
+  size_t spill_count = POPCOUNT(frame_info.CoreSpillMask());
+  size_t fp_spill_count = POPCOUNT(frame_info.FpSpillMask());
   if (spill_count > 0) {
     // Lowest number spill is farthest away, walk registers and fill into context
     int j = 1;
     for (size_t i = 0; i < kNumberOfCoreRegisters; i++) {
-      if (((core_spills >> i) & 1) != 0) {
-        gprs_[i] = fr.CalleeSaveAddress(spill_count - j, frame_size);
+      if (((frame_info.CoreSpillMask() >> i) & 1) != 0) {
+        gprs_[i] = fr.CalleeSaveAddress(spill_count - j, frame_info.FrameSizeInBytes());
         j++;
       }
     }
@@ -61,8 +60,9 @@
     // Lowest number spill is farthest away, walk registers and fill into context
     int j = 1;
     for (size_t i = 0; i < kNumberOfSRegisters; i++) {
-      if (((fp_core_spills >> i) & 1) != 0) {
-        fprs_[i] = fr.CalleeSaveAddress(spill_count + fp_spill_count - j, frame_size);
+      if (((frame_info.FpSpillMask() >> i) & 1) != 0) {
+        fprs_[i] = fr.CalleeSaveAddress(spill_count + fp_spill_count - j,
+                                        frame_info.FrameSizeInBytes());
         j++;
       }
     }
diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S
index dcf4561..5212576 100644
--- a/runtime/arch/arm/quick_entrypoints_arm.S
+++ b/runtime/arch/arm/quick_entrypoints_arm.S
@@ -399,7 +399,7 @@
     @ unlocked case - r2 holds thread id with count of 0
     strex  r3, r2, [r0, #LOCK_WORD_OFFSET]
     cbnz   r3, .Lstrex_fail           @ store failed, retry
-    dmb    ish                        @ full (LoadLoad) memory barrier
+    dmb    ish                        @ full (LoadLoad|LoadStore) memory barrier
     bx lr
 .Lstrex_fail:
     b .Lretry_lock                    @ unlikely forward branch, need to reload and recheck r1/r2
@@ -442,8 +442,8 @@
     cmp    r1, #65536
     bpl    .Lrecursive_thin_unlock
     @ transition to unlocked, r3 holds 0
+    dmb    ish                        @ full (LoadStore|StoreStore) memory barrier
     str    r3, [r0, #LOCK_WORD_OFFSET]
-    dmb    ish                        @ full (StoreLoad) memory barrier
     bx     lr
 .Lrecursive_thin_unlock:
     sub    r1, r1, #65536
diff --git a/runtime/arch/arm/quick_method_frame_info_arm.h b/runtime/arch/arm/quick_method_frame_info_arm.h
new file mode 100644
index 0000000..8d08190
--- /dev/null
+++ b/runtime/arch/arm/quick_method_frame_info_arm.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2014 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_ARCH_ARM_QUICK_METHOD_FRAME_INFO_ARM_H_
+#define ART_RUNTIME_ARCH_ARM_QUICK_METHOD_FRAME_INFO_ARM_H_
+
+#include "quick/quick_method_frame_info.h"
+#include "registers_arm.h"
+#include "runtime.h"  // for Runtime::CalleeSaveType.
+
+namespace art {
+namespace arm {
+
+static constexpr uint32_t kArmCalleeSaveRefSpills =
+    (1 << art::arm::R5) | (1 << art::arm::R6)  | (1 << art::arm::R7) | (1 << art::arm::R8) |
+    (1 << art::arm::R10) | (1 << art::arm::R11);
+static constexpr uint32_t kArmCalleeSaveArgSpills =
+    (1 << art::arm::R1) | (1 << art::arm::R2) | (1 << art::arm::R3);
+static constexpr uint32_t kArmCalleeSaveAllSpills =
+    (1 << art::arm::R4) | (1 << art::arm::R9);
+static constexpr uint32_t kArmCalleeSaveFpAllSpills =
+    (1 << art::arm::S0)  | (1 << art::arm::S1)  | (1 << art::arm::S2)  | (1 << art::arm::S3)  |
+    (1 << art::arm::S4)  | (1 << art::arm::S5)  | (1 << art::arm::S6)  | (1 << art::arm::S7)  |
+    (1 << art::arm::S8)  | (1 << art::arm::S9)  | (1 << art::arm::S10) | (1 << art::arm::S11) |
+    (1 << art::arm::S12) | (1 << art::arm::S13) | (1 << art::arm::S14) | (1 << art::arm::S15) |
+    (1 << art::arm::S16) | (1 << art::arm::S17) | (1 << art::arm::S18) | (1 << art::arm::S19) |
+    (1 << art::arm::S20) | (1 << art::arm::S21) | (1 << art::arm::S22) | (1 << art::arm::S23) |
+    (1 << art::arm::S24) | (1 << art::arm::S25) | (1 << art::arm::S26) | (1 << art::arm::S27) |
+    (1 << art::arm::S28) | (1 << art::arm::S29) | (1 << art::arm::S30) | (1 << art::arm::S31);
+
+constexpr uint32_t ArmCalleeSaveCoreSpills(Runtime::CalleeSaveType type) {
+  return kArmCalleeSaveRefSpills | (type == Runtime::kRefsAndArgs ? kArmCalleeSaveArgSpills : 0) |
+      (type == Runtime::kSaveAll ? kArmCalleeSaveAllSpills : 0) | (1 << art::arm::LR);
+}
+
+constexpr uint32_t ArmCalleeSaveFpSpills(Runtime::CalleeSaveType type) {
+  return type == Runtime::kSaveAll ? kArmCalleeSaveFpAllSpills : 0;
+}
+
+constexpr uint32_t ArmCalleeSaveFrameSize(Runtime::CalleeSaveType type) {
+  return RoundUp((POPCOUNT(ArmCalleeSaveCoreSpills(type)) /* gprs */ +
+                  POPCOUNT(ArmCalleeSaveFpSpills(type)) /* fprs */ +
+                  1 /* Method* */) * kArmPointerSize, kStackAlignment);
+}
+
+constexpr QuickMethodFrameInfo ArmCalleeSaveMethodFrameInfo(Runtime::CalleeSaveType type) {
+  return QuickMethodFrameInfo(ArmCalleeSaveFrameSize(type),
+                              ArmCalleeSaveCoreSpills(type),
+                              ArmCalleeSaveFpSpills(type));
+}
+
+}  // namespace arm
+}  // namespace art
+
+#endif  // ART_RUNTIME_ARCH_ARM_QUICK_METHOD_FRAME_INFO_ARM_H_
diff --git a/runtime/arch/arm64/context_arm64.cc b/runtime/arch/arm64/context_arm64.cc
index 0890fa9..fae44af 100644
--- a/runtime/arch/arm64/context_arm64.cc
+++ b/runtime/arch/arm64/context_arm64.cc
@@ -18,8 +18,9 @@
 
 #include "context_arm64.h"
 
-#include "mirror/art_method.h"
+#include "mirror/art_method-inl.h"
 #include "mirror/object-inl.h"
+#include "quick/quick_method_frame_info.h"
 #include "stack.h"
 #include "thread.h"
 
@@ -45,18 +46,15 @@
 
 void Arm64Context::FillCalleeSaves(const StackVisitor& fr) {
   mirror::ArtMethod* method = fr.GetMethod();
-  uint32_t core_spills = method->GetCoreSpillMask();
-  uint32_t fp_core_spills = method->GetFpSpillMask();
-  size_t spill_count = POPCOUNT(core_spills);
-  size_t fp_spill_count = POPCOUNT(fp_core_spills);
-  size_t frame_size = method->GetFrameSizeInBytes();
-
+  const QuickMethodFrameInfo frame_info = method->GetQuickFrameInfo();
+  size_t spill_count = POPCOUNT(frame_info.CoreSpillMask());
+  size_t fp_spill_count = POPCOUNT(frame_info.FpSpillMask());
   if (spill_count > 0) {
     // Lowest number spill is farthest away, walk registers and fill into context.
     int j = 1;
     for (size_t i = 0; i < kNumberOfCoreRegisters; i++) {
-      if (((core_spills >> i) & 1) != 0) {
-        gprs_[i] = fr.CalleeSaveAddress(spill_count  - j, frame_size);
+      if (((frame_info.CoreSpillMask() >> i) & 1) != 0) {
+        gprs_[i] = fr.CalleeSaveAddress(spill_count  - j, frame_info.FrameSizeInBytes());
         j++;
       }
     }
@@ -66,8 +64,9 @@
     // Lowest number spill is farthest away, walk registers and fill into context.
     int j = 1;
     for (size_t i = 0; i < kNumberOfDRegisters; i++) {
-      if (((fp_core_spills >> i) & 1) != 0) {
-        fprs_[i] = fr.CalleeSaveAddress(spill_count + fp_spill_count - j, frame_size);
+      if (((frame_info.FpSpillMask() >> i) & 1) != 0) {
+        fprs_[i] = fr.CalleeSaveAddress(spill_count + fp_spill_count - j,
+                                        frame_info.FrameSizeInBytes());
         j++;
       }
     }
diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S
index 8079460..f2050b3 100644
--- a/runtime/arch/arm64/quick_entrypoints_arm64.S
+++ b/runtime/arch/arm64/quick_entrypoints_arm64.S
@@ -443,35 +443,32 @@
     DELIVER_PENDING_EXCEPTION
 .endm
 
-// FIXME: Temporary fix for TR(XSELF).
 .macro NO_ARG_RUNTIME_EXCEPTION c_name, cxx_name
     .extern \cxx_name
 ENTRY \c_name
     SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  // save all registers as basis for long jump context
-    mov x0, x19                        // pass Thread::Current
+    mov x0, xSELF                        // pass Thread::Current
     mov x1, sp                        // pass SP
     b   \cxx_name                     // \cxx_name(Thread*, SP)
 END \c_name
 .endm
 
-// FIXME: Temporary fix for TR(XSELF).
 .macro ONE_ARG_RUNTIME_EXCEPTION c_name, cxx_name
     .extern \cxx_name
 ENTRY \c_name
     SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  // save all registers as basis for long jump context.
-    mov x1, x19                       // pass Thread::Current.
+    mov x1, xSELF                       // pass Thread::Current.
     mov x2, sp                        // pass SP.
     b   \cxx_name                     // \cxx_name(arg, Thread*, SP).
     brk 0
 END \c_name
 .endm
 
-// FIXME: Temporary fix for TR(XSELF).
 .macro TWO_ARG_RUNTIME_EXCEPTION c_name, cxx_name
     .extern \cxx_name
 ENTRY \c_name
     SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  // save all registers as basis for long jump context
-    mov x2, x19                       // pass Thread::Current
+    mov x2, xSELF                       // pass Thread::Current
     mov x3, sp                        // pass SP
     b   \cxx_name                     // \cxx_name(arg1, arg2, Thread*, SP)
     brk 0
@@ -991,7 +988,6 @@
      * failure.
      */
     .extern artHandleFillArrayDataFromCode
-// TODO: xSELF -> x19.
 ENTRY art_quick_handle_fill_data
     SETUP_REF_ONLY_CALLEE_SAVE_FRAME  // Save callee saves in case exception allocation triggers GC.
     mov    x2, xSELF                       // Pass Thread::Current.
@@ -1002,8 +998,81 @@
     DELIVER_PENDING_EXCEPTION
 END art_quick_handle_fill_data
 
-UNIMPLEMENTED art_quick_lock_object
-UNIMPLEMENTED art_quick_unlock_object
+    /*
+     * Entry from managed code that calls artLockObjectFromCode, may block for GC. x0 holds the
+     * possibly null object to lock.
+     *
+     * Derived from arm32 code.
+     */
+    .extern artLockObjectFromCode
+ENTRY art_quick_lock_object
+    cbz    w0, .Lslow_lock
+    add    x4, x0, #LOCK_WORD_OFFSET  // exclusive load/store had no immediate anymore
+.Lretry_lock:
+    ldr    w2, [xSELF, #THREAD_ID_OFFSET] // TODO: Can the thread ID really change during the loop?
+    ldxr   w1, [x4]
+    cbnz   w1, .Lnot_unlocked         // already thin locked
+    stxr   w3, w2, [x4]
+    cbnz   w3, .Lstrex_fail           // store failed, retry
+    dmb    ishld                      // full (LoadLoad|LoadStore) memory barrier
+    ret
+.Lstrex_fail:
+    b .Lretry_lock                    // unlikely forward branch, need to reload and recheck r1/r2
+.Lnot_unlocked:
+    lsr    w3, w1, 30
+    cbnz   w3, .Lslow_lock            // if either of the top two bits are set, go slow path
+    eor    w2, w1, w2                 // lock_word.ThreadId() ^ self->ThreadId()
+    uxth   w2, w2                     // zero top 16 bits
+    cbnz   w2, .Lslow_lock            // lock word and self thread id's match -> recursive lock
+                                      // else contention, go to slow path
+    add    w2, w1, #65536             // increment count in lock word placing in w2 for storing
+    lsr    w1, w2, 30                 // if either of the top two bits are set, we overflowed.
+    cbnz   w1, .Lslow_lock            // if we overflow the count go slow path
+    str    w2, [x0, #LOCK_WORD_OFFSET]// no need for stxr as we hold the lock
+    ret
+.Lslow_lock:
+    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  // save callee saves in case we block
+    mov    x1, xSELF                  // pass Thread::Current
+    mov    x2, sp                     // pass SP
+    bl     artLockObjectFromCode      // (Object* obj, Thread*, SP)
+    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+    RETURN_IF_W0_IS_ZERO_OR_DELIVER
+END art_quick_lock_object
+
+    /*
+     * Entry from managed code that calls artUnlockObjectFromCode and delivers exception on failure.
+     * x0 holds the possibly null object to lock.
+     *
+     * Derived from arm32 code.
+     */
+    .extern artUnlockObjectFromCode
+ENTRY art_quick_unlock_object
+    cbz    x0, .Lslow_unlock
+    ldr    w1, [x0, #LOCK_WORD_OFFSET]
+    lsr    w2, w1, 30
+    cbnz   w2, .Lslow_unlock          // if either of the top two bits are set, go slow path
+    ldr    w2, [xSELF, #THREAD_ID_OFFSET]
+    eor    w3, w1, w2                 // lock_word.ThreadId() ^ self->ThreadId()
+    uxth   w3, w3                     // zero top 16 bits
+    cbnz   w3, .Lslow_unlock          // do lock word and self thread id's match?
+    cmp    w1, #65536
+    bpl    .Lrecursive_thin_unlock
+    // transition to unlocked, w3 holds 0
+    dmb    ish                        // full (LoadStore|StoreStore) memory barrier
+    str    w3, [x0, #LOCK_WORD_OFFSET]
+    ret
+.Lrecursive_thin_unlock:
+    sub    w1, w1, #65536
+    str    w1, [x0, #LOCK_WORD_OFFSET]
+    ret
+.Lslow_unlock:
+    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  // save callee saves in case exception allocation triggers GC
+    mov    x1, xSELF                  // pass Thread::Current
+    mov    x2, sp                     // pass SP
+    bl     artUnlockObjectFromCode    // (Object* obj, Thread*, SP)
+    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+    RETURN_IF_W0_IS_ZERO_OR_DELIVER
+END art_quick_unlock_object
 
     /*
      * Entry from managed code that calls artIsAssignableFromCode and on failure calls
@@ -1166,12 +1235,7 @@
     brk 0                         // Unreached.
 END art_quick_aput_obj
 
-UNIMPLEMENTED art_quick_initialize_static_storage
-UNIMPLEMENTED art_quick_initialize_type
-UNIMPLEMENTED art_quick_initialize_type_and_verify_access
-
 // Macro to facilitate adding new allocation entrypoints.
-// TODO: xSELF -> x19. Temporarily rely on xSELF being saved in REF_ONLY
 .macro TWO_ARG_DOWNCALL name, entrypoint, return
     .extern \entrypoint
 ENTRY \name
@@ -1186,7 +1250,6 @@
 .endm
 
 // Macro to facilitate adding new array allocation entrypoints.
-// TODO: xSELF -> x19. Temporarily rely on xSELF being saved in REF_ONLY
 .macro THREE_ARG_DOWNCALL name, entrypoint, return
     .extern \entrypoint
 ENTRY \name
@@ -1244,6 +1307,16 @@
 END \name
 .endm
 
+    /*
+     * Entry from managed code when uninitialized static storage, this stub will run the class
+     * initializer and deliver the exception on error. On success the static storage base is
+     * returned.
+     */
+TWO_ARG_DOWNCALL art_quick_initialize_static_storage, artInitializeStaticStorageFromCode, RETURN_IF_RESULT_IS_NON_ZERO
+
+UNIMPLEMENTED art_quick_initialize_type
+UNIMPLEMENTED art_quick_initialize_type_and_verify_access
+
 ONE_ARG_REF_DOWNCALL art_quick_get32_static, artGet32StaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_X1
 ONE_ARG_REF_DOWNCALL art_quick_get64_static, artGet64StaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_X1
 ONE_ARG_REF_DOWNCALL art_quick_get_obj_static, artGetObjStaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_X1
@@ -1273,8 +1346,13 @@
     RETURN_IF_W0_IS_ZERO_OR_DELIVER
 END art_quick_set64_static
 
-
-UNIMPLEMENTED art_quick_resolve_string
+    /*
+     * Entry from managed code to resolve a string, this stub will allocate a String and deliver an
+     * exception on error. On success the String is returned. x0 holds the referring method,
+     * w1 holds the string index. The fast path check for hit in strings cache has already been
+     * performed.
+     */
+TWO_ARG_DOWNCALL art_quick_resolve_string, artResolveStringFromCode, RETURN_IF_RESULT_IS_NON_ZERO
 
 // Generate the allocation entrypoints for each allocator.
 GENERATE_ALL_ALLOC_ENTRYPOINTS
@@ -1293,7 +1371,7 @@
     mov     x2, xSELF                   // pass Thread::Current
     mov     x3, sp                      // pass SP
     bl      artQuickProxyInvokeHandler  // (Method* proxy method, receiver, Thread*, SP)
-    ldr  xSELF, [sp, #200]              // Restore self pointer.
+    ldr     xSELF, [sp, #200]           // Restore self pointer.
     ldr     x2, [xSELF, THREAD_EXCEPTION_OFFSET]
     cbnz    x2, .Lexception_in_proxy    // success if no exception is pending
     RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME_NO_D0 // keep d0
@@ -1308,14 +1386,13 @@
 
 ENTRY art_quick_resolution_trampoline
     SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
-    mov x19, x0           // save the called method
     mov x2, xSELF
     mov x3, sp
     bl artQuickResolutionTrampoline  // (called, receiver, Thread*, SP)
-    mov x9, x0            // Remember returned code pointer in x9.
-    mov x0, x19           // Restore the method, before x19 is restored to on-call value
+    cbz x0, 1f
+    mov x9, x0              // Remember returned code pointer in x9.
+    ldr x0, [sp, #0]        // artQuickResolutionTrampoline puts called method in *SP.
     RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
-    cbz x9, 1f
     br x9
 1:
     RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
@@ -1367,7 +1444,7 @@
  * | RDI/Method*       |  <- X0
  * #-------------------#
  * | local ref cookie  | // 4B
- * |   SIRT size       | // 4B
+ * | handle scope size | // 4B
  * #-------------------#
  * | JNI Call Stack    |
  * #-------------------#    <--- SP on native call
@@ -1394,7 +1471,7 @@
     .cfi_def_cfa_register x28
 
     // This looks the same, but is different: this will be updated to point to the bottom
-    // of the frame when the SIRT is inserted.
+    // of the frame when the handle scope is inserted.
     mov xFP, sp
 
     mov x8, #5120
@@ -1409,7 +1486,7 @@
     mov x1, xFP
     bl artQuickGenericJniTrampoline  // (Thread*, sp)
 
-    // Get the updated pointer. This is the bottom of the frame _with_ SIRT.
+    // Get the updated pointer. This is the bottom of the frame _with_ handle scope.
     ldr xFP, [sp]
     add x9, sp, #8
 
diff --git a/runtime/arch/arm64/quick_method_frame_info_arm64.h b/runtime/arch/arm64/quick_method_frame_info_arm64.h
new file mode 100644
index 0000000..cb830ac
--- /dev/null
+++ b/runtime/arch/arm64/quick_method_frame_info_arm64.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2014 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_ARCH_ARM64_QUICK_METHOD_FRAME_INFO_ARM64_H_
+#define ART_RUNTIME_ARCH_ARM64_QUICK_METHOD_FRAME_INFO_ARM64_H_
+
+#include "quick/quick_method_frame_info.h"
+#include "registers_arm64.h"
+#include "runtime.h"  // for Runtime::CalleeSaveType.
+
+namespace art {
+namespace arm64 {
+
+// Callee saved registers
+static constexpr uint32_t kArm64CalleeSaveRefSpills =
+    (1 << art::arm64::X19) | (1 << art::arm64::X20) | (1 << art::arm64::X21) |
+    (1 << art::arm64::X22) | (1 << art::arm64::X23) | (1 << art::arm64::X24) |
+    (1 << art::arm64::X25) | (1 << art::arm64::X26) | (1 << art::arm64::X27) |
+    (1 << art::arm64::X28);
+// X0 is the method pointer. Not saved.
+static constexpr uint32_t kArm64CalleeSaveArgSpills =
+    (1 << art::arm64::X1) | (1 << art::arm64::X2) | (1 << art::arm64::X3) |
+    (1 << art::arm64::X4) | (1 << art::arm64::X5) | (1 << art::arm64::X6) |
+    (1 << art::arm64::X7);
+// TODO  This is conservative. Only ALL should include the thread register.
+// The thread register is not preserved by the aapcs64.
+// LR is always saved.
+static constexpr uint32_t kArm64CalleeSaveAllSpills =  0;  // (1 << art::arm64::LR);
+
+// Save callee-saved floating point registers. Rest are scratch/parameters.
+static constexpr uint32_t kArm64CalleeSaveFpArgSpills =
+    (1 << art::arm64::D0) | (1 << art::arm64::D1) | (1 << art::arm64::D2) |
+    (1 << art::arm64::D3) | (1 << art::arm64::D4) | (1 << art::arm64::D5) |
+    (1 << art::arm64::D6) | (1 << art::arm64::D7);
+static constexpr uint32_t kArm64CalleeSaveFpRefSpills =
+    (1 << art::arm64::D8)  | (1 << art::arm64::D9)  | (1 << art::arm64::D10) |
+    (1 << art::arm64::D11)  | (1 << art::arm64::D12)  | (1 << art::arm64::D13) |
+    (1 << art::arm64::D14)  | (1 << art::arm64::D15);
+static constexpr uint32_t kArm64FpAllSpills =
+    kArm64CalleeSaveFpArgSpills |
+    (1 << art::arm64::D16)  | (1 << art::arm64::D17) | (1 << art::arm64::D18) |
+    (1 << art::arm64::D19)  | (1 << art::arm64::D20) | (1 << art::arm64::D21) |
+    (1 << art::arm64::D22)  | (1 << art::arm64::D23) | (1 << art::arm64::D24) |
+    (1 << art::arm64::D25)  | (1 << art::arm64::D26) | (1 << art::arm64::D27) |
+    (1 << art::arm64::D28)  | (1 << art::arm64::D29) | (1 << art::arm64::D30) |
+    (1 << art::arm64::D31);
+
+constexpr uint32_t Arm64CalleeSaveCoreSpills(Runtime::CalleeSaveType type) {
+  return kArm64CalleeSaveRefSpills |
+      (type == Runtime::kRefsAndArgs ? kArm64CalleeSaveArgSpills : 0) |
+      (type == Runtime::kSaveAll ? kArm64CalleeSaveAllSpills : 0) | (1 << art::arm64::FP) |
+      (1 << art::arm64::X18) | (1 << art::arm64::LR);
+}
+
+constexpr uint32_t Arm64CalleeSaveFpSpills(Runtime::CalleeSaveType type) {
+  return kArm64CalleeSaveFpRefSpills |
+      (type == Runtime::kRefsAndArgs ? kArm64CalleeSaveFpArgSpills: 0) |
+      (type == Runtime::kSaveAll ? kArm64FpAllSpills : 0);
+}
+
+constexpr uint32_t Arm64CalleeSaveFrameSize(Runtime::CalleeSaveType type) {
+  return RoundUp((POPCOUNT(Arm64CalleeSaveCoreSpills(type)) /* gprs */ +
+                  POPCOUNT(Arm64CalleeSaveFpSpills(type)) /* fprs */ +
+                  1 /* Method* */) * kArm64PointerSize, kStackAlignment);
+}
+
+constexpr QuickMethodFrameInfo Arm64CalleeSaveMethodFrameInfo(Runtime::CalleeSaveType type) {
+  return QuickMethodFrameInfo(Arm64CalleeSaveFrameSize(type),
+                              Arm64CalleeSaveCoreSpills(type),
+                              Arm64CalleeSaveFpSpills(type));
+}
+
+}  // namespace arm64
+}  // namespace art
+
+#endif  // ART_RUNTIME_ARCH_ARM64_QUICK_METHOD_FRAME_INFO_ARM64_H_
diff --git a/runtime/arch/arm64/registers_arm64.h b/runtime/arch/arm64/registers_arm64.h
index 2503918..ea346e0 100644
--- a/runtime/arch/arm64/registers_arm64.h
+++ b/runtime/arch/arm64/registers_arm64.h
@@ -56,8 +56,8 @@
   X29 = 29,
   X30 = 30,
   X31 = 31,
-  TR  = 18,     // ART Thread Register - Needs to be one of the callee saved regs.
-  TR1 = 19,     // FIXME!
+  TR  = 18,     // ART Thread Register - Managed Runtime (Caller Saved Reg)
+  ETR = 19,     // ART Thread Register - External Calls  (Callee Saved Reg)
   IP0 = 16,     // Used as scratch by VIXL.
   IP1 = 17,     // Used as scratch by ART JNI Assembler.
   FP  = 29,
diff --git a/runtime/arch/mips/context_mips.cc b/runtime/arch/mips/context_mips.cc
index 0950e71..ad28891 100644
--- a/runtime/arch/mips/context_mips.cc
+++ b/runtime/arch/mips/context_mips.cc
@@ -16,8 +16,9 @@
 
 #include "context_mips.h"
 
-#include "mirror/art_method.h"
+#include "mirror/art_method-inl.h"
 #include "mirror/object-inl.h"
+#include "quick/quick_method_frame_info.h"
 #include "stack.h"
 
 namespace art {
@@ -41,17 +42,15 @@
 
 void MipsContext::FillCalleeSaves(const StackVisitor& fr) {
   mirror::ArtMethod* method = fr.GetMethod();
-  uint32_t core_spills = method->GetCoreSpillMask();
-  uint32_t fp_core_spills = method->GetFpSpillMask();
-  size_t spill_count = POPCOUNT(core_spills);
-  size_t fp_spill_count = POPCOUNT(fp_core_spills);
-  size_t frame_size = method->GetFrameSizeInBytes();
+  const QuickMethodFrameInfo frame_info = method->GetQuickFrameInfo();
+  size_t spill_count = POPCOUNT(frame_info.CoreSpillMask());
+  size_t fp_spill_count = POPCOUNT(frame_info.FpSpillMask());
   if (spill_count > 0) {
     // Lowest number spill is farthest away, walk registers and fill into context.
     int j = 1;
     for (size_t i = 0; i < kNumberOfCoreRegisters; i++) {
-      if (((core_spills >> i) & 1) != 0) {
-        gprs_[i] = fr.CalleeSaveAddress(spill_count - j, frame_size);
+      if (((frame_info.CoreSpillMask() >> i) & 1) != 0) {
+        gprs_[i] = fr.CalleeSaveAddress(spill_count - j, frame_info.FrameSizeInBytes());
         j++;
       }
     }
@@ -60,8 +59,9 @@
     // Lowest number spill is farthest away, walk registers and fill into context.
     int j = 1;
     for (size_t i = 0; i < kNumberOfFRegisters; i++) {
-      if (((fp_core_spills >> i) & 1) != 0) {
-        fprs_[i] = fr.CalleeSaveAddress(spill_count + fp_spill_count - j, frame_size);
+      if (((frame_info.FpSpillMask() >> i) & 1) != 0) {
+        fprs_[i] = fr.CalleeSaveAddress(spill_count + fp_spill_count - j,
+                                        frame_info.FrameSizeInBytes());
         j++;
       }
     }
diff --git a/runtime/arch/mips/quick_method_frame_info_mips.h b/runtime/arch/mips/quick_method_frame_info_mips.h
new file mode 100644
index 0000000..2a8bcf0
--- /dev/null
+++ b/runtime/arch/mips/quick_method_frame_info_mips.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2014 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_ARCH_MIPS_QUICK_METHOD_FRAME_INFO_MIPS_H_
+#define ART_RUNTIME_ARCH_MIPS_QUICK_METHOD_FRAME_INFO_MIPS_H_
+
+#include "quick/quick_method_frame_info.h"
+#include "registers_mips.h"
+#include "runtime.h"  // for Runtime::CalleeSaveType.
+
+namespace art {
+namespace mips {
+
+static constexpr uint32_t kMipsCalleeSaveRefSpills =
+    (1 << art::mips::S2) | (1 << art::mips::S3) | (1 << art::mips::S4) | (1 << art::mips::S5) |
+    (1 << art::mips::S6) | (1 << art::mips::S7) | (1 << art::mips::GP) | (1 << art::mips::FP);
+static constexpr uint32_t kMipsCalleeSaveArgSpills =
+    (1 << art::mips::A1) | (1 << art::mips::A2) | (1 << art::mips::A3);
+static constexpr uint32_t kMipsCalleeSaveAllSpills =
+    (1 << art::mips::S0) | (1 << art::mips::S1);
+
+constexpr uint32_t MipsCalleeSaveCoreSpills(Runtime::CalleeSaveType type) {
+  return kMipsCalleeSaveRefSpills |
+      (type == Runtime::kRefsAndArgs ? kMipsCalleeSaveArgSpills : 0) |
+      (type == Runtime::kSaveAll ? kMipsCalleeSaveAllSpills : 0) | (1 << art::mips::RA);
+}
+
+constexpr uint32_t MipsCalleeSaveFrameSize(Runtime::CalleeSaveType type) {
+  return RoundUp((POPCOUNT(MipsCalleeSaveCoreSpills(type)) /* gprs */ +
+                  (type == Runtime::kRefsAndArgs ? 0 : 3) + 1 /* Method* */) *
+                 kMipsPointerSize, kStackAlignment);
+}
+
+constexpr QuickMethodFrameInfo MipsCalleeSaveMethodFrameInfo(Runtime::CalleeSaveType type) {
+  return QuickMethodFrameInfo(MipsCalleeSaveFrameSize(type),
+                              MipsCalleeSaveCoreSpills(type),
+                              0u);
+}
+
+}  // namespace mips
+}  // namespace art
+
+#endif  // ART_RUNTIME_ARCH_MIPS_QUICK_METHOD_FRAME_INFO_MIPS_H_
diff --git a/runtime/arch/stub_test.cc b/runtime/arch/stub_test.cc
index 1d05540..d9bc105 100644
--- a/runtime/arch/stub_test.cc
+++ b/runtime/arch/stub_test.cc
@@ -33,10 +33,11 @@
     {
       // Create callee-save methods
       ScopedObjectAccess soa(Thread::Current());
+      runtime_->SetInstructionSet(kRuntimeISA);
       for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
         Runtime::CalleeSaveType type = Runtime::CalleeSaveType(i);
         if (!runtime_->HasCalleeSaveMethod(type)) {
-          runtime_->SetCalleeSaveMethod(runtime_->CreateCalleeSaveMethod(kRuntimeISA, type), type);
+          runtime_->SetCalleeSaveMethod(runtime_->CreateCalleeSaveMethod(type), type);
         }
       }
     }
@@ -51,6 +52,12 @@
     }
   }
 
+  // Helper function needed since TEST_F makes a new class.
+  Thread::tls_ptr_sized_values* GetTlsPtr(Thread* self) {
+    return &self->tlsPtr_;
+  }
+
+ public:
   size_t Invoke3(size_t arg0, size_t arg1, size_t arg2, uintptr_t code, Thread* self) {
     // Push a transition back into managed code onto the linked list in thread.
     ManagedStack fragment;
@@ -164,7 +171,6 @@
     return result;
   }
 
- public:
   // TODO: Set up a frame according to referrer's specs.
   size_t Invoke3WithReferrer(size_t arg0, size_t arg1, size_t arg2, uintptr_t code, Thread* self,
                              mirror::ArtMethod* referrer) {
@@ -352,12 +358,12 @@
 #endif
 }
 
-#if defined(__i386__) || defined(__arm__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
 extern "C" void art_quick_lock_object(void);
 #endif
 
 TEST_F(StubTest, LockObject) {
-#if defined(__i386__) || defined(__arm__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
   static constexpr size_t kThinLockLoops = 100;
 
   Thread* self = Thread::Current();
@@ -365,13 +371,14 @@
   ScopedObjectAccess soa(self);
   // garbage is created during ClassLinker::Init
 
-  SirtRef<mirror::String> obj(soa.Self(),
-                              mirror::String::AllocFromModifiedUtf8(soa.Self(), "hello, world!"));
+  StackHandleScope<2> hs(soa.Self());
+  Handle<mirror::String> obj(
+      hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "hello, world!")));
   LockWord lock = obj->GetLockWord(false);
   LockWord::LockState old_state = lock.GetState();
   EXPECT_EQ(LockWord::LockState::kUnlocked, old_state);
 
-  Invoke3(reinterpret_cast<size_t>(obj.get()), 0U, 0U,
+  Invoke3(reinterpret_cast<size_t>(obj.Get()), 0U, 0U,
           reinterpret_cast<uintptr_t>(&art_quick_lock_object), self);
 
   LockWord lock_after = obj->GetLockWord(false);
@@ -380,7 +387,7 @@
   EXPECT_EQ(lock_after.ThinLockCount(), 0U);  // Thin lock starts count at zero
 
   for (size_t i = 1; i < kThinLockLoops; ++i) {
-    Invoke3(reinterpret_cast<size_t>(obj.get()), 0U, 0U,
+    Invoke3(reinterpret_cast<size_t>(obj.Get()), 0U, 0U,
               reinterpret_cast<uintptr_t>(&art_quick_lock_object), self);
 
     // Check we're at lock count i
@@ -391,8 +398,21 @@
     EXPECT_EQ(l_inc.ThinLockCount(), i);
   }
 
-  // TODO: Improve this test. Somehow force it to go to fat locked. But that needs another thread.
+  // Force a fat lock by running identity hashcode to fill up lock word.
+  Handle<mirror::String> obj2(hs.NewHandle(
+      mirror::String::AllocFromModifiedUtf8(soa.Self(), "hello, world!")));
 
+  obj2->IdentityHashCode();
+
+  Invoke3(reinterpret_cast<size_t>(obj2.Get()), 0U, 0U,
+          reinterpret_cast<uintptr_t>(&art_quick_lock_object), self);
+
+  LockWord lock_after2 = obj2->GetLockWord(false);
+  LockWord::LockState new_state2 = lock_after2.GetState();
+  EXPECT_EQ(LockWord::LockState::kFatLocked, new_state2);
+  EXPECT_NE(lock_after2.FatLockMonitor(), static_cast<Monitor*>(nullptr));
+
+  // Test done.
 #else
   LOG(INFO) << "Skipping lock_object as I don't know how to do that on " << kRuntimeISA;
   // Force-print to std::cout so it's also outside the logcat.
@@ -414,29 +434,30 @@
 };
 
 
-#if defined(__i386__) || defined(__arm__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
 extern "C" void art_quick_lock_object(void);
 extern "C" void art_quick_unlock_object(void);
 #endif
 
-TEST_F(StubTest, UnlockObject) {
-#if defined(__i386__) || defined(__arm__) || defined(__x86_64__)
+// NO_THREAD_SAFETY_ANALYSIS as we do not want to grab exclusive mutator lock for MonitorInfo.
+static void TestUnlockObject(StubTest* test) NO_THREAD_SAFETY_ANALYSIS {
+#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
   static constexpr size_t kThinLockLoops = 100;
 
   Thread* self = Thread::Current();
   // Create an object
   ScopedObjectAccess soa(self);
   // garbage is created during ClassLinker::Init
-
-  SirtRef<mirror::String> obj(soa.Self(),
-                              mirror::String::AllocFromModifiedUtf8(soa.Self(), "hello, world!"));
+  static constexpr size_t kNumberOfLocks = 10;  // Number of objects = lock
+  StackHandleScope<kNumberOfLocks + 1> hs(self);
+  Handle<mirror::String> obj(
+      hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "hello, world!")));
   LockWord lock = obj->GetLockWord(false);
   LockWord::LockState old_state = lock.GetState();
   EXPECT_EQ(LockWord::LockState::kUnlocked, old_state);
 
-  Invoke3(reinterpret_cast<size_t>(obj.get()), 0U, 0U,
-          reinterpret_cast<uintptr_t>(&art_quick_unlock_object), self);
-
+  test->Invoke3(reinterpret_cast<size_t>(obj.Get()), 0U, 0U,
+                reinterpret_cast<uintptr_t>(&art_quick_unlock_object), self);
   // This should be an illegal monitor state.
   EXPECT_TRUE(self->IsExceptionPending());
   self->ClearException();
@@ -445,15 +466,15 @@
   LockWord::LockState new_state = lock_after.GetState();
   EXPECT_EQ(LockWord::LockState::kUnlocked, new_state);
 
-  Invoke3(reinterpret_cast<size_t>(obj.get()), 0U, 0U,
-          reinterpret_cast<uintptr_t>(&art_quick_lock_object), self);
+  test->Invoke3(reinterpret_cast<size_t>(obj.Get()), 0U, 0U,
+                reinterpret_cast<uintptr_t>(&art_quick_lock_object), self);
 
   LockWord lock_after2 = obj->GetLockWord(false);
   LockWord::LockState new_state2 = lock_after2.GetState();
   EXPECT_EQ(LockWord::LockState::kThinLocked, new_state2);
 
-  Invoke3(reinterpret_cast<size_t>(obj.get()), 0U, 0U,
-          reinterpret_cast<uintptr_t>(&art_quick_unlock_object), self);
+  test->Invoke3(reinterpret_cast<size_t>(obj.Get()), 0U, 0U,
+                reinterpret_cast<uintptr_t>(&art_quick_unlock_object), self);
 
   LockWord lock_after3 = obj->GetLockWord(false);
   LockWord::LockState new_state3 = lock_after3.GetState();
@@ -465,77 +486,96 @@
 
   RandGen r(0x1234);
 
-  constexpr size_t kNumberOfLocks = 10;  // Number of objects = lock
   constexpr size_t kIterations = 10000;  // Number of iterations
+  constexpr size_t kMoveToFat = 1000;     // Chance of 1:kMoveFat to make a lock fat.
 
   size_t counts[kNumberOfLocks];
-  SirtRef<mirror::String>* objects[kNumberOfLocks];
+  bool fat[kNumberOfLocks];  // Whether a lock should be thin or fat.
+  Handle<mirror::String> objects[kNumberOfLocks];
 
   // Initialize = allocate.
   for (size_t i = 0; i < kNumberOfLocks; ++i) {
     counts[i] = 0;
-    objects[i] = new SirtRef<mirror::String>(soa.Self(),
-                                             mirror::String::AllocFromModifiedUtf8(soa.Self(), ""));
+    fat[i] = false;
+    objects[i] = hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), ""));
   }
 
   for (size_t i = 0; i < kIterations; ++i) {
     // Select which lock to update.
     size_t index = r.next() % kNumberOfLocks;
 
-    bool lock;  // Whether to lock or unlock in this step.
-    if (counts[index] == 0) {
-      lock = true;
-    } else if (counts[index] == kThinLockLoops) {
-      lock = false;
-    } else {
-      // Randomly.
-      lock = r.next() % 2 == 0;
-    }
+    // Make lock fat?
+    if (!fat[index] && (r.next() % kMoveToFat == 0)) {
+      fat[index] = true;
+      objects[index]->IdentityHashCode();
 
-    if (lock) {
-      Invoke3(reinterpret_cast<size_t>(objects[index]->get()), 0U, 0U,
-              reinterpret_cast<uintptr_t>(&art_quick_lock_object), self);
-      counts[index]++;
+      LockWord lock_iter = objects[index]->GetLockWord(false);
+      LockWord::LockState iter_state = lock_iter.GetState();
+      if (counts[index] == 0) {
+        EXPECT_EQ(LockWord::LockState::kHashCode, iter_state);
+      } else {
+        EXPECT_EQ(LockWord::LockState::kFatLocked, iter_state);
+      }
     } else {
-      Invoke3(reinterpret_cast<size_t>(objects[index]->get()), 0U, 0U,
-              reinterpret_cast<uintptr_t>(&art_quick_unlock_object), self);
-      counts[index]--;
-    }
+      bool lock;  // Whether to lock or unlock in this step.
+      if (counts[index] == 0) {
+        lock = true;
+      } else if (counts[index] == kThinLockLoops) {
+        lock = false;
+      } else {
+        // Randomly.
+        lock = r.next() % 2 == 0;
+      }
 
-    EXPECT_FALSE(self->IsExceptionPending());
+      if (lock) {
+        test->Invoke3(reinterpret_cast<size_t>(objects[index].Get()), 0U, 0U,
+                       reinterpret_cast<uintptr_t>(&art_quick_lock_object), self);
+        counts[index]++;
+      } else {
+        test->Invoke3(reinterpret_cast<size_t>(objects[index].Get()), 0U, 0U,
+                      reinterpret_cast<uintptr_t>(&art_quick_unlock_object), self);
+        counts[index]--;
+      }
 
-    // Check the new state.
-    LockWord lock_iter = objects[index]->get()->GetLockWord(false);
-    LockWord::LockState iter_state = lock_iter.GetState();
-    if (counts[index] > 0) {
-      EXPECT_EQ(LockWord::LockState::kThinLocked, iter_state);
-      EXPECT_EQ(counts[index] - 1, lock_iter.ThinLockCount());
-    } else {
-      EXPECT_EQ(LockWord::LockState::kUnlocked, iter_state);
+      EXPECT_FALSE(self->IsExceptionPending());
+
+      // Check the new state.
+      LockWord lock_iter = objects[index]->GetLockWord(true);
+      LockWord::LockState iter_state = lock_iter.GetState();
+      if (fat[index]) {
+        // Abuse MonitorInfo.
+        EXPECT_EQ(LockWord::LockState::kFatLocked, iter_state) << index;
+        MonitorInfo info(objects[index].Get());
+        EXPECT_EQ(counts[index], info.entry_count_) << index;
+      } else {
+        if (counts[index] > 0) {
+          EXPECT_EQ(LockWord::LockState::kThinLocked, iter_state);
+          EXPECT_EQ(counts[index] - 1, lock_iter.ThinLockCount());
+        } else {
+          EXPECT_EQ(LockWord::LockState::kUnlocked, iter_state);
+        }
+      }
     }
   }
 
   // Unlock the remaining count times and then check it's unlocked. Then deallocate.
-  // Go reverse order to correctly handle SirtRefs.
+  // Go reverse order to correctly handle Handles.
   for (size_t i = 0; i < kNumberOfLocks; ++i) {
     size_t index = kNumberOfLocks - 1 - i;
     size_t count = counts[index];
     while (count > 0) {
-      Invoke3(reinterpret_cast<size_t>(objects[index]->get()), 0U, 0U,
-              reinterpret_cast<uintptr_t>(&art_quick_unlock_object), self);
-
+      test->Invoke3(reinterpret_cast<size_t>(objects[index].Get()), 0U, 0U,
+                    reinterpret_cast<uintptr_t>(&art_quick_unlock_object), self);
       count--;
     }
 
-    LockWord lock_after4 = objects[index]->get()->GetLockWord(false);
+    LockWord lock_after4 = objects[index]->GetLockWord(false);
     LockWord::LockState new_state4 = lock_after4.GetState();
-    EXPECT_EQ(LockWord::LockState::kUnlocked, new_state4);
-
-    delete objects[index];
+    EXPECT_TRUE(LockWord::LockState::kUnlocked == new_state4
+                || LockWord::LockState::kFatLocked == new_state4);
   }
 
-  // TODO: Improve this test. Somehow force it to go to fat locked. But that needs another thread.
-
+  // Test done.
 #else
   LOG(INFO) << "Skipping unlock_object as I don't know how to do that on " << kRuntimeISA;
   // Force-print to std::cout so it's also outside the logcat.
@@ -543,6 +583,9 @@
 #endif
 }
 
+TEST_F(StubTest, UnlockObject) {
+  TestUnlockObject(this);
+}
 
 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
 extern "C" void art_quick_check_cast(void);
@@ -555,31 +598,32 @@
   ScopedObjectAccess soa(self);
   // garbage is created during ClassLinker::Init
 
-  SirtRef<mirror::Class> c(soa.Self(), class_linker_->FindSystemClass(soa.Self(),
-                                                                          "[Ljava/lang/Object;"));
-  SirtRef<mirror::Class> c2(soa.Self(), class_linker_->FindSystemClass(soa.Self(),
-                                                                            "[Ljava/lang/String;"));
+  StackHandleScope<2> hs(soa.Self());
+  Handle<mirror::Class> c(
+      hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "[Ljava/lang/Object;")));
+  Handle<mirror::Class> c2(
+      hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "[Ljava/lang/String;")));
 
   EXPECT_FALSE(self->IsExceptionPending());
 
-  Invoke3(reinterpret_cast<size_t>(c.get()), reinterpret_cast<size_t>(c.get()), 0U,
+  Invoke3(reinterpret_cast<size_t>(c.Get()), reinterpret_cast<size_t>(c.Get()), 0U,
           reinterpret_cast<uintptr_t>(&art_quick_check_cast), self);
 
   EXPECT_FALSE(self->IsExceptionPending());
 
-  Invoke3(reinterpret_cast<size_t>(c2.get()), reinterpret_cast<size_t>(c2.get()), 0U,
+  Invoke3(reinterpret_cast<size_t>(c2.Get()), reinterpret_cast<size_t>(c2.Get()), 0U,
           reinterpret_cast<uintptr_t>(&art_quick_check_cast), self);
 
   EXPECT_FALSE(self->IsExceptionPending());
 
-  Invoke3(reinterpret_cast<size_t>(c.get()), reinterpret_cast<size_t>(c2.get()), 0U,
+  Invoke3(reinterpret_cast<size_t>(c.Get()), reinterpret_cast<size_t>(c2.Get()), 0U,
           reinterpret_cast<uintptr_t>(&art_quick_check_cast), self);
 
   EXPECT_FALSE(self->IsExceptionPending());
 
   // TODO: Make the following work. But that would require correct managed frames.
 
-  Invoke3(reinterpret_cast<size_t>(c2.get()), reinterpret_cast<size_t>(c.get()), 0U,
+  Invoke3(reinterpret_cast<size_t>(c2.Get()), reinterpret_cast<size_t>(c.Get()), 0U,
           reinterpret_cast<uintptr_t>(&art_quick_check_cast), self);
 
   EXPECT_TRUE(self->IsExceptionPending());
@@ -607,23 +651,22 @@
   ScopedObjectAccess soa(self);
   // garbage is created during ClassLinker::Init
 
-  SirtRef<mirror::Class> c(soa.Self(), class_linker_->FindSystemClass(soa.Self(),
-                                                                            "Ljava/lang/Object;"));
-  SirtRef<mirror::Class> c2(soa.Self(), class_linker_->FindSystemClass(soa.Self(),
-                                                                            "Ljava/lang/String;"));
-  SirtRef<mirror::Class> ca(soa.Self(), class_linker_->FindSystemClass(soa.Self(),
-                                                                            "[Ljava/lang/String;"));
+  StackHandleScope<5> hs(soa.Self());
+  Handle<mirror::Class> c(
+      hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;")));
+  Handle<mirror::Class> ca(
+      hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "[Ljava/lang/String;")));
 
   // Build a string array of size 1
-  SirtRef<mirror::ObjectArray<mirror::Object> > array(soa.Self(),
-            mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), ca.get(), 10));
+  Handle<mirror::ObjectArray<mirror::Object>> array(
+      hs.NewHandle(mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), ca.Get(), 10)));
 
   // Build a string -> should be assignable
-  SirtRef<mirror::Object> str_obj(soa.Self(),
-                                  mirror::String::AllocFromModifiedUtf8(soa.Self(), "hello, world!"));
+  Handle<mirror::String> str_obj(
+      hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "hello, world!")));
 
   // Build a generic object -> should fail assigning
-  SirtRef<mirror::Object> obj_obj(soa.Self(), c->AllocObject(soa.Self()));
+  Handle<mirror::Object> obj_obj(hs.NewHandle(c->AllocObject(soa.Self())));
 
   // Play with it...
 
@@ -632,51 +675,51 @@
 
   EXPECT_FALSE(self->IsExceptionPending());
 
-  Invoke3(reinterpret_cast<size_t>(array.get()), 0U, reinterpret_cast<size_t>(str_obj.get()),
+  Invoke3(reinterpret_cast<size_t>(array.Get()), 0U, reinterpret_cast<size_t>(str_obj.Get()),
           reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
 
   EXPECT_FALSE(self->IsExceptionPending());
-  EXPECT_EQ(str_obj.get(), array->Get(0));
+  EXPECT_EQ(str_obj.Get(), array->Get(0));
 
-  Invoke3(reinterpret_cast<size_t>(array.get()), 1U, reinterpret_cast<size_t>(str_obj.get()),
+  Invoke3(reinterpret_cast<size_t>(array.Get()), 1U, reinterpret_cast<size_t>(str_obj.Get()),
           reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
 
   EXPECT_FALSE(self->IsExceptionPending());
-  EXPECT_EQ(str_obj.get(), array->Get(1));
+  EXPECT_EQ(str_obj.Get(), array->Get(1));
 
-  Invoke3(reinterpret_cast<size_t>(array.get()), 2U, reinterpret_cast<size_t>(str_obj.get()),
+  Invoke3(reinterpret_cast<size_t>(array.Get()), 2U, reinterpret_cast<size_t>(str_obj.Get()),
           reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
 
   EXPECT_FALSE(self->IsExceptionPending());
-  EXPECT_EQ(str_obj.get(), array->Get(2));
+  EXPECT_EQ(str_obj.Get(), array->Get(2));
 
-  Invoke3(reinterpret_cast<size_t>(array.get()), 3U, reinterpret_cast<size_t>(str_obj.get()),
+  Invoke3(reinterpret_cast<size_t>(array.Get()), 3U, reinterpret_cast<size_t>(str_obj.Get()),
           reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
 
   EXPECT_FALSE(self->IsExceptionPending());
-  EXPECT_EQ(str_obj.get(), array->Get(3));
+  EXPECT_EQ(str_obj.Get(), array->Get(3));
 
   // 1.2) Assign null to array[0..3]
 
-  Invoke3(reinterpret_cast<size_t>(array.get()), 0U, reinterpret_cast<size_t>(nullptr),
+  Invoke3(reinterpret_cast<size_t>(array.Get()), 0U, reinterpret_cast<size_t>(nullptr),
           reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
 
   EXPECT_FALSE(self->IsExceptionPending());
   EXPECT_EQ(nullptr, array->Get(0));
 
-  Invoke3(reinterpret_cast<size_t>(array.get()), 1U, reinterpret_cast<size_t>(nullptr),
+  Invoke3(reinterpret_cast<size_t>(array.Get()), 1U, reinterpret_cast<size_t>(nullptr),
           reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
 
   EXPECT_FALSE(self->IsExceptionPending());
   EXPECT_EQ(nullptr, array->Get(1));
 
-  Invoke3(reinterpret_cast<size_t>(array.get()), 2U, reinterpret_cast<size_t>(nullptr),
+  Invoke3(reinterpret_cast<size_t>(array.Get()), 2U, reinterpret_cast<size_t>(nullptr),
           reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
 
   EXPECT_FALSE(self->IsExceptionPending());
   EXPECT_EQ(nullptr, array->Get(2));
 
-  Invoke3(reinterpret_cast<size_t>(array.get()), 3U, reinterpret_cast<size_t>(nullptr),
+  Invoke3(reinterpret_cast<size_t>(array.Get()), 3U, reinterpret_cast<size_t>(nullptr),
           reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
 
   EXPECT_FALSE(self->IsExceptionPending());
@@ -688,7 +731,7 @@
   // 2.1) Array = null
   // TODO: Throwing NPE needs actual DEX code
 
-//  Invoke3(reinterpret_cast<size_t>(nullptr), 0U, reinterpret_cast<size_t>(str_obj.get()),
+//  Invoke3(reinterpret_cast<size_t>(nullptr), 0U, reinterpret_cast<size_t>(str_obj.Get()),
 //          reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
 //
 //  EXPECT_TRUE(self->IsExceptionPending());
@@ -696,8 +739,8 @@
 
   // 2.2) Index < 0
 
-  Invoke3(reinterpret_cast<size_t>(array.get()), static_cast<size_t>(-1),
-          reinterpret_cast<size_t>(str_obj.get()),
+  Invoke3(reinterpret_cast<size_t>(array.Get()), static_cast<size_t>(-1),
+          reinterpret_cast<size_t>(str_obj.Get()),
           reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
 
   EXPECT_TRUE(self->IsExceptionPending());
@@ -705,7 +748,7 @@
 
   // 2.3) Index > 0
 
-  Invoke3(reinterpret_cast<size_t>(array.get()), 10U, reinterpret_cast<size_t>(str_obj.get()),
+  Invoke3(reinterpret_cast<size_t>(array.Get()), 10U, reinterpret_cast<size_t>(str_obj.Get()),
           reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
 
   EXPECT_TRUE(self->IsExceptionPending());
@@ -713,7 +756,7 @@
 
   // 3) Failure cases (obj into str[])
 
-  Invoke3(reinterpret_cast<size_t>(array.get()), 0U, reinterpret_cast<size_t>(obj_obj.get()),
+  Invoke3(reinterpret_cast<size_t>(array.Get()), 0U, reinterpret_cast<size_t>(obj_obj.Get()),
           reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
 
   EXPECT_TRUE(self->IsExceptionPending());
@@ -727,13 +770,6 @@
 #endif
 }
 
-
-#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
-extern "C" void art_quick_alloc_object_rosalloc(void);
-extern "C" void art_quick_alloc_object_resolved_rosalloc(void);
-extern "C" void art_quick_alloc_object_initialized_rosalloc(void);
-#endif
-
 TEST_F(StubTest, AllocObject) {
   TEST_DISABLED_FOR_HEAP_REFERENCE_POISONING();
 
@@ -745,53 +781,53 @@
   ScopedObjectAccess soa(self);
   // garbage is created during ClassLinker::Init
 
-  SirtRef<mirror::Class> c(soa.Self(), class_linker_->FindSystemClass(soa.Self(),
-                                                                      "Ljava/lang/Object;"));
+  StackHandleScope<2> hs(soa.Self());
+  Handle<mirror::Class> c(
+      hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;")));
 
   // Play with it...
 
   EXPECT_FALSE(self->IsExceptionPending());
-
   {
     // Use an arbitrary method from c to use as referrer
     size_t result = Invoke3(static_cast<size_t>(c->GetDexTypeIndex()),    // type_idx
                             reinterpret_cast<size_t>(c->GetVirtualMethod(0)),  // arbitrary
                             0U,
-                            reinterpret_cast<uintptr_t>(&art_quick_alloc_object_rosalloc),
+                            reinterpret_cast<uintptr_t>(GetTlsPtr(self)->quick_entrypoints.pAllocObject),
                             self);
 
     EXPECT_FALSE(self->IsExceptionPending());
     EXPECT_NE(reinterpret_cast<size_t>(nullptr), result);
     mirror::Object* obj = reinterpret_cast<mirror::Object*>(result);
-    EXPECT_EQ(c.get(), obj->GetClass());
+    EXPECT_EQ(c.Get(), obj->GetClass());
     VerifyObject(obj);
   }
 
   {
     // We can use nullptr in the second argument as we do not need a method here (not used in
     // resolved/initialized cases)
-    size_t result = Invoke3(reinterpret_cast<size_t>(c.get()), reinterpret_cast<size_t>(nullptr), 0U,
-                            reinterpret_cast<uintptr_t>(&art_quick_alloc_object_resolved_rosalloc),
+    size_t result = Invoke3(reinterpret_cast<size_t>(c.Get()), reinterpret_cast<size_t>(nullptr), 0U,
+                            reinterpret_cast<uintptr_t>(GetTlsPtr(self)->quick_entrypoints.pAllocObjectResolved),
                             self);
 
     EXPECT_FALSE(self->IsExceptionPending());
     EXPECT_NE(reinterpret_cast<size_t>(nullptr), result);
     mirror::Object* obj = reinterpret_cast<mirror::Object*>(result);
-    EXPECT_EQ(c.get(), obj->GetClass());
+    EXPECT_EQ(c.Get(), obj->GetClass());
     VerifyObject(obj);
   }
 
   {
     // We can use nullptr in the second argument as we do not need a method here (not used in
     // resolved/initialized cases)
-    size_t result = Invoke3(reinterpret_cast<size_t>(c.get()), reinterpret_cast<size_t>(nullptr), 0U,
-                            reinterpret_cast<uintptr_t>(&art_quick_alloc_object_initialized_rosalloc),
+    size_t result = Invoke3(reinterpret_cast<size_t>(c.Get()), reinterpret_cast<size_t>(nullptr), 0U,
+                            reinterpret_cast<uintptr_t>(GetTlsPtr(self)->quick_entrypoints.pAllocObjectInitialized),
                             self);
 
     EXPECT_FALSE(self->IsExceptionPending());
     EXPECT_NE(reinterpret_cast<size_t>(nullptr), result);
     mirror::Object* obj = reinterpret_cast<mirror::Object*>(result);
-    EXPECT_EQ(c.get(), obj->GetClass());
+    EXPECT_EQ(c.Get(), obj->GetClass());
     VerifyObject(obj);
   }
 
@@ -802,19 +838,21 @@
     Runtime::Current()->GetHeap()->SetIdealFootprint(1 * GB);
 
     // Array helps to fill memory faster.
-    SirtRef<mirror::Class> ca(soa.Self(), class_linker_->FindSystemClass(soa.Self(),
-                                                                         "[Ljava/lang/Object;"));
-    std::vector<SirtRef<mirror::Object>*> sirt_refs;
+    Handle<mirror::Class> ca(
+        hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "[Ljava/lang/Object;")));
+
+    // Use arbitrary large amount for now.
+    static const size_t kMaxHandles = 1000000;
+    UniquePtr<StackHandleScope<kMaxHandles> > hsp(new StackHandleScope<kMaxHandles>(self));
+
+    std::vector<Handle<mirror::Object>> handles;
     // Start allocating with 128K
     size_t length = 128 * KB / 4;
     while (length > 10) {
-      SirtRef<mirror::Object>* ref = new SirtRef<mirror::Object>(soa.Self(),
-                                              mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(),
-                                                                                         ca.get(),
-                                                                                         length/4));
-      if (self->IsExceptionPending() || ref->get() == nullptr) {
+      Handle<mirror::Object> h(hsp->NewHandle<mirror::Object>(
+          mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), ca.Get(), length / 4)));
+      if (self->IsExceptionPending() || h.Get() == nullptr) {
         self->ClearException();
-        delete ref;
 
         // Try a smaller length
         length = length / 8;
@@ -824,38 +862,26 @@
           length = mem / 8;
         }
       } else {
-        sirt_refs.push_back(ref);
+        handles.push_back(h);
       }
     }
-    LOG(INFO) << "Used " << sirt_refs.size() << " arrays to fill space.";
+    LOG(INFO) << "Used " << handles.size() << " arrays to fill space.";
 
     // Allocate simple objects till it fails.
     while (!self->IsExceptionPending()) {
-      SirtRef<mirror::Object>* ref = new SirtRef<mirror::Object>(soa.Self(),
-                                                                 c->AllocObject(soa.Self()));
-      if (!self->IsExceptionPending() && ref->get() != nullptr) {
-        sirt_refs.push_back(ref);
-      } else {
-        delete ref;
+      Handle<mirror::Object> h = hsp->NewHandle(c->AllocObject(soa.Self()));
+      if (!self->IsExceptionPending() && h.Get() != nullptr) {
+        handles.push_back(h);
       }
     }
     self->ClearException();
 
-    size_t result = Invoke3(reinterpret_cast<size_t>(c.get()), reinterpret_cast<size_t>(nullptr), 0U,
-                            reinterpret_cast<uintptr_t>(&art_quick_alloc_object_initialized_rosalloc),
+    size_t result = Invoke3(reinterpret_cast<size_t>(c.Get()), reinterpret_cast<size_t>(nullptr), 0U,
+                            reinterpret_cast<uintptr_t>(GetTlsPtr(self)->quick_entrypoints.pAllocObjectInitialized),
                             self);
-
     EXPECT_TRUE(self->IsExceptionPending());
     self->ClearException();
     EXPECT_EQ(reinterpret_cast<size_t>(nullptr), result);
-
-    // Release all the allocated objects.
-    // Need to go backward to release SirtRef in the right order.
-    auto it = sirt_refs.rbegin();
-    auto end = sirt_refs.rend();
-    for (; it != end; ++it) {
-      delete *it;
-    }
   }
 
   // Tests done.
@@ -866,12 +892,6 @@
 #endif
 }
 
-
-#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
-extern "C" void art_quick_alloc_array_rosalloc(void);
-extern "C" void art_quick_alloc_array_resolved_rosalloc(void);
-#endif
-
 TEST_F(StubTest, AllocObjectArray) {
   TEST_DISABLED_FOR_HEAP_REFERENCE_POISONING();
 
@@ -883,12 +903,13 @@
   ScopedObjectAccess soa(self);
   // garbage is created during ClassLinker::Init
 
-  SirtRef<mirror::Class> c(soa.Self(), class_linker_->FindSystemClass(soa.Self(),
-                                                                        "[Ljava/lang/Object;"));
+  StackHandleScope<2> hs(self);
+  Handle<mirror::Class> c(
+      hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "[Ljava/lang/Object;")));
 
   // Needed to have a linked method.
-  SirtRef<mirror::Class> c_obj(soa.Self(), class_linker_->FindSystemClass(soa.Self(),
-                                                                          "Ljava/lang/Object;"));
+  Handle<mirror::Class> c_obj(
+      hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;")));
 
   // Play with it...
 
@@ -902,13 +923,13 @@
     size_t result = Invoke3(static_cast<size_t>(c->GetDexTypeIndex()),    // type_idx
                             reinterpret_cast<size_t>(c_obj->GetVirtualMethod(0)),  // arbitrary
                             10U,
-                            reinterpret_cast<uintptr_t>(&art_quick_alloc_array_rosalloc),
+                            reinterpret_cast<uintptr_t>(GetTlsPtr(self)->quick_entrypoints.pAllocArray),
                             self);
 
     EXPECT_FALSE(self->IsExceptionPending());
     EXPECT_NE(reinterpret_cast<size_t>(nullptr), result);
     mirror::Array* obj = reinterpret_cast<mirror::Array*>(result);
-    EXPECT_EQ(c.get(), obj->GetClass());
+    EXPECT_EQ(c.Get(), obj->GetClass());
     VerifyObject(obj);
     EXPECT_EQ(obj->GetLength(), 10);
   }
@@ -916,16 +937,15 @@
   {
     // We can use nullptr in the second argument as we do not need a method here (not used in
     // resolved/initialized cases)
-    size_t result = Invoke3(reinterpret_cast<size_t>(c.get()), reinterpret_cast<size_t>(nullptr), 10U,
-                            reinterpret_cast<uintptr_t>(&art_quick_alloc_array_resolved_rosalloc),
+    size_t result = Invoke3(reinterpret_cast<size_t>(c.Get()), reinterpret_cast<size_t>(nullptr), 10U,
+                            reinterpret_cast<uintptr_t>(GetTlsPtr(self)->quick_entrypoints.pAllocArrayResolved),
                             self);
-
     EXPECT_FALSE(self->IsExceptionPending()) << PrettyTypeOf(self->GetException(nullptr));
     EXPECT_NE(reinterpret_cast<size_t>(nullptr), result);
     mirror::Object* obj = reinterpret_cast<mirror::Object*>(result);
     EXPECT_TRUE(obj->IsArrayInstance());
     EXPECT_TRUE(obj->IsObjectArray());
-    EXPECT_EQ(c.get(), obj->GetClass());
+    EXPECT_EQ(c.Get(), obj->GetClass());
     VerifyObject(obj);
     mirror::Array* array = reinterpret_cast<mirror::Array*>(result);
     EXPECT_EQ(array->GetLength(), 10);
@@ -935,9 +955,9 @@
 
   // Out-of-memory.
   {
-    size_t result = Invoke3(reinterpret_cast<size_t>(c.get()), reinterpret_cast<size_t>(nullptr),
+    size_t result = Invoke3(reinterpret_cast<size_t>(c.Get()), reinterpret_cast<size_t>(nullptr),
                             GB,  // that should fail...
-                            reinterpret_cast<uintptr_t>(&art_quick_alloc_array_resolved_rosalloc),
+                            reinterpret_cast<uintptr_t>(GetTlsPtr(self)->quick_entrypoints.pAllocArrayResolved),
                             self);
 
     EXPECT_TRUE(self->IsExceptionPending());
@@ -972,32 +992,31 @@
   // Use array so we can index into it and use a matrix for expected results
   // Setup: The first half is standard. The second half uses a non-zero offset.
   // TODO: Shared backing arrays.
-  constexpr size_t base_string_count = 7;
-  const char* c[base_string_count] = { "", "", "a", "aa", "ab", "aac", "aac" , };
+  static constexpr size_t kBaseStringCount  = 7;
+  const char* c[kBaseStringCount] = { "", "", "a", "aa", "ab", "aac", "aac" , };
 
-  constexpr size_t string_count = 2 * base_string_count;
+  static constexpr size_t kStringCount = 2 * kBaseStringCount;
 
-  SirtRef<mirror::String>* s[string_count];
+  StackHandleScope<kStringCount> hs(self);
+  Handle<mirror::String> s[kStringCount];
 
-  for (size_t i = 0; i < base_string_count; ++i) {
-    s[i] = new SirtRef<mirror::String>(soa.Self(), mirror::String::AllocFromModifiedUtf8(soa.Self(),
-                                                                                         c[i]));
+  for (size_t i = 0; i < kBaseStringCount; ++i) {
+    s[i] = hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), c[i]));
   }
 
   RandGen r(0x1234);
 
-  for (size_t i = base_string_count; i < string_count; ++i) {
-    s[i] = new SirtRef<mirror::String>(soa.Self(), mirror::String::AllocFromModifiedUtf8(soa.Self(),
-                                                                         c[i - base_string_count]));
-    int32_t length = s[i]->get()->GetLength();
+  for (size_t i = kBaseStringCount; i < kStringCount; ++i) {
+    s[i] = hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), c[i - kBaseStringCount]));
+    int32_t length = s[i]->GetLength();
     if (length > 1) {
       // Set a random offset and length.
       int32_t new_offset = 1 + (r.next() % (length - 1));
       int32_t rest = length - new_offset - 1;
       int32_t new_length = 1 + (rest > 0 ? r.next() % rest : 0);
 
-      s[i]->get()->SetField32<false>(mirror::String::CountOffset(), new_length);
-      s[i]->get()->SetField32<false>(mirror::String::OffsetOffset(), new_offset);
+      s[i]->SetField32<false>(mirror::String::CountOffset(), new_length);
+      s[i]->SetField32<false>(mirror::String::OffsetOffset(), new_offset);
     }
   }
 
@@ -1006,20 +1025,20 @@
   // Matrix of expectations. First component is first parameter. Note we only check against the
   // sign, not the value. As we are testing random offsets, we need to compute this and need to
   // rely on String::CompareTo being correct.
-  int32_t expected[string_count][string_count];
-  for (size_t x = 0; x < string_count; ++x) {
-    for (size_t y = 0; y < string_count; ++y) {
-      expected[x][y] = s[x]->get()->CompareTo(s[y]->get());
+  int32_t expected[kStringCount][kStringCount];
+  for (size_t x = 0; x < kStringCount; ++x) {
+    for (size_t y = 0; y < kStringCount; ++y) {
+      expected[x][y] = s[x]->CompareTo(s[y].Get());
     }
   }
 
   // Play with it...
 
-  for (size_t x = 0; x < string_count; ++x) {
-    for (size_t y = 0; y < string_count; ++y) {
+  for (size_t x = 0; x < kStringCount; ++x) {
+    for (size_t y = 0; y < kStringCount; ++y) {
       // Test string_compareto x y
-      size_t result = Invoke3(reinterpret_cast<size_t>(s[x]->get()),
-                              reinterpret_cast<size_t>(s[y]->get()), 0U,
+      size_t result = Invoke3(reinterpret_cast<size_t>(s[x].Get()),
+                              reinterpret_cast<size_t>(s[y].Get()), 0U,
                               reinterpret_cast<uintptr_t>(&art_quick_string_compareto), self);
 
       EXPECT_FALSE(self->IsExceptionPending());
@@ -1057,7 +1076,7 @@
 extern "C" void art_quick_get32_static(void);
 #endif
 
-static void GetSet32Static(SirtRef<mirror::Object>* obj, SirtRef<mirror::ArtField>* f, Thread* self,
+static void GetSet32Static(Handle<mirror::Object>* obj, Handle<mirror::ArtField>* f, Thread* self,
                            mirror::ArtMethod* referrer, StubTest* test)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
@@ -1093,7 +1112,7 @@
 extern "C" void art_quick_get32_instance(void);
 #endif
 
-static void GetSet32Instance(SirtRef<mirror::Object>* obj, SirtRef<mirror::ArtField>* f,
+static void GetSet32Instance(Handle<mirror::Object>* obj, Handle<mirror::ArtField>* f,
                              Thread* self, mirror::ArtMethod* referrer, StubTest* test)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
@@ -1102,20 +1121,20 @@
 
   for (size_t i = 0; i < num_values; ++i) {
     test->Invoke3WithReferrer(static_cast<size_t>((*f)->GetDexFieldIndex()),
-                              reinterpret_cast<size_t>(obj->get()),
+                              reinterpret_cast<size_t>(obj->Get()),
                               static_cast<size_t>(values[i]),
                               reinterpret_cast<uintptr_t>(&art_quick_set32_instance),
                               self,
                               referrer);
 
-    int32_t res = f->get()->GetInt(obj->get());
+    int32_t res = f->Get()->GetInt(obj->Get());
     EXPECT_EQ(res, static_cast<int32_t>(values[i])) << "Iteration " << i;
 
     res++;
-    f->get()->SetInt<false>(obj->get(), res);
+    f->Get()->SetInt<false>(obj->Get(), res);
 
     size_t res2 = test->Invoke3WithReferrer(static_cast<size_t>((*f)->GetDexFieldIndex()),
-                                            reinterpret_cast<size_t>(obj->get()),
+                                            reinterpret_cast<size_t>(obj->Get()),
                                             0U,
                                             reinterpret_cast<uintptr_t>(&art_quick_get32_instance),
                                             self,
@@ -1154,7 +1173,7 @@
 }
 #endif
 
-static void GetSetObjStatic(SirtRef<mirror::Object>* obj, SirtRef<mirror::ArtField>* f, Thread* self,
+static void GetSetObjStatic(Handle<mirror::Object>* obj, Handle<mirror::ArtField>* f, Thread* self,
                             mirror::ArtMethod* referrer, StubTest* test)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
@@ -1177,7 +1196,7 @@
 extern "C" void art_quick_set_obj_instance(void);
 extern "C" void art_quick_get_obj_instance(void);
 
-static void set_and_check_instance(SirtRef<mirror::ArtField>* f, mirror::Object* trg,
+static void set_and_check_instance(Handle<mirror::ArtField>* f, mirror::Object* trg,
                                    mirror::Object* val, Thread* self, mirror::ArtMethod* referrer,
                                    StubTest* test)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -1197,21 +1216,21 @@
 
   EXPECT_EQ(res, reinterpret_cast<size_t>(val)) << "Value " << val;
 
-  EXPECT_EQ(val, f->get()->GetObj(trg));
+  EXPECT_EQ(val, f->Get()->GetObj(trg));
 }
 #endif
 
-static void GetSetObjInstance(SirtRef<mirror::Object>* obj, SirtRef<mirror::ArtField>* f,
+static void GetSetObjInstance(Handle<mirror::Object>* obj, Handle<mirror::ArtField>* f,
                               Thread* self, mirror::ArtMethod* referrer, StubTest* test)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
-  set_and_check_instance(f, obj->get(), nullptr, self, referrer, test);
+  set_and_check_instance(f, obj->Get(), nullptr, self, referrer, test);
 
   // Allocate a string object for simplicity.
   mirror::String* str = mirror::String::AllocFromModifiedUtf8(self, "Test");
-  set_and_check_instance(f, obj->get(), str, self, referrer, test);
+  set_and_check_instance(f, obj->Get(), str, self, referrer, test);
 
-  set_and_check_instance(f, obj->get(), nullptr, self, referrer, test);
+  set_and_check_instance(f, obj->Get(), nullptr, self, referrer, test);
 #else
   LOG(INFO) << "Skipping setObjinstance as I don't know how to do that on " << kRuntimeISA;
   // Force-print to std::cout so it's also outside the logcat.
@@ -1227,7 +1246,7 @@
 extern "C" void art_quick_get64_static(void);
 #endif
 
-static void GetSet64Static(SirtRef<mirror::Object>* obj, SirtRef<mirror::ArtField>* f, Thread* self,
+static void GetSet64Static(Handle<mirror::Object>* obj, Handle<mirror::ArtField>* f, Thread* self,
                            mirror::ArtMethod* referrer, StubTest* test)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
 #if defined(__x86_64__) || defined(__aarch64__)
@@ -1262,7 +1281,7 @@
 extern "C" void art_quick_get64_instance(void);
 #endif
 
-static void GetSet64Instance(SirtRef<mirror::Object>* obj, SirtRef<mirror::ArtField>* f,
+static void GetSet64Instance(Handle<mirror::Object>* obj, Handle<mirror::ArtField>* f,
                              Thread* self, mirror::ArtMethod* referrer, StubTest* test)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
 #if defined(__x86_64__) || defined(__aarch64__)
@@ -1271,20 +1290,20 @@
 
   for (size_t i = 0; i < num_values; ++i) {
     test->Invoke3WithReferrer(static_cast<size_t>((*f)->GetDexFieldIndex()),
-                              reinterpret_cast<size_t>(obj->get()),
+                              reinterpret_cast<size_t>(obj->Get()),
                               static_cast<size_t>(values[i]),
                               reinterpret_cast<uintptr_t>(&art_quick_set64_instance),
                               self,
                               referrer);
 
-    int64_t res = f->get()->GetLong(obj->get());
+    int64_t res = f->Get()->GetLong(obj->Get());
     EXPECT_EQ(res, static_cast<int64_t>(values[i])) << "Iteration " << i;
 
     res++;
-    f->get()->SetLong<false>(obj->get(), res);
+    f->Get()->SetLong<false>(obj->Get(), res);
 
     size_t res2 = test->Invoke3WithReferrer(static_cast<size_t>((*f)->GetDexFieldIndex()),
-                                            reinterpret_cast<size_t>(obj->get()),
+                                            reinterpret_cast<size_t>(obj->Get()),
                                             0U,
                                             reinterpret_cast<uintptr_t>(&art_quick_get64_instance),
                                             self,
@@ -1308,41 +1327,41 @@
   CHECK(o != NULL);
 
   ScopedObjectAccess soa(self);
-  SirtRef<mirror::Object> obj(self, soa.Decode<mirror::Object*>(o));
-
-  SirtRef<mirror::Class> c(self, obj->GetClass());
-
+  StackHandleScope<5> hs(self);
+  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
-  SirtRef<mirror::ArtMethod> m(self, c->GetDirectMethod(0));
+  Handle<mirror::ArtMethod> m(hs.NewHandle(c->GetDirectMethod(0)));
 
   // Play with it...
 
   // Static fields.
   {
-    SirtRef<mirror::ObjectArray<mirror::ArtField>> fields(self, c.get()->GetSFields());
+    Handle<mirror::ObjectArray<mirror::ArtField>> fields(hs.NewHandle(c.Get()->GetSFields()));
     int32_t num_fields = fields->GetLength();
     for (int32_t i = 0; i < num_fields; ++i) {
-      SirtRef<mirror::ArtField> f(self, fields->Get(i));
+      StackHandleScope<1> hs(self);
+      Handle<mirror::ArtField> f(hs.NewHandle(fields->Get(i)));
 
-      FieldHelper fh(f.get());
+      FieldHelper fh(f.Get());
       Primitive::Type type = fh.GetTypeAsPrimitiveType();
       switch (type) {
         case Primitive::Type::kPrimInt:
           if (test_type == type) {
-            GetSet32Static(&obj, &f, self, m.get(), test);
+            GetSet32Static(&obj, &f, self, m.Get(), test);
           }
           break;
 
         case Primitive::Type::kPrimLong:
           if (test_type == type) {
-            GetSet64Static(&obj, &f, self, m.get(), test);
+            GetSet64Static(&obj, &f, self, m.Get(), test);
           }
           break;
 
         case Primitive::Type::kPrimNot:
           // Don't try array.
           if (test_type == type && fh.GetTypeDescriptor()[0] != '[') {
-            GetSetObjStatic(&obj, &f, self, m.get(), test);
+            GetSetObjStatic(&obj, &f, self, m.Get(), test);
           }
           break;
 
@@ -1354,30 +1373,31 @@
 
   // Instance fields.
   {
-    SirtRef<mirror::ObjectArray<mirror::ArtField>> fields(self, c.get()->GetIFields());
+    Handle<mirror::ObjectArray<mirror::ArtField>> fields(hs.NewHandle(c.Get()->GetIFields()));
     int32_t num_fields = fields->GetLength();
     for (int32_t i = 0; i < num_fields; ++i) {
-      SirtRef<mirror::ArtField> f(self, fields->Get(i));
+      StackHandleScope<1> hs(self);
+      Handle<mirror::ArtField> f(hs.NewHandle(fields->Get(i)));
 
-      FieldHelper fh(f.get());
+      FieldHelper fh(f.Get());
       Primitive::Type type = fh.GetTypeAsPrimitiveType();
       switch (type) {
         case Primitive::Type::kPrimInt:
           if (test_type == type) {
-            GetSet32Instance(&obj, &f, self, m.get(), test);
+            GetSet32Instance(&obj, &f, self, m.Get(), test);
           }
           break;
 
         case Primitive::Type::kPrimLong:
           if (test_type == type) {
-            GetSet64Instance(&obj, &f, self, m.get(), test);
+            GetSet64Instance(&obj, &f, self, m.Get(), test);
           }
           break;
 
         case Primitive::Type::kPrimNot:
           // Don't try array.
           if (test_type == type && fh.GetTypeDescriptor()[0] != '[') {
-            GetSetObjInstance(&obj, &f, self, m.get(), test);
+            GetSetObjInstance(&obj, &f, self, m.Get(), test);
           }
           break;
 
diff --git a/runtime/arch/x86/context_x86.cc b/runtime/arch/x86/context_x86.cc
index c68d76a..8c98d91 100644
--- a/runtime/arch/x86/context_x86.cc
+++ b/runtime/arch/x86/context_x86.cc
@@ -16,8 +16,9 @@
 
 #include "context_x86.h"
 
-#include "mirror/art_method.h"
+#include "mirror/art_method-inl.h"
 #include "mirror/object-inl.h"
+#include "quick/quick_method_frame_info.h"
 #include "stack.h"
 
 namespace art {
@@ -37,16 +38,15 @@
 
 void X86Context::FillCalleeSaves(const StackVisitor& fr) {
   mirror::ArtMethod* method = fr.GetMethod();
-  uint32_t core_spills = method->GetCoreSpillMask();
-  size_t spill_count = POPCOUNT(core_spills);
-  DCHECK_EQ(method->GetFpSpillMask(), 0u);
-  size_t frame_size = method->GetFrameSizeInBytes();
+  const QuickMethodFrameInfo frame_info = method->GetQuickFrameInfo();
+  size_t spill_count = POPCOUNT(frame_info.CoreSpillMask());
+  DCHECK_EQ(frame_info.FpSpillMask(), 0u);
   if (spill_count > 0) {
     // Lowest number spill is farthest away, walk registers and fill into context.
     int j = 2;  // Offset j to skip return address spill.
     for (int i = 0; i < kNumberOfCpuRegisters; i++) {
-      if (((core_spills >> i) & 1) != 0) {
-        gprs_[i] = fr.CalleeSaveAddress(spill_count - j, frame_size);
+      if (((frame_info.CoreSpillMask() >> i) & 1) != 0) {
+        gprs_[i] = fr.CalleeSaveAddress(spill_count - j, frame_info.FrameSizeInBytes());
         j++;
       }
     }
diff --git a/runtime/arch/x86/quick_method_frame_info_x86.h b/runtime/arch/x86/quick_method_frame_info_x86.h
new file mode 100644
index 0000000..b9dc0d8
--- /dev/null
+++ b/runtime/arch/x86/quick_method_frame_info_x86.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2014 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_ARCH_X86_QUICK_METHOD_FRAME_INFO_X86_H_
+#define ART_RUNTIME_ARCH_X86_QUICK_METHOD_FRAME_INFO_X86_H_
+
+#include "quick/quick_method_frame_info.h"
+#include "registers_x86.h"
+#include "runtime.h"  // for Runtime::CalleeSaveType.
+
+namespace art {
+namespace x86 {
+
+static constexpr uint32_t kX86CalleeSaveRefSpills =
+    (1 << art::x86::EBP) | (1 << art::x86::ESI) | (1 << art::x86::EDI);
+static constexpr uint32_t kX86CalleeSaveArgSpills =
+    (1 << art::x86::ECX) | (1 << art::x86::EDX) | (1 << art::x86::EBX);
+
+constexpr uint32_t X86CalleeSaveCoreSpills(Runtime::CalleeSaveType type) {
+  return kX86CalleeSaveRefSpills | (type == Runtime::kRefsAndArgs ? kX86CalleeSaveArgSpills : 0) |
+      (1 << art::x86::kNumberOfCpuRegisters);  // fake return address callee save
+}
+
+constexpr uint32_t X86CalleeSaveFrameSize(Runtime::CalleeSaveType type) {
+  return RoundUp((POPCOUNT(X86CalleeSaveCoreSpills(type)) /* gprs */ +
+                  1 /* Method* */) * kX86PointerSize, kStackAlignment);
+}
+
+constexpr QuickMethodFrameInfo X86CalleeSaveMethodFrameInfo(Runtime::CalleeSaveType type) {
+  return QuickMethodFrameInfo(X86CalleeSaveFrameSize(type),
+                              X86CalleeSaveCoreSpills(type),
+                              0u);
+}
+
+}  // namespace x86
+}  // namespace art
+
+#endif  // ART_RUNTIME_ARCH_X86_QUICK_METHOD_FRAME_INFO_X86_H_
diff --git a/runtime/arch/x86_64/context_x86_64.cc b/runtime/arch/x86_64/context_x86_64.cc
index 29a7065..810ef94 100644
--- a/runtime/arch/x86_64/context_x86_64.cc
+++ b/runtime/arch/x86_64/context_x86_64.cc
@@ -16,8 +16,9 @@
 
 #include "context_x86_64.h"
 
-#include "mirror/art_method.h"
+#include "mirror/art_method-inl.h"
 #include "mirror/object-inl.h"
+#include "quick/quick_method_frame_info.h"
 #include "stack.h"
 
 namespace art {
@@ -40,17 +41,15 @@
 
 void X86_64Context::FillCalleeSaves(const StackVisitor& fr) {
   mirror::ArtMethod* method = fr.GetMethod();
-  uint32_t core_spills = method->GetCoreSpillMask();
-  uint32_t fp_core_spills = method->GetFpSpillMask();
-  size_t spill_count = POPCOUNT(core_spills);
-  size_t fp_spill_count = POPCOUNT(fp_core_spills);
-  size_t frame_size = method->GetFrameSizeInBytes();
+  const QuickMethodFrameInfo frame_info = method->GetQuickFrameInfo();
+  size_t spill_count = POPCOUNT(frame_info.CoreSpillMask());
+  size_t fp_spill_count = POPCOUNT(frame_info.FpSpillMask());
   if (spill_count > 0) {
     // Lowest number spill is farthest away, walk registers and fill into context.
     size_t j = 2;  // Offset j to skip return address spill.
     for (size_t i = 0; i < kNumberOfCpuRegisters; ++i) {
-      if (((core_spills >> i) & 1) != 0) {
-        gprs_[i] = fr.CalleeSaveAddress(spill_count - j, frame_size);
+      if (((frame_info.CoreSpillMask() >> i) & 1) != 0) {
+        gprs_[i] = fr.CalleeSaveAddress(spill_count - j, frame_info.FrameSizeInBytes());
         j++;
       }
     }
@@ -59,8 +58,9 @@
     // Lowest number spill is farthest away, walk registers and fill into context.
     size_t j = 2;  // Offset j to skip return address spill.
     for (size_t i = 0; i < kNumberOfFloatRegisters; ++i) {
-      if (((fp_core_spills >> i) & 1) != 0) {
-        fprs_[i] = fr.CalleeSaveAddress(spill_count + fp_spill_count - j, frame_size);
+      if (((frame_info.FpSpillMask() >> i) & 1) != 0) {
+        fprs_[i] = fr.CalleeSaveAddress(spill_count + fp_spill_count - j,
+                                        frame_info.FrameSizeInBytes());
         j++;
       }
     }
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index a55dbb6..9c86c75 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -476,7 +476,6 @@
 
 MACRO3(NO_ARG_DOWNCALL, c_name, cxx_name, return_macro)
     DEFINE_FUNCTION VAR(c_name, 0)
-    UNTESTED
     SETUP_REF_ONLY_CALLEE_SAVE_FRAME  // save ref containing registers for GC
     // Outgoing argument set up
     movq %rsp, %rsi                   // pass SP
@@ -489,7 +488,6 @@
 
 MACRO3(ONE_ARG_DOWNCALL, c_name, cxx_name, return_macro)
     DEFINE_FUNCTION VAR(c_name, 0)
-    UNTESTED
     SETUP_REF_ONLY_CALLEE_SAVE_FRAME   // save ref containing registers for GC
     // Outgoing argument set up
     movq %rsp, %rdx                    // pass SP
@@ -697,8 +695,8 @@
     jz   .Lslow_unlock
     movl LOCK_WORD_OFFSET(%edi), %ecx     // ecx := lock word
     movl %gs:THREAD_ID_OFFSET, %edx       // edx := thread id
-    test %ecx, %ecx
-    jb   .Lslow_unlock                    // lock word contains a monitor
+    test LITERAL(0xC0000000), %ecx
+    jnz  .Lslow_unlock                    // lock word contains a monitor
     cmpw %cx, %dx                         // does the thread id match?
     jne  .Lslow_unlock
     cmpl LITERAL(65536), %ecx
@@ -995,7 +993,6 @@
     jz 1f
     jmp *%r10                     // Tail call into method.
 1:
-    RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
     DELIVER_PENDING_EXCEPTION
 END_FUNCTION art_quick_resolution_trampoline
 
@@ -1053,12 +1050,12 @@
  * | Return            |
  * | Callee-Save Data  |
  * #-------------------#
- * | SIRT              |
+ * | handle scope      |
  * #-------------------#
  * | Method*           |    <--- (1)
  * #-------------------#
  * | local ref cookie  | // 4B
- * | SIRT size         | // 4B   TODO: roll into call stack alignment?
+ * | handle scope size | // 4B   TODO: roll into call stack alignment?
  * #-------------------#
  * | JNI Call Stack    |
  * #-------------------#    <--- SP on native call
@@ -1111,8 +1108,8 @@
     //
     //      4    local state ref
     //      4    padding
-    //   4196    4k scratch space, enough for 2x 256 8-byte parameters (TODO: SIRT overhead?)
-    //     16    SIRT member fields ?
+    //   4196    4k scratch space, enough for 2x 256 8-byte parameters (TODO: handle scope overhead?)
+    //     16    handle scope member fields ?
     // +  112    14x 8-byte stack-2-register space
     // ------
     //   4332
@@ -1217,7 +1214,7 @@
     movq %rbx, %rsp
     CFI_DEF_CFA_REGISTER(rsp)
 .Lexception_in_native:
-    // TODO: the SIRT contains the this pointer which is used by the debugger for exception
+    // TODO: the handle scope contains the this pointer which is used by the debugger for exception
     //       delivery.
     movq %xmm0, 16(%rsp)         // doesn't make sense!!!
     movq 24(%rsp), %xmm1            // neither does this!!!
diff --git a/runtime/arch/x86_64/quick_method_frame_info_x86_64.h b/runtime/arch/x86_64/quick_method_frame_info_x86_64.h
new file mode 100644
index 0000000..6183909
--- /dev/null
+++ b/runtime/arch/x86_64/quick_method_frame_info_x86_64.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2014 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_ARCH_X86_64_QUICK_METHOD_FRAME_INFO_X86_64_H_
+#define ART_RUNTIME_ARCH_X86_64_QUICK_METHOD_FRAME_INFO_X86_64_H_
+
+#include "quick/quick_method_frame_info.h"
+#include "registers_x86_64.h"
+#include "runtime.h"  // for Runtime::CalleeSaveType.
+
+namespace art {
+namespace x86_64 {
+
+static constexpr uint32_t kX86_64CalleeSaveRefSpills =
+    (1 << art::x86_64::RBX) | (1 << art::x86_64::RBP) | (1 << art::x86_64::R12) |
+    (1 << art::x86_64::R13) | (1 << art::x86_64::R14) | (1 << art::x86_64::R15);
+static constexpr uint32_t kX86_64CalleeSaveArgSpills =
+    (1 << art::x86_64::RSI) | (1 << art::x86_64::RDX) | (1 << art::x86_64::RCX) |
+    (1 << art::x86_64::R8) | (1 << art::x86_64::R9);
+static constexpr uint32_t kX86_64CalleeSaveFpArgSpills =
+    (1 << art::x86_64::XMM0) | (1 << art::x86_64::XMM1) | (1 << art::x86_64::XMM2) |
+    (1 << art::x86_64::XMM3) | (1 << art::x86_64::XMM4) | (1 << art::x86_64::XMM5) |
+    (1 << art::x86_64::XMM6) | (1 << art::x86_64::XMM7);
+
+constexpr uint32_t X86_64CalleeSaveCoreSpills(Runtime::CalleeSaveType type) {
+  return kX86_64CalleeSaveRefSpills |
+      (type == Runtime::kRefsAndArgs ? kX86_64CalleeSaveArgSpills : 0) |
+      (1 << art::x86_64::kNumberOfCpuRegisters);  // fake return address callee save;
+}
+
+constexpr uint32_t X86_64CalleeSaveFpSpills(Runtime::CalleeSaveType type) {
+  return (type == Runtime::kRefsAndArgs ? kX86_64CalleeSaveFpArgSpills : 0);
+}
+
+constexpr uint32_t X86_64CalleeSaveFrameSize(Runtime::CalleeSaveType type) {
+  return RoundUp((POPCOUNT(X86_64CalleeSaveCoreSpills(type)) /* gprs */ +
+                  POPCOUNT(X86_64CalleeSaveFpSpills(type)) /* fprs */ +
+                  1 /* Method* */) * kX86_64PointerSize, kStackAlignment);
+}
+
+constexpr QuickMethodFrameInfo X86_64CalleeSaveMethodFrameInfo(Runtime::CalleeSaveType type) {
+  return QuickMethodFrameInfo(X86_64CalleeSaveFrameSize(type),
+                              X86_64CalleeSaveCoreSpills(type),
+                              X86_64CalleeSaveFpSpills(type));
+}
+
+}  // namespace x86_64
+}  // namespace art
+
+#endif  // ART_RUNTIME_ARCH_X86_64_QUICK_METHOD_FRAME_INFO_X86_64_H_
diff --git a/runtime/base/bit_vector.cc b/runtime/base/bit_vector.cc
index 0e01dc2..a3e2b15 100644
--- a/runtime/base/bit_vector.cc
+++ b/runtime/base/bit_vector.cc
@@ -399,13 +399,13 @@
   return count;
 }
 
-void BitVector::Dump(std::ostream& os, const char *prefix) {
+void BitVector::Dump(std::ostream& os, const char *prefix) const {
   std::ostringstream buffer;
   DumpHelper(buffer, prefix);
   os << buffer.str() << std::endl;
 }
 
-void BitVector::DumpDot(FILE* file, const char* prefix, bool last_entry) {
+void BitVector::DumpDot(FILE* file, const char* prefix, bool last_entry) const {
   std::ostringstream buffer;
   Dump(buffer, prefix);
 
@@ -421,7 +421,7 @@
   fprintf(file, "\\\n");
 }
 
-void BitVector::DumpHelper(std::ostringstream& buffer, const char* prefix) {
+void BitVector::DumpHelper(std::ostringstream& buffer, const char* prefix) const {
   // Initialize it.
   if (prefix != nullptr) {
     buffer << prefix;
diff --git a/runtime/base/bit_vector.h b/runtime/base/bit_vector.h
index 6ee6b00..2a68396 100644
--- a/runtime/base/bit_vector.h
+++ b/runtime/base/bit_vector.h
@@ -148,11 +148,11 @@
 
     bool EnsureSizeAndClear(unsigned int num);
 
-    void Dump(std::ostream& os, const char* prefix);
-    void DumpDot(FILE* file, const char* prefix, bool last_entry = false);
+    void Dump(std::ostream& os, const char* prefix) const;
+    void DumpDot(FILE* file, const char* prefix, bool last_entry = false) const;
 
   protected:
-    void DumpHelper(std::ostringstream& buffer, const char* prefix);
+    void DumpHelper(std::ostringstream& buffer, const char* prefix) const;
 
   private:
     Allocator* const allocator_;
diff --git a/runtime/catch_block_stack_visitor.cc b/runtime/catch_block_stack_visitor.cc
index 8d10a97..55b330a 100644
--- a/runtime/catch_block_stack_visitor.cc
+++ b/runtime/catch_block_stack_visitor.cc
@@ -19,7 +19,7 @@
 #include "dex_instruction.h"
 #include "mirror/art_method-inl.h"
 #include "quick_exception_handler.h"
-#include "sirt_ref.h"
+#include "handle_scope-inl.h"
 #include "verifier/method_verifier.h"
 
 namespace art {
@@ -50,7 +50,17 @@
   }
   if (dex_pc != DexFile::kDexNoIndex) {
     bool clear_exception = false;
-    uint32_t found_dex_pc = method->FindCatchBlock(to_find_, dex_pc, &clear_exception);
+    bool exc_changed = false;
+    StackHandleScope<1> hs(Thread::Current());
+    Handle<mirror::Class> to_find(hs.NewHandle((*exception_)->GetClass()));
+    uint32_t found_dex_pc = method->FindCatchBlock(to_find, dex_pc, &clear_exception,
+                                                   &exc_changed);
+    if (UNLIKELY(exc_changed)) {
+      DCHECK_EQ(DexFile::kDexNoIndex, found_dex_pc);
+      exception_->Assign(self_->GetException(nullptr));  // TODO: Throw location?
+      // There is a new context installed, delete it.
+      delete self_->GetLongJumpContext();
+    }
     exception_handler_->SetClearException(clear_exception);
     if (found_dex_pc != DexFile::kDexNoIndex) {
       exception_handler_->SetHandlerDexPc(found_dex_pc);
diff --git a/runtime/catch_block_stack_visitor.h b/runtime/catch_block_stack_visitor.h
index 6f0fe11..f45cf03 100644
--- a/runtime/catch_block_stack_visitor.h
+++ b/runtime/catch_block_stack_visitor.h
@@ -19,7 +19,7 @@
 
 #include "mirror/object-inl.h"
 #include "stack.h"
-#include "sirt_ref-inl.h"
+#include "handle_scope-inl.h"
 
 namespace art {
 
@@ -34,10 +34,10 @@
 // Finds catch handler or prepares deoptimization.
 class CatchBlockStackVisitor FINAL : public StackVisitor {
  public:
-  CatchBlockStackVisitor(Thread* self, Context* context, SirtRef<mirror::Throwable>& exception,
+  CatchBlockStackVisitor(Thread* self, Context* context, Handle<mirror::Throwable>* exception,
                          QuickExceptionHandler* exception_handler)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-      : StackVisitor(self, context), self_(self), to_find_(self, exception->GetClass()),
+      : StackVisitor(self, context), self_(self), exception_(exception),
         exception_handler_(exception_handler) {
   }
 
@@ -48,7 +48,7 @@
 
   Thread* const self_;
   // The type of the exception catch block to find.
-  SirtRef<mirror::Class> to_find_;
+  Handle<mirror::Throwable>* exception_;
   QuickExceptionHandler* const exception_handler_;
 
   DISALLOW_COPY_AND_ASSIGN(CatchBlockStackVisitor);
diff --git a/runtime/check_jni.cc b/runtime/check_jni.cc
index 3df050e..cfd0c00 100644
--- a/runtime/check_jni.cc
+++ b/runtime/check_jni.cc
@@ -86,9 +86,9 @@
  * ===========================================================================
  */
 
-static bool IsSirtLocalRef(JNIEnv* env, jobject localRef) {
-  return GetIndirectRefKind(localRef) == kSirtOrInvalid &&
-      reinterpret_cast<JNIEnvExt*>(env)->self->SirtContains(localRef);
+static bool IsHandleScopeLocalRef(JNIEnv* env, jobject localRef) {
+  return GetIndirectRefKind(localRef) == kHandleScopeOrInvalid &&
+      reinterpret_cast<JNIEnvExt*>(env)->self->HandleScopeContains(localRef);
 }
 
 // Flags passed into ScopedCheck.
@@ -179,7 +179,7 @@
   // times, so using "java.lang.Thread" instead of "java/lang/Thread" might work in some
   // circumstances, but this is incorrect.
   void CheckClassName(const char* class_name) {
-    if (!IsValidJniClassName(class_name)) {
+    if ((class_name == nullptr) || !IsValidJniClassName(class_name)) {
       JniAbortF(function_name_,
                 "illegal class name '%s'\n"
                 "    (should be of the form 'package/Class', [Lpackage/Class;' or '[[B')",
@@ -1243,7 +1243,7 @@
 
   static void DeleteLocalRef(JNIEnv* env, jobject localRef) {
     CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, localRef);
-    if (localRef != nullptr && GetIndirectRefKind(localRef) != kLocal && !IsSirtLocalRef(env, localRef)) {
+    if (localRef != nullptr && GetIndirectRefKind(localRef) != kLocal && !IsHandleScopeLocalRef(env, localRef)) {
       JniAbortF(__FUNCTION__, "DeleteLocalRef on %s: %p",
                 ToStr<IndirectRefKind>(GetIndirectRefKind(localRef)).c_str(), localRef);
     } else {
diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h
index df88794..ce634e0 100644
--- a/runtime/class_linker-inl.h
+++ b/runtime/class_linker-inl.h
@@ -24,7 +24,7 @@
 #include "mirror/iftable.h"
 #include "mirror/object_array.h"
 #include "object_utils.h"
-#include "sirt_ref-inl.h"
+#include "handle_scope-inl.h"
 
 namespace art {
 
@@ -34,7 +34,8 @@
 }
 
 inline mirror::Class* ClassLinker::FindSystemClass(Thread* self, const char* descriptor) {
-  SirtRef<mirror::ClassLoader> class_loader(self, nullptr);
+  StackHandleScope<1> hs(self);
+  auto class_loader = hs.NewHandle<mirror::ClassLoader>(nullptr);
   return FindClass(self, descriptor, class_loader);
 }
 
@@ -49,7 +50,8 @@
   DCHECK(!element_class->IsPrimitiveVoid());
   std::string descriptor("[");
   descriptor += ClassHelper(element_class).GetDescriptor();
-  SirtRef<mirror::ClassLoader> class_loader(self, element_class->GetClassLoader());
+  StackHandleScope<1> hs(Thread::Current());
+  Handle<mirror::ClassLoader> class_loader(hs.NewHandle(element_class->GetClassLoader()));
   mirror::Class* array_class = FindClass(self, descriptor.c_str(), class_loader);
   // Benign races in storing array class and incrementing index.
   size_t victim_index = find_array_class_cache_next_victim_;
@@ -63,7 +65,8 @@
   mirror::String* resolved_string = referrer->GetDexCacheStrings()->Get(string_idx);
   if (UNLIKELY(resolved_string == NULL)) {
     mirror::Class* declaring_class = referrer->GetDeclaringClass();
-    SirtRef<mirror::DexCache> dex_cache(Thread::Current(), declaring_class->GetDexCache());
+    StackHandleScope<1> hs(Thread::Current());
+    Handle<mirror::DexCache> dex_cache(hs.NewHandle(declaring_class->GetDexCache()));
     const DexFile& dex_file = *dex_cache->GetDexFile();
     resolved_string = ResolveString(dex_file, string_idx, dex_cache);
     if (resolved_string != nullptr) {
@@ -76,11 +79,11 @@
 inline mirror::Class* ClassLinker::ResolveType(uint16_t type_idx,
                                                mirror::ArtMethod* referrer) {
   mirror::Class* resolved_type = referrer->GetDexCacheResolvedTypes()->Get(type_idx);
-  if (UNLIKELY(resolved_type == NULL)) {
+  if (UNLIKELY(resolved_type == nullptr)) {
     mirror::Class* declaring_class = referrer->GetDeclaringClass();
-    Thread* self = Thread::Current();
-    SirtRef<mirror::DexCache> dex_cache(self, declaring_class->GetDexCache());
-    SirtRef<mirror::ClassLoader> class_loader(self, declaring_class->GetClassLoader());
+    StackHandleScope<2> hs(Thread::Current());
+    Handle<mirror::DexCache> dex_cache(hs.NewHandle(declaring_class->GetDexCache()));
+    Handle<mirror::ClassLoader> class_loader(hs.NewHandle(declaring_class->GetClassLoader()));
     const DexFile& dex_file = *dex_cache->GetDexFile();
     resolved_type = ResolveType(dex_file, type_idx, dex_cache, class_loader);
     if (resolved_type != nullptr) {
@@ -95,9 +98,9 @@
   mirror::DexCache* dex_cache_ptr = declaring_class->GetDexCache();
   mirror::Class* resolved_type = dex_cache_ptr->GetResolvedType(type_idx);
   if (UNLIKELY(resolved_type == NULL)) {
-    Thread* self = Thread::Current();
-    SirtRef<mirror::DexCache> dex_cache(self, dex_cache_ptr);
-    SirtRef<mirror::ClassLoader> class_loader(self, declaring_class->GetClassLoader());
+    StackHandleScope<2> hs(Thread::Current());
+    Handle<mirror::DexCache> dex_cache(hs.NewHandle(dex_cache_ptr));
+    Handle<mirror::ClassLoader> class_loader(hs.NewHandle(declaring_class->GetClassLoader()));
     const DexFile& dex_file = *dex_cache->GetDexFile();
     resolved_type = ResolveType(dex_file, type_idx, dex_cache, class_loader);
     if (resolved_type != nullptr) {
@@ -114,9 +117,9 @@
       referrer->GetDexCacheResolvedMethods()->Get(method_idx);
   if (UNLIKELY(resolved_method == NULL || resolved_method->IsRuntimeMethod())) {
     mirror::Class* declaring_class = referrer->GetDeclaringClass();
-    Thread* self = Thread::Current();
-    SirtRef<mirror::DexCache> dex_cache(self, declaring_class->GetDexCache());
-    SirtRef<mirror::ClassLoader> class_loader(self, declaring_class->GetClassLoader());
+    StackHandleScope<2> hs(Thread::Current());
+    Handle<mirror::DexCache> dex_cache(hs.NewHandle(declaring_class->GetDexCache()));
+    Handle<mirror::ClassLoader> class_loader(hs.NewHandle(declaring_class->GetClassLoader()));
     const DexFile& dex_file = *dex_cache->GetDexFile();
     resolved_method = ResolveMethod(dex_file, method_idx, dex_cache, class_loader, referrer, type);
     if (resolved_method != nullptr) {
@@ -133,9 +136,9 @@
   mirror::ArtField* resolved_field =
       declaring_class->GetDexCache()->GetResolvedField(field_idx);
   if (UNLIKELY(resolved_field == NULL)) {
-    Thread* self = Thread::Current();
-    SirtRef<mirror::DexCache>  dex_cache(self, declaring_class->GetDexCache());
-    SirtRef<mirror::ClassLoader> class_loader(self, declaring_class->GetClassLoader());
+    StackHandleScope<2> hs(Thread::Current());
+    Handle<mirror::DexCache> dex_cache(hs.NewHandle(declaring_class->GetDexCache()));
+    Handle<mirror::ClassLoader> class_loader(hs.NewHandle(declaring_class->GetClassLoader()));
     const DexFile& dex_file = *dex_cache->GetDexFile();
     resolved_field = ResolveField(dex_file, field_idx, dex_cache, class_loader, is_static);
     if (resolved_field != nullptr) {
@@ -174,9 +177,8 @@
 
 inline mirror::ObjectArray<mirror::ArtField>* ClassLinker::AllocArtFieldArray(Thread* self,
                                                                               size_t length) {
-  return mirror::ObjectArray<mirror::ArtField>::Alloc(self,
-                                                      GetClassRoot(kJavaLangReflectArtFieldArrayClass),
-                                                      length);
+  return mirror::ObjectArray<mirror::ArtField>::Alloc(
+      self, GetClassRoot(kJavaLangReflectArtFieldArrayClass), length);
 }
 
 inline mirror::Class* ClassLinker::GetClassRoot(ClassRoot class_root)
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index e3c162b..9034560 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -37,6 +37,7 @@
 #include "gc/accounting/heap_bitmap.h"
 #include "gc/heap.h"
 #include "gc/space/image_space.h"
+#include "handle_scope.h"
 #include "intern_table.h"
 #include "interpreter/interpreter.h"
 #include "leb128.h"
@@ -59,8 +60,7 @@
 #include "entrypoints/entrypoint_utils.h"
 #include "ScopedLocalRef.h"
 #include "scoped_thread_state_change.h"
-#include "sirt_ref.h"
-#include "stack_indirect_reference_table.h"
+#include "handle_scope-inl.h"
 #include "thread.h"
 #include "UniquePtr.h"
 #include "utils.h"
@@ -202,11 +202,12 @@
   gc::Heap* heap = Runtime::Current()->GetHeap();
   // The GC can't handle an object with a null class since we can't get the size of this object.
   heap->IncrementDisableMovingGC(self);
-  SirtRef<mirror::Class> java_lang_Class(self, down_cast<mirror::Class*>(
-      heap->AllocNonMovableObject<true>(self, nullptr, sizeof(mirror::ClassClass), VoidFunctor())));
-  CHECK(java_lang_Class.get() != NULL);
-  mirror::Class::SetClassClass(java_lang_Class.get());
-  java_lang_Class->SetClass(java_lang_Class.get());
+  StackHandleScope<64> hs(self);  // 64 is picked arbitrarily.
+  Handle<mirror::Class> java_lang_Class(hs.NewHandle(down_cast<mirror::Class*>(
+      heap->AllocNonMovableObject<true>(self, nullptr, sizeof(mirror::ClassClass), VoidFunctor()))));
+  CHECK(java_lang_Class.Get() != NULL);
+  mirror::Class::SetClassClass(java_lang_Class.Get());
+  java_lang_Class->SetClass(java_lang_Class.Get());
   if (kUseBakerOrBrooksReadBarrier) {
     java_lang_Class->AssertReadBarrierPointer();
   }
@@ -215,44 +216,47 @@
   // AllocClass(mirror::Class*) can now be used
 
   // Class[] is used for reflection support.
-  SirtRef<mirror::Class> class_array_class(self, AllocClass(self, java_lang_Class.get(), sizeof(mirror::Class)));
-  class_array_class->SetComponentType(java_lang_Class.get());
+  Handle<mirror::Class> class_array_class(
+      hs.NewHandle(AllocClass(self, java_lang_Class.Get(), sizeof(mirror::Class))));
+  class_array_class->SetComponentType(java_lang_Class.Get());
 
   // java_lang_Object comes next so that object_array_class can be created.
-  SirtRef<mirror::Class> java_lang_Object(self, AllocClass(self, java_lang_Class.get(), sizeof(mirror::Class)));
-  CHECK(java_lang_Object.get() != NULL);
+  Handle<mirror::Class> java_lang_Object(
+      hs.NewHandle(AllocClass(self, java_lang_Class.Get(), sizeof(mirror::Class))));
+  CHECK(java_lang_Object.Get() != NULL);
   // backfill Object as the super class of Class.
-  java_lang_Class->SetSuperClass(java_lang_Object.get());
+  java_lang_Class->SetSuperClass(java_lang_Object.Get());
   java_lang_Object->SetStatus(mirror::Class::kStatusLoaded, self);
 
   // Object[] next to hold class roots.
-  SirtRef<mirror::Class> object_array_class(self, AllocClass(self, java_lang_Class.get(), sizeof(mirror::Class)));
-  object_array_class->SetComponentType(java_lang_Object.get());
+  Handle<mirror::Class> object_array_class(
+      hs.NewHandle(AllocClass(self, java_lang_Class.Get(), sizeof(mirror::Class))));
+  object_array_class->SetComponentType(java_lang_Object.Get());
 
   // Setup the char class to be used for char[].
-  SirtRef<mirror::Class> char_class(self, AllocClass(self, java_lang_Class.get(), sizeof(mirror::Class)));
+  Handle<mirror::Class> char_class(hs.NewHandle(AllocClass(self, java_lang_Class.Get(), sizeof(mirror::Class))));
 
   // Setup the char[] class to be used for String.
-  SirtRef<mirror::Class> char_array_class(self, AllocClass(self, java_lang_Class.get(), sizeof(mirror::Class)));
-  char_array_class->SetComponentType(char_class.get());
-  mirror::CharArray::SetArrayClass(char_array_class.get());
+  Handle<mirror::Class> char_array_class(hs.NewHandle(AllocClass(self, java_lang_Class.Get(), sizeof(mirror::Class))));
+  char_array_class->SetComponentType(char_class.Get());
+  mirror::CharArray::SetArrayClass(char_array_class.Get());
 
   // Setup String.
-  SirtRef<mirror::Class> java_lang_String(self, AllocClass(self, java_lang_Class.get(), sizeof(mirror::StringClass)));
-  mirror::String::SetClass(java_lang_String.get());
+  Handle<mirror::Class> java_lang_String(hs.NewHandle(AllocClass(self, java_lang_Class.Get(), sizeof(mirror::StringClass))));
+  mirror::String::SetClass(java_lang_String.Get());
   java_lang_String->SetObjectSize(sizeof(mirror::String));
   java_lang_String->SetStatus(mirror::Class::kStatusResolved, self);
 
   // Create storage for root classes, save away our work so far (requires descriptors).
-  class_roots_ = mirror::ObjectArray<mirror::Class>::Alloc(self, object_array_class.get(),
+  class_roots_ = mirror::ObjectArray<mirror::Class>::Alloc(self, object_array_class.Get(),
                                                            kClassRootsMax);
   CHECK(class_roots_ != NULL);
-  SetClassRoot(kJavaLangClass, java_lang_Class.get());
-  SetClassRoot(kJavaLangObject, java_lang_Object.get());
-  SetClassRoot(kClassArrayClass, class_array_class.get());
-  SetClassRoot(kObjectArrayClass, object_array_class.get());
-  SetClassRoot(kCharArrayClass, char_array_class.get());
-  SetClassRoot(kJavaLangString, java_lang_String.get());
+  SetClassRoot(kJavaLangClass, java_lang_Class.Get());
+  SetClassRoot(kJavaLangObject, java_lang_Object.Get());
+  SetClassRoot(kClassArrayClass, class_array_class.Get());
+  SetClassRoot(kObjectArrayClass, object_array_class.Get());
+  SetClassRoot(kCharArrayClass, char_array_class.Get());
+  SetClassRoot(kJavaLangString, java_lang_String.Get());
 
   // Setup the primitive type classes.
   SetClassRoot(kPrimitiveBoolean, CreatePrimitiveClass(self, Primitive::kPrimBoolean));
@@ -268,53 +272,54 @@
   array_iftable_ = AllocIfTable(self, 2);
 
   // Create int array type for AllocDexCache (done in AppendToBootClassPath).
-  SirtRef<mirror::Class> int_array_class(self, AllocClass(self, java_lang_Class.get(), sizeof(mirror::Class)));
+  Handle<mirror::Class> int_array_class(
+      hs.NewHandle(AllocClass(self, java_lang_Class.Get(), sizeof(mirror::Class))));
   int_array_class->SetComponentType(GetClassRoot(kPrimitiveInt));
-  mirror::IntArray::SetArrayClass(int_array_class.get());
-  SetClassRoot(kIntArrayClass, int_array_class.get());
+  mirror::IntArray::SetArrayClass(int_array_class.Get());
+  SetClassRoot(kIntArrayClass, int_array_class.Get());
 
   // now that these are registered, we can use AllocClass() and AllocObjectArray
 
   // Set up DexCache. This cannot be done later since AppendToBootClassPath calls AllocDexCache.
-  SirtRef<mirror::Class>
-      java_lang_DexCache(self, AllocClass(self, java_lang_Class.get(), sizeof(mirror::DexCacheClass)));
-  SetClassRoot(kJavaLangDexCache, java_lang_DexCache.get());
+  Handle<mirror::Class> java_lang_DexCache(
+      hs.NewHandle(AllocClass(self, java_lang_Class.Get(), sizeof(mirror::DexCacheClass))));
+  SetClassRoot(kJavaLangDexCache, java_lang_DexCache.Get());
   java_lang_DexCache->SetObjectSize(sizeof(mirror::DexCache));
   java_lang_DexCache->SetStatus(mirror::Class::kStatusResolved, self);
 
   // Constructor, Field, Method, and AbstractMethod are necessary so that FindClass can link members.
-  SirtRef<mirror::Class> java_lang_reflect_ArtField(self, AllocClass(self, java_lang_Class.get(),
-                                                                     sizeof(mirror::ArtFieldClass)));
-  CHECK(java_lang_reflect_ArtField.get() != NULL);
+  Handle<mirror::Class> java_lang_reflect_ArtField(
+      hs.NewHandle(AllocClass(self, java_lang_Class.Get(), sizeof(mirror::ArtFieldClass))));
+  CHECK(java_lang_reflect_ArtField.Get() != NULL);
   java_lang_reflect_ArtField->SetObjectSize(sizeof(mirror::ArtField));
-  SetClassRoot(kJavaLangReflectArtField, java_lang_reflect_ArtField.get());
+  SetClassRoot(kJavaLangReflectArtField, java_lang_reflect_ArtField.Get());
   java_lang_reflect_ArtField->SetStatus(mirror::Class::kStatusResolved, self);
-  mirror::ArtField::SetClass(java_lang_reflect_ArtField.get());
+  mirror::ArtField::SetClass(java_lang_reflect_ArtField.Get());
 
-  SirtRef<mirror::Class> java_lang_reflect_ArtMethod(self, AllocClass(self, java_lang_Class.get(),
-                                                                      sizeof(mirror::ArtMethodClass)));
-  CHECK(java_lang_reflect_ArtMethod.get() != NULL);
+  Handle<mirror::Class> java_lang_reflect_ArtMethod(
+      hs.NewHandle(AllocClass(self, java_lang_Class.Get(), sizeof(mirror::ArtMethodClass))));
+  CHECK(java_lang_reflect_ArtMethod.Get() != NULL);
   java_lang_reflect_ArtMethod->SetObjectSize(sizeof(mirror::ArtMethod));
-  SetClassRoot(kJavaLangReflectArtMethod, java_lang_reflect_ArtMethod.get());
+  SetClassRoot(kJavaLangReflectArtMethod, java_lang_reflect_ArtMethod.Get());
   java_lang_reflect_ArtMethod->SetStatus(mirror::Class::kStatusResolved, self);
 
-  mirror::ArtMethod::SetClass(java_lang_reflect_ArtMethod.get());
+  mirror::ArtMethod::SetClass(java_lang_reflect_ArtMethod.Get());
 
   // Set up array classes for string, field, method
-  SirtRef<mirror::Class> object_array_string(self, AllocClass(self, java_lang_Class.get(),
-                                                              sizeof(mirror::Class)));
-  object_array_string->SetComponentType(java_lang_String.get());
-  SetClassRoot(kJavaLangStringArrayClass, object_array_string.get());
+  Handle<mirror::Class> object_array_string(
+      hs.NewHandle(AllocClass(self, java_lang_Class.Get(), sizeof(mirror::Class))));
+  object_array_string->SetComponentType(java_lang_String.Get());
+  SetClassRoot(kJavaLangStringArrayClass, object_array_string.Get());
 
-  SirtRef<mirror::Class> object_array_art_method(self, AllocClass(self, java_lang_Class.get(),
-                                                                  sizeof(mirror::Class)));
-  object_array_art_method->SetComponentType(java_lang_reflect_ArtMethod.get());
-  SetClassRoot(kJavaLangReflectArtMethodArrayClass, object_array_art_method.get());
+  Handle<mirror::Class> object_array_art_method(
+      hs.NewHandle(AllocClass(self, java_lang_Class.Get(), sizeof(mirror::Class))));
+  object_array_art_method->SetComponentType(java_lang_reflect_ArtMethod.Get());
+  SetClassRoot(kJavaLangReflectArtMethodArrayClass, object_array_art_method.Get());
 
-  SirtRef<mirror::Class> object_array_art_field(self, AllocClass(self, java_lang_Class.get(),
-                                                                 sizeof(mirror::Class)));
-  object_array_art_field->SetComponentType(java_lang_reflect_ArtField.get());
-  SetClassRoot(kJavaLangReflectArtFieldArrayClass, object_array_art_field.get());
+  Handle<mirror::Class> object_array_art_field(
+      hs.NewHandle(AllocClass(self, java_lang_Class.Get(), sizeof(mirror::Class))));
+  object_array_art_field->SetComponentType(java_lang_reflect_ArtField.Get());
+  SetClassRoot(kJavaLangReflectArtFieldArrayClass, object_array_art_field.Get());
 
   // Setup boot_class_path_ and register class_path now that we can use AllocObjectArray to create
   // DexCache instances. Needs to be after String, Field, Method arrays since AllocDexCache uses
@@ -329,8 +334,8 @@
   // now we can use FindSystemClass
 
   // run char class through InitializePrimitiveClass to finish init
-  InitializePrimitiveClass(char_class.get(), Primitive::kPrimChar);
-  SetClassRoot(kPrimitiveChar, char_class.get());  // needs descriptor
+  InitializePrimitiveClass(char_class.Get(), Primitive::kPrimChar);
+  SetClassRoot(kPrimitiveChar, char_class.Get());  // needs descriptor
 
   // Create runtime resolution and imt conflict methods. Also setup the default imt.
   Runtime* runtime = Runtime::Current();
@@ -341,16 +346,16 @@
   // Object, String and DexCache need to be rerun through FindSystemClass to finish init
   java_lang_Object->SetStatus(mirror::Class::kStatusNotReady, self);
   mirror::Class* Object_class = FindSystemClass(self, "Ljava/lang/Object;");
-  CHECK_EQ(java_lang_Object.get(), Object_class);
+  CHECK_EQ(java_lang_Object.Get(), Object_class);
   CHECK_EQ(java_lang_Object->GetObjectSize(), sizeof(mirror::Object));
   java_lang_String->SetStatus(mirror::Class::kStatusNotReady, self);
   mirror::Class* String_class = FindSystemClass(self, "Ljava/lang/String;");
-  CHECK_EQ(java_lang_String.get(), String_class);
+  CHECK_EQ(java_lang_String.Get(), String_class);
   CHECK_EQ(java_lang_String->GetObjectSize(), sizeof(mirror::String));
   java_lang_DexCache->SetStatus(mirror::Class::kStatusNotReady, self);
   mirror::Class* DexCache_class = FindSystemClass(self, "Ljava/lang/DexCache;");
-  CHECK_EQ(java_lang_String.get(), String_class);
-  CHECK_EQ(java_lang_DexCache.get(), DexCache_class);
+  CHECK_EQ(java_lang_String.Get(), String_class);
+  CHECK_EQ(java_lang_DexCache.Get(), DexCache_class);
   CHECK_EQ(java_lang_DexCache->GetObjectSize(), sizeof(mirror::DexCache));
 
   // Setup the primitive array type classes - can't be done until Object has a vtable.
@@ -361,13 +366,13 @@
   mirror::ByteArray::SetArrayClass(GetClassRoot(kByteArrayClass));
 
   mirror::Class* found_char_array_class = FindSystemClass(self, "[C");
-  CHECK_EQ(char_array_class.get(), found_char_array_class);
+  CHECK_EQ(char_array_class.Get(), found_char_array_class);
 
   SetClassRoot(kShortArrayClass, FindSystemClass(self, "[S"));
   mirror::ShortArray::SetArrayClass(GetClassRoot(kShortArrayClass));
 
   mirror::Class* found_int_array_class = FindSystemClass(self, "[I");
-  CHECK_EQ(int_array_class.get(), found_int_array_class);
+  CHECK_EQ(int_array_class.Get(), found_int_array_class);
 
   SetClassRoot(kLongArrayClass, FindSystemClass(self, "[J"));
   mirror::LongArray::SetArrayClass(GetClassRoot(kLongArrayClass));
@@ -379,10 +384,10 @@
   mirror::DoubleArray::SetArrayClass(GetClassRoot(kDoubleArrayClass));
 
   mirror::Class* found_class_array_class = FindSystemClass(self, "[Ljava/lang/Class;");
-  CHECK_EQ(class_array_class.get(), found_class_array_class);
+  CHECK_EQ(class_array_class.Get(), found_class_array_class);
 
   mirror::Class* found_object_array_class = FindSystemClass(self, "[Ljava/lang/Object;");
-  CHECK_EQ(object_array_class.get(), found_object_array_class);
+  CHECK_EQ(object_array_class.Get(), found_object_array_class);
 
   // Setup the single, global copy of "iftable".
   mirror::Class* java_lang_Cloneable = FindSystemClass(self, "Ljava/lang/Cloneable;");
@@ -395,35 +400,35 @@
   array_iftable_->SetInterface(1, java_io_Serializable);
 
   // Sanity check Class[] and Object[]'s interfaces.
-  ClassHelper kh(class_array_class.get());
+  ClassHelper kh(class_array_class.Get());
   CHECK_EQ(java_lang_Cloneable, kh.GetDirectInterface(0));
   CHECK_EQ(java_io_Serializable, kh.GetDirectInterface(1));
-  kh.ChangeClass(object_array_class.get());
+  kh.ChangeClass(object_array_class.Get());
   CHECK_EQ(java_lang_Cloneable, kh.GetDirectInterface(0));
   CHECK_EQ(java_io_Serializable, kh.GetDirectInterface(1));
   // Run Class, ArtField, and ArtMethod through FindSystemClass. This initializes their
   // dex_cache_ fields and register them in class_table_.
   mirror::Class* Class_class = FindSystemClass(self, "Ljava/lang/Class;");
-  CHECK_EQ(java_lang_Class.get(), Class_class);
+  CHECK_EQ(java_lang_Class.Get(), Class_class);
 
   java_lang_reflect_ArtMethod->SetStatus(mirror::Class::kStatusNotReady, self);
   mirror::Class* Art_method_class = FindSystemClass(self, "Ljava/lang/reflect/ArtMethod;");
-  CHECK_EQ(java_lang_reflect_ArtMethod.get(), Art_method_class);
+  CHECK_EQ(java_lang_reflect_ArtMethod.Get(), Art_method_class);
 
   java_lang_reflect_ArtField->SetStatus(mirror::Class::kStatusNotReady, self);
   mirror::Class* Art_field_class = FindSystemClass(self, "Ljava/lang/reflect/ArtField;");
-  CHECK_EQ(java_lang_reflect_ArtField.get(), Art_field_class);
+  CHECK_EQ(java_lang_reflect_ArtField.Get(), Art_field_class);
 
   mirror::Class* String_array_class = FindSystemClass(self, class_roots_descriptors_[kJavaLangStringArrayClass]);
-  CHECK_EQ(object_array_string.get(), String_array_class);
+  CHECK_EQ(object_array_string.Get(), String_array_class);
 
   mirror::Class* Art_method_array_class =
       FindSystemClass(self, class_roots_descriptors_[kJavaLangReflectArtMethodArrayClass]);
-  CHECK_EQ(object_array_art_method.get(), Art_method_array_class);
+  CHECK_EQ(object_array_art_method.Get(), Art_method_array_class);
 
   mirror::Class* Art_field_array_class =
       FindSystemClass(self, class_roots_descriptors_[kJavaLangReflectArtFieldArrayClass]);
-  CHECK_EQ(object_array_art_field.get(), Art_field_array_class);
+  CHECK_EQ(object_array_art_field.Get(), Art_field_array_class);
 
   // End of special init trickery, subsequent classes may be loaded via FindSystemClass.
 
@@ -529,8 +534,9 @@
   for (size_t i = 0; i < ClassLinker::kClassRootsMax; ++i) {
     mirror::Class* c = GetClassRoot(ClassRoot(i));
     if (!c->IsArrayClass() && !c->IsPrimitive()) {
-      SirtRef<mirror::Class> sirt_class(self, GetClassRoot(ClassRoot(i)));
-      EnsureInitialized(sirt_class, true, true);
+      StackHandleScope<1> hs(self);
+      Handle<mirror::Class> h_class(hs.NewHandle(GetClassRoot(ClassRoot(i))));
+      EnsureInitialized(h_class, true, true);
       self->AssertNoPendingException();
     }
   }
@@ -1027,10 +1033,11 @@
   mirror::ObjectArray<mirror::DexCache>* dex_caches =
       dex_caches_object->AsObjectArray<mirror::DexCache>();
 
-  SirtRef<mirror::ObjectArray<mirror::Class> > class_roots(
-      self,
-      space->GetImageHeader().GetImageRoot(ImageHeader::kClassRoots)->AsObjectArray<mirror::Class>());
-  class_roots_ = class_roots.get();
+  StackHandleScope<1> hs(self);
+  Handle<mirror::ObjectArray<mirror::Class>> class_roots(hs.NewHandle(
+          space->GetImageHeader().GetImageRoot(ImageHeader::kClassRoots)->
+          AsObjectArray<mirror::Class>()));
+  class_roots_ = class_roots.Get();
 
   // Special case of setting up the String class early so that we can test arbitrary objects
   // as being Strings or not
@@ -1039,7 +1046,8 @@
   CHECK_EQ(oat_file.GetOatHeader().GetDexFileCount(),
            static_cast<uint32_t>(dex_caches->GetLength()));
   for (int32_t i = 0; i < dex_caches->GetLength(); i++) {
-    SirtRef<mirror::DexCache> dex_cache(self, dex_caches->Get(i));
+    StackHandleScope<1> hs(self);
+    Handle<mirror::DexCache> dex_cache(hs.NewHandle(dex_caches->Get(i)));
     const std::string& dex_file_location(dex_cache->GetLocation()->ToModifiedUtf8());
     const OatFile::OatDexFile* oat_dex_file = oat_file.GetOatDexFile(dex_file_location.c_str(),
                                                                      nullptr);
@@ -1069,7 +1077,7 @@
 
   // reinit class_roots_
   mirror::Class::SetClassClass(class_roots->Get(kJavaLangClass));
-  class_roots_ = class_roots.get();
+  class_roots_ = class_roots.Get();
 
   // reinit array_iftable_ from any array class instance, they should be ==
   array_iftable_ = GetClassRoot(kObjectArrayClass)->GetIfTable();
@@ -1212,42 +1220,43 @@
 
 mirror::DexCache* ClassLinker::AllocDexCache(Thread* self, const DexFile& dex_file) {
   gc::Heap* heap = Runtime::Current()->GetHeap();
-  SirtRef<mirror::Class> dex_cache_class(self, GetClassRoot(kJavaLangDexCache));
-  SirtRef<mirror::DexCache> dex_cache(
-      self, down_cast<mirror::DexCache*>(
-          heap->AllocObject<true>(self, dex_cache_class.get(), dex_cache_class->GetObjectSize(),
-                                  VoidFunctor())));
-  if (dex_cache.get() == NULL) {
+  StackHandleScope<16> hs(self);
+  Handle<mirror::Class> dex_cache_class(hs.NewHandle(GetClassRoot(kJavaLangDexCache)));
+  Handle<mirror::DexCache> dex_cache(
+      hs.NewHandle(down_cast<mirror::DexCache*>(
+          heap->AllocObject<true>(self, dex_cache_class.Get(), dex_cache_class->GetObjectSize(),
+                                  VoidFunctor()))));
+  if (dex_cache.Get() == NULL) {
     return NULL;
   }
-  SirtRef<mirror::String>
-      location(self, intern_table_->InternStrong(dex_file.GetLocation().c_str()));
-  if (location.get() == NULL) {
+  Handle<mirror::String>
+      location(hs.NewHandle(intern_table_->InternStrong(dex_file.GetLocation().c_str())));
+  if (location.Get() == NULL) {
     return NULL;
   }
-  SirtRef<mirror::ObjectArray<mirror::String> >
-      strings(self, AllocStringArray(self, dex_file.NumStringIds()));
-  if (strings.get() == NULL) {
+  Handle<mirror::ObjectArray<mirror::String> >
+      strings(hs.NewHandle(AllocStringArray(self, dex_file.NumStringIds())));
+  if (strings.Get() == NULL) {
     return NULL;
   }
-  SirtRef<mirror::ObjectArray<mirror::Class> >
-      types(self, AllocClassArray(self, dex_file.NumTypeIds()));
-  if (types.get() == NULL) {
+  Handle<mirror::ObjectArray<mirror::Class> >
+      types(hs.NewHandle(AllocClassArray(self, dex_file.NumTypeIds())));
+  if (types.Get() == NULL) {
     return NULL;
   }
-  SirtRef<mirror::ObjectArray<mirror::ArtMethod> >
-      methods(self, AllocArtMethodArray(self, dex_file.NumMethodIds()));
-  if (methods.get() == NULL) {
+  Handle<mirror::ObjectArray<mirror::ArtMethod> >
+      methods(hs.NewHandle(AllocArtMethodArray(self, dex_file.NumMethodIds())));
+  if (methods.Get() == NULL) {
     return NULL;
   }
-  SirtRef<mirror::ObjectArray<mirror::ArtField> >
-      fields(self, AllocArtFieldArray(self, dex_file.NumFieldIds()));
-  if (fields.get() == NULL) {
+  Handle<mirror::ObjectArray<mirror::ArtField> >
+      fields(hs.NewHandle(AllocArtFieldArray(self, dex_file.NumFieldIds())));
+  if (fields.Get() == NULL) {
     return NULL;
   }
-  dex_cache->Init(&dex_file, location.get(), strings.get(), types.get(), methods.get(),
-                  fields.get());
-  return dex_cache.get();
+  dex_cache->Init(&dex_file, location.Get(), strings.Get(), types.Get(), methods.Get(),
+                  fields.Get());
+  return dex_cache.Get();
 }
 
 // Used to initialize a class in the allocation code path to ensure it is guarded by a StoreStore
@@ -1315,19 +1324,20 @@
   DCHECK(klass != NULL);
   // Wait for the class if it has not already been linked.
   if (!klass->IsResolved() && !klass->IsErroneous()) {
-    SirtRef<mirror::Class> sirt_class(self, klass);
-    ObjectLock<mirror::Class> lock(self, &sirt_class);
+    StackHandleScope<1> hs(self);
+    Handle<mirror::Class> h_class(hs.NewHandle(klass));
+    ObjectLock<mirror::Class> lock(self, &h_class);
     // Check for circular dependencies between classes.
-    if (!sirt_class->IsResolved() && sirt_class->GetClinitThreadId() == self->GetTid()) {
-      ThrowClassCircularityError(sirt_class.get());
-      sirt_class->SetStatus(mirror::Class::kStatusError, self);
+    if (!h_class->IsResolved() && h_class->GetClinitThreadId() == self->GetTid()) {
+      ThrowClassCircularityError(h_class.Get());
+      h_class->SetStatus(mirror::Class::kStatusError, self);
       return nullptr;
     }
     // Wait for the pending initialization to complete.
-    while (!sirt_class->IsResolved() && !sirt_class->IsErroneous()) {
+    while (!h_class->IsResolved() && !h_class->IsErroneous()) {
       lock.WaitIgnoringInterrupts();
     }
-    klass = sirt_class.get();
+    klass = h_class.Get();
   }
   if (klass->IsErroneous()) {
     ThrowEarlierClassFailure(klass);
@@ -1340,7 +1350,7 @@
 }
 
 mirror::Class* ClassLinker::FindClass(Thread* self, const char* descriptor,
-                                      const SirtRef<mirror::ClassLoader>& class_loader) {
+                                      const Handle<mirror::ClassLoader>& class_loader) {
   DCHECK_NE(*descriptor, '\0') << "descriptor is empty string";
   DCHECK(self != nullptr);
   self->AssertNoPendingException();
@@ -1350,17 +1360,18 @@
     return FindPrimitiveClass(descriptor[0]);
   }
   // Find the class in the loaded classes table.
-  mirror::Class* klass = LookupClass(descriptor, class_loader.get());
+  mirror::Class* klass = LookupClass(descriptor, class_loader.Get());
   if (klass != NULL) {
     return EnsureResolved(self, klass);
   }
   // Class is not yet loaded.
   if (descriptor[0] == '[') {
     return CreateArrayClass(self, descriptor, class_loader);
-  } else if (class_loader.get() == nullptr) {
+  } else if (class_loader.Get() == nullptr) {
     DexFile::ClassPathEntry pair = DexFile::FindInClassPath(descriptor, boot_class_path_);
     if (pair.second != NULL) {
-      SirtRef<mirror::ClassLoader> class_loader(self, nullptr);
+      StackHandleScope<1> hs(self);
+      auto class_loader = hs.NewHandle<mirror::ClassLoader>(nullptr);
       return DefineClass(descriptor, class_loader, *pair.first, *pair.second);
     }
   } else if (Runtime::Current()->UseCompileTimeClassPath()) {
@@ -1376,7 +1387,7 @@
     {
       ScopedObjectAccessUnchecked soa(self);
       ScopedLocalRef<jobject> jclass_loader(soa.Env(),
-                                            soa.AddLocalReference<jobject>(class_loader.get()));
+                                            soa.AddLocalReference<jobject>(class_loader.Get()));
       class_path = &Runtime::Current()->GetCompileTimeClassPath(jclass_loader.get());
     }
 
@@ -1388,7 +1399,7 @@
   } else {
     ScopedObjectAccessUnchecked soa(self);
     ScopedLocalRef<jobject> class_loader_object(soa.Env(),
-                                                soa.AddLocalReference<jobject>(class_loader.get()));
+                                                soa.AddLocalReference<jobject>(class_loader.Get()));
     std::string class_name_string(DescriptorToDot(descriptor));
     ScopedLocalRef<jobject> result(soa.Env(), NULL);
     {
@@ -1422,38 +1433,39 @@
 }
 
 mirror::Class* ClassLinker::DefineClass(const char* descriptor,
-                                        const SirtRef<mirror::ClassLoader>& class_loader,
+                                        const Handle<mirror::ClassLoader>& class_loader,
                                         const DexFile& dex_file,
                                         const DexFile::ClassDef& dex_class_def) {
   Thread* self = Thread::Current();
-  SirtRef<mirror::Class> klass(self, NULL);
+  StackHandleScope<2> hs(self);
+  auto klass = hs.NewHandle<mirror::Class>(nullptr);
   // Load the class from the dex file.
   if (UNLIKELY(!init_done_)) {
     // finish up init of hand crafted class_roots_
     if (strcmp(descriptor, "Ljava/lang/Object;") == 0) {
-      klass.reset(GetClassRoot(kJavaLangObject));
+      klass.Assign(GetClassRoot(kJavaLangObject));
     } else if (strcmp(descriptor, "Ljava/lang/Class;") == 0) {
-      klass.reset(GetClassRoot(kJavaLangClass));
+      klass.Assign(GetClassRoot(kJavaLangClass));
     } else if (strcmp(descriptor, "Ljava/lang/String;") == 0) {
-      klass.reset(GetClassRoot(kJavaLangString));
+      klass.Assign(GetClassRoot(kJavaLangString));
     } else if (strcmp(descriptor, "Ljava/lang/DexCache;") == 0) {
-      klass.reset(GetClassRoot(kJavaLangDexCache));
+      klass.Assign(GetClassRoot(kJavaLangDexCache));
     } else if (strcmp(descriptor, "Ljava/lang/reflect/ArtField;") == 0) {
-      klass.reset(GetClassRoot(kJavaLangReflectArtField));
+      klass.Assign(GetClassRoot(kJavaLangReflectArtField));
     } else if (strcmp(descriptor, "Ljava/lang/reflect/ArtMethod;") == 0) {
-      klass.reset(GetClassRoot(kJavaLangReflectArtMethod));
+      klass.Assign(GetClassRoot(kJavaLangReflectArtMethod));
     } else {
-      klass.reset(AllocClass(self, SizeOfClass(dex_file, dex_class_def)));
+      klass.Assign(AllocClass(self, SizeOfClass(dex_file, dex_class_def)));
     }
   } else {
-    klass.reset(AllocClass(self, SizeOfClass(dex_file, dex_class_def)));
+    klass.Assign(AllocClass(self, SizeOfClass(dex_file, dex_class_def)));
   }
-  if (UNLIKELY(klass.get() == NULL)) {
+  if (UNLIKELY(klass.Get() == NULL)) {
     CHECK(self->IsExceptionPending());  // Expect an OOME.
     return NULL;
   }
   klass->SetDexCache(FindDexCache(dex_file));
-  LoadClass(dex_file, dex_class_def, klass, class_loader.get());
+  LoadClass(dex_file, dex_class_def, klass, class_loader.Get());
   // Check for a pending exception during load
   if (self->IsExceptionPending()) {
     klass->SetStatus(mirror::Class::kStatusError, self);
@@ -1462,7 +1474,7 @@
   ObjectLock<mirror::Class> lock(self, &klass);
   klass->SetClinitThreadId(self->GetTid());
   // Add the newly loaded class to the loaded classes table.
-  mirror::Class* existing = InsertClass(descriptor, klass.get(), Hash(descriptor));
+  mirror::Class* existing = InsertClass(descriptor, klass.Get(), Hash(descriptor));
   if (existing != NULL) {
     // We failed to insert because we raced with another thread. Calling EnsureResolved may cause
     // this thread to block.
@@ -1479,7 +1491,7 @@
   // Link the class (if necessary)
   CHECK(!klass->IsResolved());
   // TODO: Use fast jobjects?
-  SirtRef<mirror::ObjectArray<mirror::Class> > interfaces(self, nullptr);
+  auto interfaces = hs.NewHandle<mirror::ObjectArray<mirror::Class>>(nullptr);
   if (!LinkClass(self, klass, interfaces)) {
     // Linking failed.
     klass->SetStatus(mirror::Class::kStatusError, self);
@@ -1498,9 +1510,9 @@
    * The class has been prepared and resolved but possibly not yet verified
    * at this point.
    */
-  Dbg::PostClassPrepare(klass.get());
+  Dbg::PostClassPrepare(klass.Get());
 
-  return klass.get();
+  return klass.Get();
 }
 
 // Precomputes size that will be needed for Class, matching LinkStaticFields
@@ -1765,7 +1777,7 @@
   // Ignore virtual methods on the iterator.
 }
 
-static void LinkCode(const SirtRef<mirror::ArtMethod>& method, const OatFile::OatClass* oat_class,
+static void LinkCode(const Handle<mirror::ArtMethod>& method, const OatFile::OatClass* oat_class,
                      const DexFile& dex_file, uint32_t dex_method_index, uint32_t method_index)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   // Method shouldn't have already been linked.
@@ -1774,11 +1786,11 @@
   // Every kind of method should at least get an invoke stub from the oat_method.
   // non-abstract methods also get their code pointers.
   const OatFile::OatMethod oat_method = oat_class->GetOatMethod(method_index);
-  oat_method.LinkMethod(method.get());
+  oat_method.LinkMethod(method.Get());
 
   // Install entry point from interpreter.
   Runtime* runtime = Runtime::Current();
-  bool enter_interpreter = NeedsInterpreter(method.get(),
+  bool enter_interpreter = NeedsInterpreter(method.Get(),
                                             method->GetEntryPointFromQuickCompiledCode(),
                                             method->GetEntryPointFromPortableCompiledCode());
   if (enter_interpreter && !method->IsNative()) {
@@ -1828,32 +1840,11 @@
       DCHECK(method->GetEntryPointFromQuickCompiledCode() ==
           GetQuickResolutionTrampoline(runtime->GetClassLinker())
           || method->GetEntryPointFromQuickCompiledCode() == GetQuickGenericJniTrampoline());
-
-      DCHECK_EQ(method->GetFrameSizeInBytes<false>(), 0U);
-
-      // Fix up method metadata if necessary.
-      uint32_t s_len;
-      const char* shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(dex_method_index), &s_len);
-      uint32_t refs = 1;    // Native method always has "this" or class.
-      for (uint32_t i = 1; i < s_len; ++i) {
-        if (shorty[i] == 'L') {
-          refs++;
-        }
-      }
-      size_t sirt_size = StackIndirectReferenceTable::GetAlignedSirtSize(refs);
-
-      // Get the generic spill masks and base frame size.
-      mirror::ArtMethod* callee_save_method =
-          Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs);
-
-      method->SetFrameSizeInBytes(callee_save_method->GetFrameSizeInBytes() + sirt_size);
-      method->SetCoreSpillMask(callee_save_method->GetCoreSpillMask());
-      method->SetFpSpillMask(callee_save_method->GetFpSpillMask());
     }
   }
 
   // Allow instrumentation its chance to hijack code.
-  runtime->GetInstrumentation()->UpdateMethodsCode(method.get(),
+  runtime->GetInstrumentation()->UpdateMethodsCode(method.Get(),
                                                    method->GetEntryPointFromQuickCompiledCode(),
                                                    method->GetEntryPointFromPortableCompiledCode(),
                                                    have_portable_code);
@@ -1861,9 +1852,9 @@
 
 void ClassLinker::LoadClass(const DexFile& dex_file,
                             const DexFile::ClassDef& dex_class_def,
-                            const SirtRef<mirror::Class>& klass,
+                            const Handle<mirror::Class>& klass,
                             mirror::ClassLoader* class_loader) {
-  CHECK(klass.get() != NULL);
+  CHECK(klass.Get() != NULL);
   CHECK(klass->GetDexCache() != NULL);
   CHECK_EQ(mirror::Class::kStatusNotReady, klass->GetStatus());
   const char* descriptor = dex_file.GetClassDescriptor(dex_class_def);
@@ -1899,7 +1890,7 @@
 
 void ClassLinker::LoadClassMembers(const DexFile& dex_file,
                                    const byte* class_data,
-                                   const SirtRef<mirror::Class>& klass,
+                                   const Handle<mirror::Class>& klass,
                                    mirror::ClassLoader* class_loader,
                                    const OatFile::OatClass* oat_class) {
   // Load fields.
@@ -1923,21 +1914,23 @@
     klass->SetIFields(fields);
   }
   for (size_t i = 0; it.HasNextStaticField(); i++, it.Next()) {
-    SirtRef<mirror::ArtField> sfield(self, AllocArtField(self));
-    if (UNLIKELY(sfield.get() == NULL)) {
+    StackHandleScope<1> hs(self);
+    Handle<mirror::ArtField> sfield(hs.NewHandle(AllocArtField(self)));
+    if (UNLIKELY(sfield.Get() == NULL)) {
       CHECK(self->IsExceptionPending());  // OOME.
       return;
     }
-    klass->SetStaticField(i, sfield.get());
+    klass->SetStaticField(i, sfield.Get());
     LoadField(dex_file, it, klass, sfield);
   }
   for (size_t i = 0; it.HasNextInstanceField(); i++, it.Next()) {
-    SirtRef<mirror::ArtField> ifield(self, AllocArtField(self));
-    if (UNLIKELY(ifield.get() == NULL)) {
+    StackHandleScope<1> hs(self);
+    Handle<mirror::ArtField> ifield(hs.NewHandle(AllocArtField(self)));
+    if (UNLIKELY(ifield.Get() == NULL)) {
       CHECK(self->IsExceptionPending());  // OOME.
       return;
     }
-    klass->SetInstanceField(i, ifield.get());
+    klass->SetInstanceField(i, ifield.Get());
     LoadField(dex_file, it, klass, ifield);
   }
 
@@ -1964,12 +1957,13 @@
   }
   size_t class_def_method_index = 0;
   for (size_t i = 0; it.HasNextDirectMethod(); i++, it.Next()) {
-    SirtRef<mirror::ArtMethod> method(self, LoadMethod(self, dex_file, it, klass));
-    if (UNLIKELY(method.get() == NULL)) {
+    StackHandleScope<1> hs(self);
+    Handle<mirror::ArtMethod> method(hs.NewHandle(LoadMethod(self, dex_file, it, klass)));
+    if (UNLIKELY(method.Get() == NULL)) {
       CHECK(self->IsExceptionPending());  // OOME.
       return;
     }
-    klass->SetDirectMethod(i, method.get());
+    klass->SetDirectMethod(i, method.Get());
     if (oat_class != nullptr) {
       LinkCode(method, oat_class, dex_file, it.GetMemberIndex(), class_def_method_index);
     }
@@ -1977,12 +1971,13 @@
     class_def_method_index++;
   }
   for (size_t i = 0; it.HasNextVirtualMethod(); i++, it.Next()) {
-    SirtRef<mirror::ArtMethod> method(self, LoadMethod(self, dex_file, it, klass));
-    if (UNLIKELY(method.get() == NULL)) {
+    StackHandleScope<1> hs(self);
+    Handle<mirror::ArtMethod> method(hs.NewHandle(LoadMethod(self, dex_file, it, klass)));
+    if (UNLIKELY(method.Get() == NULL)) {
       CHECK(self->IsExceptionPending());  // OOME.
       return;
     }
-    klass->SetVirtualMethod(i, method.get());
+    klass->SetVirtualMethod(i, method.Get());
     DCHECK_EQ(class_def_method_index, it.NumDirectMethods() + i);
     if (oat_class != nullptr) {
       LinkCode(method, oat_class, dex_file, it.GetMemberIndex(), class_def_method_index);
@@ -1993,17 +1988,17 @@
 }
 
 void ClassLinker::LoadField(const DexFile& /*dex_file*/, const ClassDataItemIterator& it,
-                            const SirtRef<mirror::Class>& klass,
-                            const SirtRef<mirror::ArtField>& dst) {
+                            const Handle<mirror::Class>& klass,
+                            const Handle<mirror::ArtField>& dst) {
   uint32_t field_idx = it.GetMemberIndex();
   dst->SetDexFieldIndex(field_idx);
-  dst->SetDeclaringClass(klass.get());
+  dst->SetDeclaringClass(klass.Get());
   dst->SetAccessFlags(it.GetMemberAccessFlags());
 }
 
 mirror::ArtMethod* ClassLinker::LoadMethod(Thread* self, const DexFile& dex_file,
                                            const ClassDataItemIterator& it,
-                                           const SirtRef<mirror::Class>& klass) {
+                                           const Handle<mirror::Class>& klass) {
   uint32_t dex_method_idx = it.GetMemberIndex();
   const DexFile::MethodId& method_id = dex_file.GetMethodId(dex_method_idx);
   const char* method_name = dex_file.StringDataByIdx(method_id.name_idx_);
@@ -2017,7 +2012,7 @@
 
   const char* old_cause = self->StartAssertNoThreadSuspension("LoadMethod");
   dst->SetDexMethodIndex(dex_method_idx);
-  dst->SetDeclaringClass(klass.get());
+  dst->SetDeclaringClass(klass.Get());
   dst->SetCodeItemOffset(it.GetMethodCodeItemOffset());
 
   dst->SetDexCacheStrings(klass->GetDexCache()->GetStrings());
@@ -2033,7 +2028,7 @@
       if (klass->GetClassLoader() != NULL) {  // All non-boot finalizer methods are flagged
         klass->SetFinalizable();
       } else {
-        ClassHelper kh(klass.get());
+        ClassHelper kh(klass.Get());
         const char* klass_descriptor = kh.GetDescriptor();
         // The Enum class declares a "final" finalize() method to prevent subclasses from
         // introducing a finalizer. We don't want to set the finalizable flag for Enum or its
@@ -2055,7 +2050,7 @@
     } else {
       if (UNLIKELY((access_flags & kAccConstructor) == 0)) {
         LOG(WARNING) << method_name << " didn't have expected constructor access flag in class "
-            << PrettyDescriptor(klass.get()) << " in dex file " << dex_file.GetLocation();
+            << PrettyDescriptor(klass.Get()) << " in dex file " << dex_file.GetLocation();
         access_flags |= kAccConstructor;
       }
     }
@@ -2068,14 +2063,15 @@
 
 void ClassLinker::AppendToBootClassPath(const DexFile& dex_file) {
   Thread* self = Thread::Current();
-  SirtRef<mirror::DexCache> dex_cache(self, AllocDexCache(self, dex_file));
-  CHECK(dex_cache.get() != NULL) << "Failed to allocate dex cache for " << dex_file.GetLocation();
+  StackHandleScope<1> hs(self);
+  Handle<mirror::DexCache> dex_cache(hs.NewHandle(AllocDexCache(self, dex_file)));
+  CHECK(dex_cache.Get() != NULL) << "Failed to allocate dex cache for " << dex_file.GetLocation();
   AppendToBootClassPath(dex_file, dex_cache);
 }
 
 void ClassLinker::AppendToBootClassPath(const DexFile& dex_file,
-                                        const SirtRef<mirror::DexCache>& dex_cache) {
-  CHECK(dex_cache.get() != NULL) << dex_file.GetLocation();
+                                        const Handle<mirror::DexCache>& dex_cache) {
+  CHECK(dex_cache.Get() != NULL) << dex_file.GetLocation();
   boot_class_path_.push_back(&dex_file);
   RegisterDexFile(dex_file, dex_cache);
 }
@@ -2096,12 +2092,12 @@
 }
 
 void ClassLinker::RegisterDexFileLocked(const DexFile& dex_file,
-                                        const SirtRef<mirror::DexCache>& dex_cache) {
+                                        const Handle<mirror::DexCache>& dex_cache) {
   dex_lock_.AssertExclusiveHeld(Thread::Current());
-  CHECK(dex_cache.get() != NULL) << dex_file.GetLocation();
+  CHECK(dex_cache.Get() != NULL) << dex_file.GetLocation();
   CHECK(dex_cache->GetLocation()->Equals(dex_file.GetLocation()))
       << dex_cache->GetLocation()->ToModifiedUtf8() << " " << dex_file.GetLocation();
-  dex_caches_.push_back(dex_cache.get());
+  dex_caches_.push_back(dex_cache.Get());
   dex_cache->SetDexFile(&dex_file);
   if (log_new_dex_caches_roots_) {
     // TODO: This is not safe if we can remove dex caches.
@@ -2120,8 +2116,9 @@
   // Don't alloc while holding the lock, since allocation may need to
   // suspend all threads and another thread may need the dex_lock_ to
   // get to a suspend point.
-  SirtRef<mirror::DexCache> dex_cache(self, AllocDexCache(self, dex_file));
-  CHECK(dex_cache.get() != NULL) << "Failed to allocate dex cache for " << dex_file.GetLocation();
+  StackHandleScope<1> hs(self);
+  Handle<mirror::DexCache> dex_cache(hs.NewHandle(AllocDexCache(self, dex_file)));
+  CHECK(dex_cache.Get() != NULL) << "Failed to allocate dex cache for " << dex_file.GetLocation();
   {
     WriterMutexLock mu(self, dex_lock_);
     if (IsDexFileRegisteredLocked(dex_file)) {
@@ -2132,7 +2129,7 @@
 }
 
 void ClassLinker::RegisterDexFile(const DexFile& dex_file,
-                                  const SirtRef<mirror::DexCache>& dex_cache) {
+                                  const Handle<mirror::DexCache>& dex_cache) {
   WriterMutexLock mu(Thread::Current(), dex_lock_);
   RegisterDexFileLocked(dex_file, dex_cache);
 }
@@ -2183,8 +2180,9 @@
   CHECK(primitive_class != NULL);
   // Must hold lock on object when initializing.
   Thread* self = Thread::Current();
-  SirtRef<mirror::Class> sirt_class(self, primitive_class);
-  ObjectLock<mirror::Class> lock(self, &sirt_class);
+  StackHandleScope<1> hs(self);
+  Handle<mirror::Class> h_class(hs.NewHandle(primitive_class));
+  ObjectLock<mirror::Class> lock(self, &h_class);
   primitive_class->SetAccessFlags(kAccPublic | kAccFinal | kAccAbstract);
   primitive_class->SetPrimitiveType(type);
   primitive_class->SetStatus(mirror::Class::kStatusInitialized, self);
@@ -2208,15 +2206,19 @@
 //
 // Returns NULL with an exception raised on failure.
 mirror::Class* ClassLinker::CreateArrayClass(Thread* self, const char* descriptor,
-                                             const SirtRef<mirror::ClassLoader>& class_loader) {
+                                             const Handle<mirror::ClassLoader>& class_loader) {
   // Identify the underlying component type
   CHECK_EQ('[', descriptor[0]);
-  SirtRef<mirror::Class> component_type(self, FindClass(self, descriptor + 1, class_loader));
-  if (component_type.get() == nullptr) {
+  StackHandleScope<2> hs(self);
+  Handle<mirror::Class> component_type(hs.NewHandle(FindClass(self, descriptor + 1, class_loader)));
+  if (component_type.Get() == nullptr) {
     DCHECK(self->IsExceptionPending());
     return nullptr;
   }
-
+  if (UNLIKELY(component_type->IsPrimitiveVoid())) {
+    ThrowNoClassDefFoundError("Attempt to create array of void primitive type");
+    return nullptr;
+  }
   // See if the component type is already loaded.  Array classes are
   // always associated with the class loader of their underlying
   // element type -- an array of Strings goes with the loader for
@@ -2234,7 +2236,7 @@
   // because we effectively do this lookup again when we add the new
   // class to the hash table --- necessary because of possible races with
   // other threads.)
-  if (class_loader.get() != component_type->GetClassLoader()) {
+  if (class_loader.Get() != component_type->GetClassLoader()) {
     mirror::Class* new_class = LookupClass(descriptor, component_type->GetClassLoader());
     if (new_class != NULL) {
       return new_class;
@@ -2249,33 +2251,33 @@
   //
   // Array classes are simple enough that we don't need to do a full
   // link step.
-  SirtRef<mirror::Class> new_class(self, NULL);
+  auto new_class = hs.NewHandle<mirror::Class>(nullptr);
   if (UNLIKELY(!init_done_)) {
     // Classes that were hand created, ie not by FindSystemClass
     if (strcmp(descriptor, "[Ljava/lang/Class;") == 0) {
-      new_class.reset(GetClassRoot(kClassArrayClass));
+      new_class.Assign(GetClassRoot(kClassArrayClass));
     } else if (strcmp(descriptor, "[Ljava/lang/Object;") == 0) {
-      new_class.reset(GetClassRoot(kObjectArrayClass));
+      new_class.Assign(GetClassRoot(kObjectArrayClass));
     } else if (strcmp(descriptor, class_roots_descriptors_[kJavaLangStringArrayClass]) == 0) {
-      new_class.reset(GetClassRoot(kJavaLangStringArrayClass));
+      new_class.Assign(GetClassRoot(kJavaLangStringArrayClass));
     } else if (strcmp(descriptor,
                       class_roots_descriptors_[kJavaLangReflectArtMethodArrayClass]) == 0) {
-      new_class.reset(GetClassRoot(kJavaLangReflectArtMethodArrayClass));
+      new_class.Assign(GetClassRoot(kJavaLangReflectArtMethodArrayClass));
     } else if (strcmp(descriptor,
                       class_roots_descriptors_[kJavaLangReflectArtFieldArrayClass]) == 0) {
-      new_class.reset(GetClassRoot(kJavaLangReflectArtFieldArrayClass));
+      new_class.Assign(GetClassRoot(kJavaLangReflectArtFieldArrayClass));
     } else if (strcmp(descriptor, "[C") == 0) {
-      new_class.reset(GetClassRoot(kCharArrayClass));
+      new_class.Assign(GetClassRoot(kCharArrayClass));
     } else if (strcmp(descriptor, "[I") == 0) {
-      new_class.reset(GetClassRoot(kIntArrayClass));
+      new_class.Assign(GetClassRoot(kIntArrayClass));
     }
   }
-  if (new_class.get() == nullptr) {
-    new_class.reset(AllocClass(self, sizeof(mirror::Class)));
-    if (new_class.get() == nullptr) {
+  if (new_class.Get() == nullptr) {
+    new_class.Assign(AllocClass(self, sizeof(mirror::Class)));
+    if (new_class.Get() == nullptr) {
       return nullptr;
     }
-    new_class->SetComponentType(component_type.get());
+    new_class->SetComponentType(component_type.Get());
   }
   ObjectLock<mirror::Class> lock(self, &new_class);  // Must hold lock on object when initializing.
   DCHECK(new_class->GetComponentType() != NULL);
@@ -2315,9 +2317,9 @@
 
   new_class->SetAccessFlags(access_flags);
 
-  mirror::Class* existing = InsertClass(descriptor, new_class.get(), Hash(descriptor));
+  mirror::Class* existing = InsertClass(descriptor, new_class.Get(), Hash(descriptor));
   if (existing == nullptr) {
-    return new_class.get();
+    return new_class.Get();
   }
   // Another thread must have loaded the class after we
   // started but before we finished.  Abandon what we've
@@ -2549,7 +2551,7 @@
   }
 }
 
-void ClassLinker::VerifyClass(const SirtRef<mirror::Class>& klass) {
+void ClassLinker::VerifyClass(const Handle<mirror::Class>& klass) {
   // TODO: assert that the monitor on the Class is held
   Thread* self = Thread::Current();
   ObjectLock<mirror::Class> lock(self, &klass);
@@ -2563,7 +2565,7 @@
   // The class might already be erroneous, for example at compile time if we attempted to verify
   // this class as a parent to another.
   if (klass->IsErroneous()) {
-    ThrowEarlierClassFailure(klass.get());
+    ThrowEarlierClassFailure(klass.Get());
     return;
   }
 
@@ -2571,7 +2573,7 @@
     klass->SetStatus(mirror::Class::kStatusVerifying, self);
   } else {
     CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusRetryVerificationAtRuntime)
-        << PrettyClass(klass.get());
+        << PrettyClass(klass.Get());
     CHECK(!Runtime::Current()->IsCompiler());
     klass->SetStatus(mirror::Class::kStatusVerifyingAtRuntime, self);
   }
@@ -2583,8 +2585,9 @@
   }
 
   // Verify super class.
-  SirtRef<mirror::Class> super(self, klass->GetSuperClass());
-  if (super.get() != NULL) {
+  StackHandleScope<2> hs(self);
+  Handle<mirror::Class> super(hs.NewHandle(klass->GetSuperClass()));
+  if (super.Get() != NULL) {
     // Acquire lock to prevent races on verifying the super class.
     ObjectLock<mirror::Class> lock(self, &super);
 
@@ -2593,16 +2596,16 @@
     }
     if (!super->IsCompileTimeVerified()) {
       std::string error_msg(StringPrintf("Rejecting class %s that attempts to sub-class erroneous class %s",
-                                         PrettyDescriptor(klass.get()).c_str(),
-                                         PrettyDescriptor(super.get()).c_str()));
+                                         PrettyDescriptor(klass.Get()).c_str(),
+                                         PrettyDescriptor(super.Get()).c_str()));
       LOG(ERROR) << error_msg  << " in " << klass->GetDexCache()->GetLocation()->ToModifiedUtf8();
-      SirtRef<mirror::Throwable> cause(self, self->GetException(NULL));
-      if (cause.get() != nullptr) {
+      Handle<mirror::Throwable> cause(hs.NewHandle(self->GetException(nullptr)));
+      if (cause.Get() != nullptr) {
         self->ClearException();
       }
-      ThrowVerifyError(klass.get(), "%s", error_msg.c_str());
-      if (cause.get() != nullptr) {
-        self->GetException(nullptr)->SetCause(cause.get());
+      ThrowVerifyError(klass.Get(), "%s", error_msg.c_str());
+      if (cause.Get() != nullptr) {
+        self->GetException(nullptr)->SetCause(cause.Get());
       }
       ClassReference ref(klass->GetDexCache()->GetDexFile(), klass->GetDexClassDefIndex());
       if (Runtime::Current()->IsCompiler()) {
@@ -2616,26 +2619,26 @@
   // Try to use verification information from the oat file, otherwise do runtime verification.
   const DexFile& dex_file = *klass->GetDexCache()->GetDexFile();
   mirror::Class::Status oat_file_class_status(mirror::Class::kStatusNotReady);
-  bool preverified = VerifyClassUsingOatFile(dex_file, klass.get(), oat_file_class_status);
+  bool preverified = VerifyClassUsingOatFile(dex_file, klass.Get(), oat_file_class_status);
   if (oat_file_class_status == mirror::Class::kStatusError) {
     VLOG(class_linker) << "Skipping runtime verification of erroneous class "
-        << PrettyDescriptor(klass.get()) << " in "
+        << PrettyDescriptor(klass.Get()) << " in "
         << klass->GetDexCache()->GetLocation()->ToModifiedUtf8();
-    ThrowVerifyError(klass.get(), "Rejecting class %s because it failed compile-time verification",
-                     PrettyDescriptor(klass.get()).c_str());
+    ThrowVerifyError(klass.Get(), "Rejecting class %s because it failed compile-time verification",
+                     PrettyDescriptor(klass.Get()).c_str());
     klass->SetStatus(mirror::Class::kStatusError, self);
     return;
   }
   verifier::MethodVerifier::FailureKind verifier_failure = verifier::MethodVerifier::kNoFailure;
   std::string error_msg;
   if (!preverified) {
-    verifier_failure = verifier::MethodVerifier::VerifyClass(klass.get(),
+    verifier_failure = verifier::MethodVerifier::VerifyClass(klass.Get(),
                                                              Runtime::Current()->IsCompiler(),
                                                              &error_msg);
   }
   if (preverified || verifier_failure != verifier::MethodVerifier::kHardFailure) {
     if (!preverified && verifier_failure != verifier::MethodVerifier::kNoFailure) {
-      VLOG(class_linker) << "Soft verification failure in class " << PrettyDescriptor(klass.get())
+      VLOG(class_linker) << "Soft verification failure in class " << PrettyDescriptor(klass.Get())
           << " in " << klass->GetDexCache()->GetLocation()->ToModifiedUtf8()
           << " because: " << error_msg;
     }
@@ -2645,7 +2648,7 @@
     if (verifier_failure == verifier::MethodVerifier::kNoFailure) {
       // Even though there were no verifier failures we need to respect whether the super-class
       // was verified or requiring runtime reverification.
-      if (super.get() == NULL || super->IsVerified()) {
+      if (super.Get() == NULL || super->IsVerified()) {
         klass->SetStatus(mirror::Class::kStatusVerified, self);
       } else {
         CHECK_EQ(super->GetStatus(), mirror::Class::kStatusRetryVerificationAtRuntime);
@@ -2665,11 +2668,11 @@
       }
     }
   } else {
-    LOG(ERROR) << "Verification failed on class " << PrettyDescriptor(klass.get())
+    LOG(ERROR) << "Verification failed on class " << PrettyDescriptor(klass.Get())
         << " in " << klass->GetDexCache()->GetLocation()->ToModifiedUtf8()
         << " because: " << error_msg;
     self->AssertNoPendingException();
-    ThrowVerifyError(klass.get(), "%s", error_msg.c_str());
+    ThrowVerifyError(klass.Get(), "%s", error_msg.c_str());
     klass->SetStatus(mirror::Class::kStatusError, self);
   }
   if (preverified || verifier_failure == verifier::MethodVerifier::kNoFailure) {
@@ -2760,7 +2763,7 @@
 }
 
 void ClassLinker::ResolveClassExceptionHandlerTypes(const DexFile& dex_file,
-                                                    const SirtRef<mirror::Class>& klass) {
+                                                    const Handle<mirror::Class>& klass) {
   for (size_t i = 0; i < klass->NumDirectMethods(); i++) {
     ResolveMethodExceptionHandlerTypes(dex_file, klass->GetDirectMethod(i));
   }
@@ -2801,15 +2804,16 @@
 
 static void CheckProxyConstructor(mirror::ArtMethod* constructor);
 static void CheckProxyMethod(mirror::ArtMethod* method,
-                             SirtRef<mirror::ArtMethod>& prototype);
+                             Handle<mirror::ArtMethod>& prototype);
 
 mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccess& soa, jstring name,
                                              jobjectArray interfaces, jobject loader,
                                              jobjectArray methods, jobjectArray throws) {
   Thread* self = soa.Self();
-  SirtRef<mirror::Class> klass(self, AllocClass(self, GetClassRoot(kJavaLangClass),
-                                                sizeof(mirror::SynthesizedProxyClass)));
-  if (klass.get() == NULL) {
+  StackHandleScope<8> hs(self);
+  Handle<mirror::Class> klass(hs.NewHandle(AllocClass(self, GetClassRoot(kJavaLangClass),
+                                                      sizeof(mirror::SynthesizedProxyClass))));
+  if (klass.Get() == NULL) {
     CHECK(self->IsExceptionPending());  // OOME.
     return NULL;
   }
@@ -2834,38 +2838,38 @@
   }
   // 1. Create a static field 'interfaces' that holds the _declared_ interfaces implemented by
   // our proxy, so Class.getInterfaces doesn't return the flattened set.
-  SirtRef<mirror::ArtField> interfaces_sfield(self, AllocArtField(self));
-  if (UNLIKELY(interfaces_sfield.get() == NULL)) {
+  Handle<mirror::ArtField> interfaces_sfield(hs.NewHandle(AllocArtField(self)));
+  if (UNLIKELY(interfaces_sfield.Get() == nullptr)) {
     CHECK(self->IsExceptionPending());  // OOME.
-    return NULL;
+    return nullptr;
   }
-  klass->SetStaticField(0, interfaces_sfield.get());
+  klass->SetStaticField(0, interfaces_sfield.Get());
   interfaces_sfield->SetDexFieldIndex(0);
-  interfaces_sfield->SetDeclaringClass(klass.get());
+  interfaces_sfield->SetDeclaringClass(klass.Get());
   interfaces_sfield->SetAccessFlags(kAccStatic | kAccPublic | kAccFinal);
   // 2. Create a static field 'throws' that holds exceptions thrown by our methods.
-  SirtRef<mirror::ArtField> throws_sfield(self, AllocArtField(self));
-  if (UNLIKELY(throws_sfield.get() == NULL)) {
+  Handle<mirror::ArtField> throws_sfield(hs.NewHandle(AllocArtField(self)));
+  if (UNLIKELY(throws_sfield.Get() == nullptr)) {
     CHECK(self->IsExceptionPending());  // OOME.
-    return NULL;
+    return nullptr;
   }
-  klass->SetStaticField(1, throws_sfield.get());
+  klass->SetStaticField(1, throws_sfield.Get());
   throws_sfield->SetDexFieldIndex(1);
-  throws_sfield->SetDeclaringClass(klass.get());
+  throws_sfield->SetDeclaringClass(klass.Get());
   throws_sfield->SetAccessFlags(kAccStatic | kAccPublic | kAccFinal);
 
   // Proxies have 1 direct method, the constructor
   {
     mirror::ObjectArray<mirror::ArtMethod>* directs = AllocArtMethodArray(self, 1);
-    if (UNLIKELY(directs == NULL)) {
+    if (UNLIKELY(directs == nullptr)) {
       CHECK(self->IsExceptionPending());  // OOME.
-      return NULL;
+      return nullptr;
     }
     klass->SetDirectMethods(directs);
     mirror::ArtMethod* constructor = CreateProxyConstructor(self, klass, proxy_class);
-    if (UNLIKELY(constructor == NULL)) {
+    if (UNLIKELY(constructor == nullptr)) {
       CHECK(self->IsExceptionPending());  // OOME.
-      return NULL;
+      return nullptr;
     }
     klass->SetDirectMethod(0, constructor);
   }
@@ -2882,13 +2886,14 @@
     klass->SetVirtualMethods(virtuals);
   }
   for (size_t i = 0; i < num_virtual_methods; ++i) {
+    StackHandleScope<1> hs(self);
     mirror::ObjectArray<mirror::ArtMethod>* decoded_methods =
         soa.Decode<mirror::ObjectArray<mirror::ArtMethod>*>(methods);
-    SirtRef<mirror::ArtMethod> prototype(self, decoded_methods->Get(i));
+    Handle<mirror::ArtMethod> prototype(hs.NewHandle(decoded_methods->Get(i)));
     mirror::ArtMethod* clone = CreateProxyMethod(self, klass, prototype);
-    if (UNLIKELY(clone == NULL)) {
+    if (UNLIKELY(clone == nullptr)) {
       CHECK(self->IsExceptionPending());  // OOME.
-      return NULL;
+      return nullptr;
     }
     klass->SetVirtualMethod(i, clone);
   }
@@ -2900,26 +2905,27 @@
   {
     ObjectLock<mirror::Class> lock(self, &klass);  // Must hold lock on object when resolved.
     // Link the fields and virtual methods, creating vtable and iftables
-    SirtRef<mirror::ObjectArray<mirror::Class> > sirt_interfaces(
-        self, soa.Decode<mirror::ObjectArray<mirror::Class>*>(interfaces));
-    if (!LinkClass(self, klass, sirt_interfaces)) {
+    Handle<mirror::ObjectArray<mirror::Class> > h_interfaces(
+        hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Class>*>(interfaces)));
+    if (!LinkClass(self, klass, h_interfaces)) {
       klass->SetStatus(mirror::Class::kStatusError, self);
       return nullptr;
     }
 
-    interfaces_sfield->SetObject<false>(klass.get(), soa.Decode<mirror::ObjectArray<mirror::Class>*>(interfaces));
-    throws_sfield->SetObject<false>(klass.get(), soa.Decode<mirror::ObjectArray<mirror::ObjectArray<mirror::Class> >*>(throws));
+    interfaces_sfield->SetObject<false>(klass.Get(), soa.Decode<mirror::ObjectArray<mirror::Class>*>(interfaces));
+    throws_sfield->SetObject<false>(klass.Get(), soa.Decode<mirror::ObjectArray<mirror::ObjectArray<mirror::Class> >*>(throws));
     klass->SetStatus(mirror::Class::kStatusInitialized, self);
   }
 
   // sanity checks
   if (kIsDebugBuild) {
-    CHECK(klass->GetIFields() == NULL);
+    CHECK(klass->GetIFields() == nullptr);
     CheckProxyConstructor(klass->GetDirectMethod(0));
     for (size_t i = 0; i < num_virtual_methods; ++i) {
+      StackHandleScope<1> hs(self);
       mirror::ObjectArray<mirror::ArtMethod>* decoded_methods =
           soa.Decode<mirror::ObjectArray<mirror::ArtMethod>*>(methods);
-      SirtRef<mirror::ArtMethod> prototype(self, decoded_methods->Get(i));
+      Handle<mirror::ArtMethod> prototype(hs.NewHandle(decoded_methods->Get(i)));
       CheckProxyMethod(klass->GetVirtualMethod(i), prototype);
     }
 
@@ -2933,14 +2939,14 @@
     CHECK_EQ(PrettyField(klass->GetStaticField(1)), throws_field_name);
 
     mirror::SynthesizedProxyClass* synth_proxy_class =
-        down_cast<mirror::SynthesizedProxyClass*>(klass.get());
+        down_cast<mirror::SynthesizedProxyClass*>(klass.Get());
     CHECK_EQ(synth_proxy_class->GetInterfaces(), soa.Decode<mirror::ObjectArray<mirror::Class>*>(interfaces));
     CHECK_EQ(synth_proxy_class->GetThrows(), soa.Decode<mirror::ObjectArray<mirror::ObjectArray<mirror::Class> >*>(throws));
   }
-  std::string descriptor(GetDescriptorForProxy(klass.get()));
-  mirror::Class* existing = InsertClass(descriptor.c_str(), klass.get(), Hash(descriptor.c_str()));
+  std::string descriptor(GetDescriptorForProxy(klass.Get()));
+  mirror::Class* existing = InsertClass(descriptor.c_str(), klass.Get(), Hash(descriptor.c_str()));
   CHECK(existing == nullptr);
-  return klass.get();
+  return klass.Get();
 }
 
 std::string ClassLinker::GetDescriptorForProxy(mirror::Class* proxy_class) {
@@ -2975,7 +2981,7 @@
 
 
 mirror::ArtMethod* ClassLinker::CreateProxyConstructor(Thread* self,
-                                                       const SirtRef<mirror::Class>& klass,
+                                                       const Handle<mirror::Class>& klass,
                                                        mirror::Class* proxy_class) {
   // Create constructor for Proxy that must initialize h
   mirror::ObjectArray<mirror::ArtMethod>* proxy_direct_methods =
@@ -2992,7 +2998,7 @@
   }
   // Make this constructor public and fix the class to be our Proxy version
   constructor->SetAccessFlags((constructor->GetAccessFlags() & ~kAccProtected) | kAccPublic);
-  constructor->SetDeclaringClass(klass.get());
+  constructor->SetDeclaringClass(klass.Get());
   return constructor;
 }
 
@@ -3006,12 +3012,12 @@
 }
 
 mirror::ArtMethod* ClassLinker::CreateProxyMethod(Thread* self,
-                                                  const SirtRef<mirror::Class>& klass,
-                                                  const SirtRef<mirror::ArtMethod>& prototype) {
+                                                  const Handle<mirror::Class>& klass,
+                                                  const Handle<mirror::ArtMethod>& prototype) {
   // Ensure prototype is in dex cache so that we can use the dex cache to look up the overridden
   // prototype method
   prototype->GetDeclaringClass()->GetDexCache()->SetResolvedMethod(prototype->GetDexMethodIndex(),
-                                                                   prototype.get());
+                                                                   prototype.Get());
   // We steal everything from the prototype (such as DexCache, invoke stub, etc.) then specialize
   // as necessary
   mirror::ArtMethod* method = down_cast<mirror::ArtMethod*>(prototype->Clone(self));
@@ -3022,16 +3028,11 @@
 
   // Set class to be the concrete proxy class and clear the abstract flag, modify exceptions to
   // the intersection of throw exceptions as defined in Proxy
-  method->SetDeclaringClass(klass.get());
+  method->SetDeclaringClass(klass.Get());
   method->SetAccessFlags((method->GetAccessFlags() & ~kAccAbstract) | kAccFinal);
 
   // At runtime the method looks like a reference and argument saving method, clone the code
   // related parameters from this method.
-  mirror::ArtMethod* refs_and_args =
-      Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs);
-  method->SetCoreSpillMask(refs_and_args->GetCoreSpillMask());
-  method->SetFpSpillMask(refs_and_args->GetFpSpillMask());
-  method->SetFrameSizeInBytes(refs_and_args->GetFrameSizeInBytes());
   method->SetEntryPointFromQuickCompiledCode(GetQuickProxyInvokeHandler());
   method->SetEntryPointFromPortableCompiledCode(GetPortableProxyInvokeHandler());
   method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
@@ -3040,7 +3041,7 @@
 }
 
 static void CheckProxyMethod(mirror::ArtMethod* method,
-                             SirtRef<mirror::ArtMethod>& prototype)
+                             Handle<mirror::ArtMethod>& prototype)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   // Basic sanity
   CHECK(!prototype->IsFinal());
@@ -3055,7 +3056,7 @@
   CHECK_EQ(prototype->GetDexMethodIndex(), method->GetDexMethodIndex());
 
   MethodHelper mh(method);
-  MethodHelper mh2(prototype.get());
+  MethodHelper mh2(prototype.Get());
   CHECK_STREQ(mh.GetName(), mh2.GetName());
   CHECK_STREQ(mh.GetShorty(), mh2.GetShorty());
   // More complex sanity - via dex cache
@@ -3101,7 +3102,7 @@
   return init_done_;
 }
 
-bool ClassLinker::InitializeClass(const SirtRef<mirror::Class>& klass, bool can_init_statics,
+bool ClassLinker::InitializeClass(const Handle<mirror::Class>& klass, bool can_init_statics,
                                   bool can_init_parents) {
   // see JLS 3rd edition, 12.4.2 "Detailed Initialization Procedure" for the locking protocol
 
@@ -3113,7 +3114,7 @@
   }
 
   // Fast fail if initialization requires a full runtime. Not part of the JLS.
-  if (!CanWeInitializeClass(klass.get(), can_init_statics, can_init_parents)) {
+  if (!CanWeInitializeClass(klass.Get(), can_init_statics, can_init_parents)) {
     return false;
   }
 
@@ -3129,11 +3130,11 @@
 
     // Was the class already found to be erroneous? Done under the lock to match the JLS.
     if (klass->IsErroneous()) {
-      ThrowEarlierClassFailure(klass.get());
+      ThrowEarlierClassFailure(klass.Get());
       return false;
     }
 
-    CHECK(klass->IsResolved()) << PrettyClass(klass.get()) << ": state=" << klass->GetStatus();
+    CHECK(klass->IsResolved()) << PrettyClass(klass.Get()) << ": state=" << klass->GetStatus();
 
     if (!klass->IsVerified()) {
       VerifyClass(klass);
@@ -3170,7 +3171,7 @@
       return false;
     }
 
-    CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusVerified) << PrettyClass(klass.get());
+    CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusVerified) << PrettyClass(klass.Get());
 
     // From here out other threads may observe that we're initializing and so changes of state
     // require the a notification.
@@ -3186,14 +3187,15 @@
     if (!super_class->IsInitialized()) {
       CHECK(!super_class->IsInterface());
       CHECK(can_init_parents);
-      SirtRef<mirror::Class> sirt_super(self, super_class);
-      bool super_initialized = InitializeClass(sirt_super, can_init_statics, true);
+      StackHandleScope<1> hs(self);
+      Handle<mirror::Class> handle_scope_super(hs.NewHandle(super_class));
+      bool super_initialized = InitializeClass(handle_scope_super, can_init_statics, true);
       if (!super_initialized) {
         // The super class was verified ahead of entering initializing, we should only be here if
         // the super class became erroneous due to initialization.
-        CHECK(sirt_super->IsErroneous() && self->IsExceptionPending())
-            << "Super class initialization failed for " << PrettyDescriptor(sirt_super.get())
-            << " that has unexpected status " << sirt_super->GetStatus()
+        CHECK(handle_scope_super->IsErroneous() && self->IsExceptionPending())
+            << "Super class initialization failed for " << PrettyDescriptor(handle_scope_super.Get())
+            << " that has unexpected status " << handle_scope_super->GetStatus()
             << "\nPending exception:\n"
             << (self->GetException(NULL) != NULL ? self->GetException(NULL)->Dump() : "");
         ObjectLock<mirror::Class> lock(self, &klass);
@@ -3205,19 +3207,20 @@
   }
 
   if (klass->NumStaticFields() > 0) {
-    ClassHelper kh(klass.get());
+    ClassHelper kh(klass.Get());
     const DexFile::ClassDef* dex_class_def = kh.GetClassDef();
     CHECK(dex_class_def != NULL);
     const DexFile& dex_file = kh.GetDexFile();
-    SirtRef<mirror::ClassLoader> class_loader(self, klass->GetClassLoader());
-    SirtRef<mirror::DexCache> dex_cache(self, kh.GetDexCache());
+    StackHandleScope<2> hs(self);
+    Handle<mirror::ClassLoader> class_loader(hs.NewHandle(klass->GetClassLoader()));
+    Handle<mirror::DexCache> dex_cache(hs.NewHandle(kh.GetDexCache()));
     EncodedStaticFieldValueIterator it(dex_file, &dex_cache, &class_loader,
                                        this, *dex_class_def);
     if (it.HasNext()) {
       CHECK(can_init_statics);
       // We reordered the fields, so we need to be able to map the field indexes to the right fields.
       SafeMap<uint32_t, mirror::ArtField*> field_map;
-      ConstructFieldMap(dex_file, *dex_class_def, klass.get(), field_map);
+      ConstructFieldMap(dex_file, *dex_class_def, klass.Get(), field_map);
       for (size_t i = 0; it.HasNext(); i++, it.Next()) {
         if (Runtime::Current()->IsActiveTransaction()) {
           it.ReadValueToField<true>(field_map.Get(i));
@@ -3255,17 +3258,17 @@
       // Set the class as initialized except if failed to initialize static fields.
       klass->SetStatus(mirror::Class::kStatusInitialized, self);
       if (VLOG_IS_ON(class_linker)) {
-        ClassHelper kh(klass.get());
+        ClassHelper kh(klass.Get());
         LOG(INFO) << "Initialized class " << kh.GetDescriptor() << " from " << kh.GetLocation();
       }
       // Opportunistically set static method trampolines to their destination.
-      FixupStaticTrampolines(klass.get());
+      FixupStaticTrampolines(klass.Get());
     }
   }
   return success;
 }
 
-bool ClassLinker::WaitForInitializeClass(const SirtRef<mirror::Class>& klass, Thread* self,
+bool ClassLinker::WaitForInitializeClass(const Handle<mirror::Class>& klass, Thread* self,
                                          ObjectLock<mirror::Class>& lock)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   while (true) {
@@ -3293,19 +3296,19 @@
       // The caller wants an exception, but it was thrown in a
       // different thread.  Synthesize one here.
       ThrowNoClassDefFoundError("<clinit> failed for class %s; see exception in other thread",
-                                PrettyDescriptor(klass.get()).c_str());
+                                PrettyDescriptor(klass.Get()).c_str());
       return false;
     }
     if (klass->IsInitialized()) {
       return true;
     }
-    LOG(FATAL) << "Unexpected class status. " << PrettyClass(klass.get()) << " is "
+    LOG(FATAL) << "Unexpected class status. " << PrettyClass(klass.Get()) << " is "
         << klass->GetStatus();
   }
-  LOG(FATAL) << "Not Reached" << PrettyClass(klass.get());
+  LOG(FATAL) << "Not Reached" << PrettyClass(klass.Get());
 }
 
-bool ClassLinker::ValidateSuperClassDescriptors(const SirtRef<mirror::Class>& klass) {
+bool ClassLinker::ValidateSuperClassDescriptors(const Handle<mirror::Class>& klass) {
   if (klass->IsInterface()) {
     return true;
   }
@@ -3319,8 +3322,8 @@
       super_mh.ChangeMethod(klass->GetSuperClass()->GetVTable()->GetWithoutChecks(i));
       bool is_override = mh.GetMethod() != super_mh.GetMethod();
       if (is_override && !mh.HasSameSignatureWithDifferentClassLoaders(&super_mh)) {
-        ThrowLinkageError(klass.get(), "Class %s method %s resolves differently in superclass %s",
-                          PrettyDescriptor(klass.get()).c_str(),
+        ThrowLinkageError(klass.Get(), "Class %s method %s resolves differently in superclass %s",
+                          PrettyDescriptor(klass.Get()).c_str(),
                           PrettyMethod(mh.GetMethod()).c_str(),
                           PrettyDescriptor(klass->GetSuperClass()).c_str());
         return false;
@@ -3335,8 +3338,8 @@
         super_mh.ChangeMethod(klass->GetIfTable()->GetInterface(i)->GetVirtualMethod(j));
         bool is_override = mh.GetMethod() != super_mh.GetMethod();
         if (is_override && !mh.HasSameSignatureWithDifferentClassLoaders(&super_mh)) {
-          ThrowLinkageError(klass.get(), "Class %s method %s resolves differently in interface %s",
-                            PrettyDescriptor(klass.get()).c_str(),
+          ThrowLinkageError(klass.Get(), "Class %s method %s resolves differently in interface %s",
+                            PrettyDescriptor(klass.Get()).c_str(),
                             PrettyMethod(mh.GetMethod()).c_str(),
                             PrettyDescriptor(klass->GetIfTable()->GetInterface(i)).c_str());
           return false;
@@ -3347,9 +3350,9 @@
   return true;
 }
 
-bool ClassLinker::EnsureInitialized(const SirtRef<mirror::Class>& c, bool can_init_fields,
+bool ClassLinker::EnsureInitialized(const Handle<mirror::Class>& c, bool can_init_fields,
                                     bool can_init_parents) {
-  DCHECK(c.get() != NULL);
+  DCHECK(c.Get() != NULL);
   if (c->IsInitialized()) {
     return true;
   }
@@ -3357,7 +3360,7 @@
   bool success = InitializeClass(c, can_init_fields, can_init_parents);
   if (!success) {
     if (can_init_fields && can_init_parents) {
-      CHECK(Thread::Current()->IsExceptionPending()) << PrettyClass(c.get());
+      CHECK(Thread::Current()->IsExceptionPending()) << PrettyClass(c.Get());
     }
   }
   return success;
@@ -3368,17 +3371,17 @@
                                     SafeMap<uint32_t, mirror::ArtField*>& field_map) {
   const byte* class_data = dex_file.GetClassData(dex_class_def);
   ClassDataItemIterator it(dex_file, class_data);
-  Thread* self = Thread::Current();
-  SirtRef<mirror::DexCache> dex_cache(self, c->GetDexCache());
-  SirtRef<mirror::ClassLoader> class_loader(self, c->GetClassLoader());
+  StackHandleScope<2> hs(Thread::Current());
+  Handle<mirror::DexCache> dex_cache(hs.NewHandle(c->GetDexCache()));
+  Handle<mirror::ClassLoader> class_loader(hs.NewHandle(c->GetClassLoader()));
   CHECK(!kMovingFields);
   for (size_t i = 0; it.HasNextStaticField(); i++, it.Next()) {
     field_map.Put(i, ResolveField(dex_file, it.GetMemberIndex(), dex_cache, class_loader, true));
   }
 }
 
-bool ClassLinker::LinkClass(Thread* self, const SirtRef<mirror::Class>& klass,
-                            const SirtRef<mirror::ObjectArray<mirror::Class> >& interfaces) {
+bool ClassLinker::LinkClass(Thread* self, const Handle<mirror::Class>& klass,
+                            const Handle<mirror::ObjectArray<mirror::Class> >& interfaces) {
   CHECK_EQ(mirror::Class::kStatusLoaded, klass->GetStatus());
   if (!LinkSuperClass(klass)) {
     return false;
@@ -3399,22 +3402,22 @@
   return true;
 }
 
-bool ClassLinker::LoadSuperAndInterfaces(const SirtRef<mirror::Class>& klass,
+bool ClassLinker::LoadSuperAndInterfaces(const Handle<mirror::Class>& klass,
                                          const DexFile& dex_file) {
   CHECK_EQ(mirror::Class::kStatusIdx, klass->GetStatus());
   const DexFile::ClassDef& class_def = dex_file.GetClassDef(klass->GetDexClassDefIndex());
   uint16_t super_class_idx = class_def.superclass_idx_;
   if (super_class_idx != DexFile::kDexNoIndex16) {
-    mirror::Class* super_class = ResolveType(dex_file, super_class_idx, klass.get());
+    mirror::Class* super_class = ResolveType(dex_file, super_class_idx, klass.Get());
     if (super_class == NULL) {
       DCHECK(Thread::Current()->IsExceptionPending());
       return false;
     }
     // Verify
     if (!klass->CanAccess(super_class)) {
-      ThrowIllegalAccessError(klass.get(), "Class %s extended by class %s is inaccessible",
+      ThrowIllegalAccessError(klass.Get(), "Class %s extended by class %s is inaccessible",
                               PrettyDescriptor(super_class).c_str(),
-                              PrettyDescriptor(klass.get()).c_str());
+                              PrettyDescriptor(klass.Get()).c_str());
       return false;
     }
     klass->SetSuperClass(super_class);
@@ -3423,7 +3426,7 @@
   if (interfaces != NULL) {
     for (size_t i = 0; i < interfaces->Size(); i++) {
       uint16_t idx = interfaces->GetTypeItem(i).type_idx_;
-      mirror::Class* interface = ResolveType(dex_file, idx, klass.get());
+      mirror::Class* interface = ResolveType(dex_file, idx, klass.Get());
       if (interface == NULL) {
         DCHECK(Thread::Current()->IsExceptionPending());
         return false;
@@ -3431,9 +3434,9 @@
       // Verify
       if (!klass->CanAccess(interface)) {
         // TODO: the RI seemed to ignore this in my testing.
-        ThrowIllegalAccessError(klass.get(), "Interface %s implemented by class %s is inaccessible",
+        ThrowIllegalAccessError(klass.Get(), "Interface %s implemented by class %s is inaccessible",
                                 PrettyDescriptor(interface).c_str(),
-                                PrettyDescriptor(klass.get()).c_str());
+                                PrettyDescriptor(klass.Get()).c_str());
         return false;
       }
     }
@@ -3443,33 +3446,33 @@
   return true;
 }
 
-bool ClassLinker::LinkSuperClass(const SirtRef<mirror::Class>& klass) {
+bool ClassLinker::LinkSuperClass(const Handle<mirror::Class>& klass) {
   CHECK(!klass->IsPrimitive());
   mirror::Class* super = klass->GetSuperClass();
-  if (klass.get() == GetClassRoot(kJavaLangObject)) {
+  if (klass.Get() == GetClassRoot(kJavaLangObject)) {
     if (super != NULL) {
-      ThrowClassFormatError(klass.get(), "java.lang.Object must not have a superclass");
+      ThrowClassFormatError(klass.Get(), "java.lang.Object must not have a superclass");
       return false;
     }
     return true;
   }
   if (super == NULL) {
-    ThrowLinkageError(klass.get(), "No superclass defined for class %s",
-                      PrettyDescriptor(klass.get()).c_str());
+    ThrowLinkageError(klass.Get(), "No superclass defined for class %s",
+                      PrettyDescriptor(klass.Get()).c_str());
     return false;
   }
   // Verify
   if (super->IsFinal() || super->IsInterface()) {
-    ThrowIncompatibleClassChangeError(klass.get(), "Superclass %s of %s is %s",
+    ThrowIncompatibleClassChangeError(klass.Get(), "Superclass %s of %s is %s",
                                       PrettyDescriptor(super).c_str(),
-                                      PrettyDescriptor(klass.get()).c_str(),
+                                      PrettyDescriptor(klass.Get()).c_str(),
                                       super->IsFinal() ? "declared final" : "an interface");
     return false;
   }
   if (!klass->CanAccess(super)) {
-    ThrowIllegalAccessError(klass.get(), "Superclass %s is inaccessible to class %s",
+    ThrowIllegalAccessError(klass.Get(), "Superclass %s is inaccessible to class %s",
                             PrettyDescriptor(super).c_str(),
-                            PrettyDescriptor(klass.get()).c_str());
+                            PrettyDescriptor(klass.Get()).c_str());
     return false;
   }
 
@@ -3485,9 +3488,9 @@
   }
   // Disallow custom direct subclasses of java.lang.ref.Reference.
   if (init_done_ && super == GetClassRoot(kJavaLangRefReference)) {
-    ThrowLinkageError(klass.get(),
+    ThrowLinkageError(klass.Get(),
                       "Class %s attempts to subclass java.lang.ref.Reference, which is not allowed",
-                      PrettyDescriptor(klass.get()).c_str());
+                      PrettyDescriptor(klass.Get()).c_str());
     return false;
   }
 
@@ -3502,13 +3505,13 @@
 }
 
 // Populate the class vtable and itable. Compute return type indices.
-bool ClassLinker::LinkMethods(const SirtRef<mirror::Class>& klass,
-                              const SirtRef<mirror::ObjectArray<mirror::Class> >& interfaces) {
+bool ClassLinker::LinkMethods(const Handle<mirror::Class>& klass,
+                              const Handle<mirror::ObjectArray<mirror::Class> >& interfaces) {
   if (klass->IsInterface()) {
     // No vtable.
     size_t count = klass->NumVirtualMethods();
     if (!IsUint(16, count)) {
-      ThrowClassFormatError(klass.get(), "Too many methods on interface: %zd", count);
+      ThrowClassFormatError(klass.Get(), "Too many methods on interface: %zd", count);
       return false;
     }
     for (size_t i = 0; i < count; ++i) {
@@ -3523,16 +3526,17 @@
   return true;
 }
 
-bool ClassLinker::LinkVirtualMethods(const SirtRef<mirror::Class>& klass) {
+bool ClassLinker::LinkVirtualMethods(const Handle<mirror::Class>& klass) {
   Thread* self = Thread::Current();
   if (klass->HasSuperClass()) {
     uint32_t max_count = klass->NumVirtualMethods() + klass->GetSuperClass()->GetVTable()->GetLength();
     size_t actual_count = klass->GetSuperClass()->GetVTable()->GetLength();
     CHECK_LE(actual_count, max_count);
     // TODO: do not assign to the vtable field until it is fully constructed.
-    SirtRef<mirror::ObjectArray<mirror::ArtMethod> >
-      vtable(self, klass->GetSuperClass()->GetVTable()->CopyOf(self, max_count));
-    if (UNLIKELY(vtable.get() == NULL)) {
+    StackHandleScope<1> hs(self);
+    Handle<mirror::ObjectArray<mirror::ArtMethod>> vtable(
+        hs.NewHandle(klass->GetSuperClass()->GetVTable()->CopyOf(self, max_count)));
+    if (UNLIKELY(vtable.Get() == NULL)) {
       CHECK(self->IsExceptionPending());  // OOME.
       return false;
     }
@@ -3547,7 +3551,7 @@
         if (local_mh.HasSameNameAndSignature(&super_mh)) {
           if (klass->CanAccessMember(super_method->GetDeclaringClass(), super_method->GetAccessFlags())) {
             if (super_method->IsFinal()) {
-              ThrowLinkageError(klass.get(), "Method %s overrides final method in class %s",
+              ThrowLinkageError(klass.Get(), "Method %s overrides final method in class %s",
                                 PrettyMethod(local_method).c_str(),
                                 super_mh.GetDeclaringClassDescriptor());
               return false;
@@ -3570,29 +3574,30 @@
       }
     }
     if (!IsUint(16, actual_count)) {
-      ThrowClassFormatError(klass.get(), "Too many methods defined on class: %zd", actual_count);
+      ThrowClassFormatError(klass.Get(), "Too many methods defined on class: %zd", actual_count);
       return false;
     }
     // Shrink vtable if possible
     CHECK_LE(actual_count, max_count);
     if (actual_count < max_count) {
-      vtable.reset(vtable->CopyOf(self, actual_count));
-      if (UNLIKELY(vtable.get() == NULL)) {
+      vtable.Assign(vtable->CopyOf(self, actual_count));
+      if (UNLIKELY(vtable.Get() == NULL)) {
         CHECK(self->IsExceptionPending());  // OOME.
         return false;
       }
     }
-    klass->SetVTable(vtable.get());
+    klass->SetVTable(vtable.Get());
   } else {
-    CHECK(klass.get() == GetClassRoot(kJavaLangObject));
+    CHECK(klass.Get() == GetClassRoot(kJavaLangObject));
     uint32_t num_virtual_methods = klass->NumVirtualMethods();
     if (!IsUint(16, num_virtual_methods)) {
-      ThrowClassFormatError(klass.get(), "Too many methods: %d", num_virtual_methods);
+      ThrowClassFormatError(klass.Get(), "Too many methods: %d", num_virtual_methods);
       return false;
     }
-    SirtRef<mirror::ObjectArray<mirror::ArtMethod> >
-        vtable(self, AllocArtMethodArray(self, num_virtual_methods));
-    if (UNLIKELY(vtable.get() == NULL)) {
+    StackHandleScope<1> hs(self);
+    Handle<mirror::ObjectArray<mirror::ArtMethod> >
+        vtable(hs.NewHandle(AllocArtMethodArray(self, num_virtual_methods)));
+    if (UNLIKELY(vtable.Get() == NULL)) {
       CHECK(self->IsExceptionPending());  // OOME.
       return false;
     }
@@ -3601,13 +3606,13 @@
       vtable->Set<false>(i, virtual_method);
       virtual_method->SetMethodIndex(i & 0xFFFF);
     }
-    klass->SetVTable(vtable.get());
+    klass->SetVTable(vtable.Get());
   }
   return true;
 }
 
-bool ClassLinker::LinkInterfaceMethods(const SirtRef<mirror::Class>& klass,
-                                       const SirtRef<mirror::ObjectArray<mirror::Class> >& interfaces) {
+bool ClassLinker::LinkInterfaceMethods(const Handle<mirror::Class>& klass,
+                                       const Handle<mirror::ObjectArray<mirror::Class> >& interfaces) {
   // Set the imt table to be all conflicts by default.
   klass->SetImTable(Runtime::Current()->GetDefaultImt());
   size_t super_ifcount;
@@ -3619,13 +3624,13 @@
   size_t ifcount = super_ifcount;
   uint32_t num_interfaces;
   {
-    ClassHelper kh(klass.get());
+    ClassHelper kh(klass.Get());
     num_interfaces =
-        interfaces.get() == nullptr ? kh.NumDirectInterfaces() : interfaces->GetLength();
+        interfaces.Get() == nullptr ? kh.NumDirectInterfaces() : interfaces->GetLength();
     ifcount += num_interfaces;
     for (size_t i = 0; i < num_interfaces; i++) {
       mirror::Class* interface =
-          interfaces.get() == nullptr ? kh.GetDirectInterface(i) : interfaces->Get(i);
+          interfaces.Get() == nullptr ? kh.GetDirectInterface(i) : interfaces->Get(i);
       ifcount += interface->GetIfTableCount();
     }
   }
@@ -3652,8 +3657,9 @@
     }
   }
   Thread* self = Thread::Current();
-  SirtRef<mirror::IfTable> iftable(self, AllocIfTable(self, ifcount));
-  if (UNLIKELY(iftable.get() == NULL)) {
+  StackHandleScope<2> hs(self);
+  Handle<mirror::IfTable> iftable(hs.NewHandle(AllocIfTable(self, ifcount)));
+  if (UNLIKELY(iftable.Get() == NULL)) {
     CHECK(self->IsExceptionPending());  // OOME.
     return false;
   }
@@ -3667,14 +3673,14 @@
   // Flatten the interface inheritance hierarchy.
   size_t idx = super_ifcount;
   for (size_t i = 0; i < num_interfaces; i++) {
-    ClassHelper kh(klass.get());
+    ClassHelper kh(klass.Get());
     mirror::Class* interface =
-        interfaces.get() == nullptr ? kh.GetDirectInterface(i) : interfaces->Get(i);
+        interfaces.Get() == nullptr ? kh.GetDirectInterface(i) : interfaces->Get(i);
     DCHECK(interface != NULL);
     if (!interface->IsInterface()) {
       ClassHelper ih(interface);
-      ThrowIncompatibleClassChangeError(klass.get(), "Class %s implements non-interface class %s",
-                                        PrettyDescriptor(klass.get()).c_str(),
+      ThrowIncompatibleClassChangeError(klass.Get(), "Class %s implements non-interface class %s",
+                                        PrettyDescriptor(klass.Get()).c_str(),
                                         PrettyDescriptor(ih.GetDescriptor()).c_str());
       return false;
     }
@@ -3709,8 +3715,8 @@
   }
   // Shrink iftable in case duplicates were found
   if (idx < ifcount) {
-    iftable.reset(down_cast<mirror::IfTable*>(iftable->CopyOf(self, idx * mirror::IfTable::kMax)));
-    if (UNLIKELY(iftable.get() == NULL)) {
+    iftable.Assign(down_cast<mirror::IfTable*>(iftable->CopyOf(self, idx * mirror::IfTable::kMax)));
+    if (UNLIKELY(iftable.Get() == NULL)) {
       CHECK(self->IsExceptionPending());  // OOME.
       return false;
     }
@@ -3718,7 +3724,7 @@
   } else {
     CHECK_EQ(idx, ifcount);
   }
-  klass->SetIfTable(iftable.get());
+  klass->SetIfTable(iftable.Get());
 
   // If we're an interface, we don't need the vtable pointers, so we're done.
   if (klass->IsInterface()) {
@@ -3726,8 +3732,9 @@
   }
   // Allocate imtable
   bool imtable_changed = false;
-  SirtRef<mirror::ObjectArray<mirror::ArtMethod> > imtable(self, AllocArtMethodArray(self, kImtSize));
-  if (UNLIKELY(imtable.get() == NULL)) {
+  Handle<mirror::ObjectArray<mirror::ArtMethod> > imtable(
+      hs.NewHandle(AllocArtMethodArray(self, kImtSize)));
+  if (UNLIKELY(imtable.Get() == NULL)) {
     CHECK(self->IsExceptionPending());  // OOME.
     return false;
   }
@@ -3735,15 +3742,16 @@
   for (size_t i = 0; i < ifcount; ++i) {
     size_t num_methods = iftable->GetInterface(i)->NumVirtualMethods();
     if (num_methods > 0) {
-      SirtRef<mirror::ObjectArray<mirror::ArtMethod> >
-          method_array(self, AllocArtMethodArray(self, num_methods));
-      if (UNLIKELY(method_array.get() == nullptr)) {
+      StackHandleScope<2> hs(self);
+      Handle<mirror::ObjectArray<mirror::ArtMethod> >
+          method_array(hs.NewHandle(AllocArtMethodArray(self, num_methods)));
+      if (UNLIKELY(method_array.Get() == nullptr)) {
         CHECK(self->IsExceptionPending());  // OOME.
         return false;
       }
-      iftable->SetMethodArray(i, method_array.get());
-      SirtRef<mirror::ObjectArray<mirror::ArtMethod> > vtable(self,
-                                                              klass->GetVTableDuringLinking());
+      iftable->SetMethodArray(i, method_array.Get());
+      Handle<mirror::ObjectArray<mirror::ArtMethod> > vtable(
+          hs.NewHandle(klass->GetVTableDuringLinking()));
       for (size_t j = 0; j < num_methods; ++j) {
         mirror::ArtMethod* interface_method = iftable->GetInterface(i)->GetVirtualMethod(j);
         MethodHelper interface_mh(interface_method);
@@ -3761,7 +3769,7 @@
           MethodHelper vtable_mh(vtable_method);
           if (interface_mh.HasSameNameAndSignature(&vtable_mh)) {
             if (!vtable_method->IsAbstract() && !vtable_method->IsPublic()) {
-              ThrowIllegalAccessError(klass.get(),
+              ThrowIllegalAccessError(klass.Get(),
                                       "Method '%s' implementing interface method '%s' is not public",
                                       PrettyMethod(vtable_method).c_str(),
                                       PrettyMethod(interface_method).c_str());
@@ -3780,26 +3788,27 @@
           }
         }
         if (k < 0) {
-          SirtRef<mirror::ArtMethod> miranda_method(self, NULL);
+          StackHandleScope<1> hs(self);
+          auto miranda_method = hs.NewHandle<mirror::ArtMethod>(nullptr);
           for (size_t mir = 0; mir < miranda_list.size(); mir++) {
             mirror::ArtMethod* mir_method = miranda_list[mir];
             MethodHelper vtable_mh(mir_method);
             if (interface_mh.HasSameNameAndSignature(&vtable_mh)) {
-              miranda_method.reset(miranda_list[mir]);
+              miranda_method.Assign(miranda_list[mir]);
               break;
             }
           }
-          if (miranda_method.get() == NULL) {
+          if (miranda_method.Get() == NULL) {
             // Point the interface table at a phantom slot.
-            miranda_method.reset(down_cast<mirror::ArtMethod*>(interface_method->Clone(self)));
-            if (UNLIKELY(miranda_method.get() == NULL)) {
+            miranda_method.Assign(down_cast<mirror::ArtMethod*>(interface_method->Clone(self)));
+            if (UNLIKELY(miranda_method.Get() == NULL)) {
               CHECK(self->IsExceptionPending());  // OOME.
               return false;
             }
             // TODO: If a methods move then the miranda_list may hold stale references.
-            miranda_list.push_back(miranda_method.get());
+            miranda_list.push_back(miranda_method.Get());
           }
-          method_array->Set<false>(j, miranda_method.get());
+          method_array->Set<false>(j, miranda_method.Get());
         }
       }
     }
@@ -3812,7 +3821,7 @@
         imtable->Set<false>(i, imt_conflict_method);
       }
     }
-    klass->SetImTable(imtable.get());
+    klass->SetImTable(imtable.Get());
   }
   if (!miranda_list.empty()) {
     int old_method_count = klass->NumVirtualMethods();
@@ -3829,13 +3838,14 @@
     }
     klass->SetVirtualMethods(virtuals);
 
-    SirtRef<mirror::ObjectArray<mirror::ArtMethod> >
-        vtable(self, klass->GetVTableDuringLinking());
-    CHECK(vtable.get() != NULL);
+    StackHandleScope<1> hs(self);
+    Handle<mirror::ObjectArray<mirror::ArtMethod> > vtable(
+        hs.NewHandle(klass->GetVTableDuringLinking()));
+    CHECK(vtable.Get() != NULL);
     int old_vtable_count = vtable->GetLength();
     int new_vtable_count = old_vtable_count + miranda_list.size();
-    vtable.reset(vtable->CopyOf(self, new_vtable_count));
-    if (UNLIKELY(vtable.get() == NULL)) {
+    vtable.Assign(vtable->CopyOf(self, new_vtable_count));
+    if (UNLIKELY(vtable.Get() == NULL)) {
       CHECK(self->IsExceptionPending());  // OOME.
       return false;
     }
@@ -3848,7 +3858,7 @@
       vtable->Set<false>(old_vtable_count + i, method);
     }
     // TODO: do not assign to the vtable field until it is fully constructed.
-    klass->SetVTable(vtable.get());
+    klass->SetVTable(vtable.Get());
   }
 
   mirror::ObjectArray<mirror::ArtMethod>* vtable = klass->GetVTableDuringLinking();
@@ -3861,13 +3871,13 @@
   return true;
 }
 
-bool ClassLinker::LinkInstanceFields(const SirtRef<mirror::Class>& klass) {
-  CHECK(klass.get() != NULL);
+bool ClassLinker::LinkInstanceFields(const Handle<mirror::Class>& klass) {
+  CHECK(klass.Get() != NULL);
   return LinkFields(klass, false);
 }
 
-bool ClassLinker::LinkStaticFields(const SirtRef<mirror::Class>& klass) {
-  CHECK(klass.get() != NULL);
+bool ClassLinker::LinkStaticFields(const Handle<mirror::Class>& klass) {
+  CHECK(klass.Get() != NULL);
   size_t allocated_class_size = klass->GetClassSize();
   bool success = LinkFields(klass, true);
   CHECK_EQ(allocated_class_size, klass->GetClassSize());
@@ -3903,7 +3913,7 @@
   }
 };
 
-bool ClassLinker::LinkFields(const SirtRef<mirror::Class>& klass, bool is_static) {
+bool ClassLinker::LinkFields(const Handle<mirror::Class>& klass, bool is_static) {
   size_t num_fields =
       is_static ? klass->NumStaticFields() : klass->NumInstanceFields();
 
@@ -3998,7 +4008,7 @@
 
   // We lie to the GC about the java.lang.ref.Reference.referent field, so it doesn't scan it.
   if (!is_static &&
-      (strcmp("Ljava/lang/ref/Reference;", ClassHelper(klass.get()).GetDescriptor()) == 0)) {
+      (strcmp("Ljava/lang/ref/Reference;", ClassHelper(klass.Get()).GetDescriptor()) == 0)) {
     // We know there are no non-reference fields in the Reference classes, and we know
     // that 'referent' is alphabetically last, so this is easy...
     CHECK_EQ(num_reference_fields, num_fields);
@@ -4015,7 +4025,7 @@
       mirror::ArtField* field = fields->Get(i);
       if (false) {  // enable to debug field layout
         LOG(INFO) << "LinkFields: " << (is_static ? "static" : "instance")
-                    << " class=" << PrettyClass(klass.get())
+                    << " class=" << PrettyClass(klass.Get())
                     << " field=" << PrettyField(field)
                     << " offset="
                     << field->GetField32(MemberOffset(mirror::ArtField::OffsetOffset()));
@@ -4023,7 +4033,7 @@
       FieldHelper fh(field);
       Primitive::Type type = fh.GetTypeAsPrimitiveType();
       bool is_primitive = type != Primitive::kPrimNot;
-      if ((strcmp("Ljava/lang/ref/Reference;", ClassHelper(klass.get()).GetDescriptor()) == 0)
+      if ((strcmp("Ljava/lang/ref/Reference;", ClassHelper(klass.Get()).GetDescriptor()) == 0)
           && (strcmp("referent", fh.GetName()) == 0)) {
         is_primitive = true;  // We lied above, so we have to expect a lie here.
       }
@@ -4048,7 +4058,7 @@
   } else {
     klass->SetNumReferenceInstanceFields(num_reference_fields);
     if (!klass->IsVariableSize()) {
-      DCHECK_GE(size, sizeof(mirror::Object)) << ClassHelper(klass.get()).GetDescriptor();
+      DCHECK_GE(size, sizeof(mirror::Object)) << ClassHelper(klass.Get()).GetDescriptor();
       size_t previous_size = klass->GetObjectSize();
       if (previous_size != 0) {
         // Make sure that we didn't originally have an incorrect size.
@@ -4062,7 +4072,7 @@
 
 //  Set the bitmap of reference offsets, refOffsets, from the ifields
 //  list.
-void ClassLinker::CreateReferenceInstanceOffsets(const SirtRef<mirror::Class>& klass) {
+void ClassLinker::CreateReferenceInstanceOffsets(const Handle<mirror::Class>& klass) {
   uint32_t reference_offsets = 0;
   mirror::Class* super_class = klass->GetSuperClass();
   if (super_class != NULL) {
@@ -4076,11 +4086,11 @@
   CreateReferenceOffsets(klass, false, reference_offsets);
 }
 
-void ClassLinker::CreateReferenceStaticOffsets(const SirtRef<mirror::Class>& klass) {
+void ClassLinker::CreateReferenceStaticOffsets(const Handle<mirror::Class>& klass) {
   CreateReferenceOffsets(klass, true, 0);
 }
 
-void ClassLinker::CreateReferenceOffsets(const SirtRef<mirror::Class>& klass, bool is_static,
+void ClassLinker::CreateReferenceOffsets(const Handle<mirror::Class>& klass, bool is_static,
                                          uint32_t reference_offsets) {
   size_t num_reference_fields =
       is_static ? klass->NumReferenceStaticFieldsDuringLinking()
@@ -4113,8 +4123,8 @@
 }
 
 mirror::String* ClassLinker::ResolveString(const DexFile& dex_file, uint32_t string_idx,
-                                           const SirtRef<mirror::DexCache>& dex_cache) {
-  DCHECK(dex_cache.get() != nullptr);
+                                           const Handle<mirror::DexCache>& dex_cache) {
+  DCHECK(dex_cache.Get() != nullptr);
   mirror::String* resolved = dex_cache->GetResolvedString(string_idx);
   if (resolved != NULL) {
     return resolved;
@@ -4128,16 +4138,16 @@
 
 mirror::Class* ClassLinker::ResolveType(const DexFile& dex_file, uint16_t type_idx,
                                         mirror::Class* referrer) {
-  Thread* self = Thread::Current();
-  SirtRef<mirror::DexCache> dex_cache(self, referrer->GetDexCache());
-  SirtRef<mirror::ClassLoader> class_loader(self, referrer->GetClassLoader());
+  StackHandleScope<2> hs(Thread::Current());
+  Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache()));
+  Handle<mirror::ClassLoader> class_loader(hs.NewHandle(referrer->GetClassLoader()));
   return ResolveType(dex_file, type_idx, dex_cache, class_loader);
 }
 
 mirror::Class* ClassLinker::ResolveType(const DexFile& dex_file, uint16_t type_idx,
-                                        const SirtRef<mirror::DexCache>& dex_cache,
-                                        const SirtRef<mirror::ClassLoader>& class_loader) {
-  DCHECK(dex_cache.get() != NULL);
+                                        const Handle<mirror::DexCache>& dex_cache,
+                                        const Handle<mirror::ClassLoader>& class_loader) {
+  DCHECK(dex_cache.Get() != NULL);
   mirror::Class* resolved = dex_cache->GetResolvedType(type_idx);
   if (resolved == NULL) {
     Thread* self = Thread::Current();
@@ -4152,12 +4162,13 @@
       CHECK(self->IsExceptionPending())
           << "Expected pending exception for failed resolution of: " << descriptor;
       // Convert a ClassNotFoundException to a NoClassDefFoundError.
-      SirtRef<mirror::Throwable> cause(self, self->GetException(NULL));
+      StackHandleScope<1> hs(self);
+      Handle<mirror::Throwable> cause(hs.NewHandle(self->GetException(nullptr)));
       if (cause->InstanceOf(GetClassRoot(kJavaLangClassNotFoundException))) {
-        DCHECK(resolved == NULL);  // No SirtRef needed to preserve resolved.
+        DCHECK(resolved == NULL);  // No Handle needed to preserve resolved.
         self->ClearException();
         ThrowNoClassDefFoundError("Failed resolution of: %s", descriptor);
-        self->GetException(NULL)->SetCause(cause.get());
+        self->GetException(NULL)->SetCause(cause.Get());
       }
     }
   }
@@ -4168,11 +4179,11 @@
 
 mirror::ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file,
                                               uint32_t method_idx,
-                                              const SirtRef<mirror::DexCache>& dex_cache,
-                                              const SirtRef<mirror::ClassLoader>& class_loader,
+                                              const Handle<mirror::DexCache>& dex_cache,
+                                              const Handle<mirror::ClassLoader>& class_loader,
                                               mirror::ArtMethod* referrer,
                                               InvokeType type) {
-  DCHECK(dex_cache.get() != NULL);
+  DCHECK(dex_cache.Get() != NULL);
   // Check for hit in the dex cache.
   mirror::ArtMethod* resolved = dex_cache->GetResolvedMethod(method_idx);
   if (resolved != NULL && !resolved->IsRuntimeMethod()) {
@@ -4190,15 +4201,15 @@
   switch (type) {
     case kDirect:  // Fall-through.
     case kStatic:
-      resolved = klass->FindDirectMethod(dex_cache.get(), method_idx);
+      resolved = klass->FindDirectMethod(dex_cache.Get(), method_idx);
       break;
     case kInterface:
-      resolved = klass->FindInterfaceMethod(dex_cache.get(), method_idx);
+      resolved = klass->FindInterfaceMethod(dex_cache.Get(), method_idx);
       DCHECK(resolved == NULL || resolved->GetDeclaringClass()->IsInterface());
       break;
     case kSuper:  // Fall-through.
     case kVirtual:
-      resolved = klass->FindVirtualMethod(dex_cache.get(), method_idx);
+      resolved = klass->FindVirtualMethod(dex_cache.Get(), method_idx);
       break;
     default:
       LOG(FATAL) << "Unreachable - invocation type: " << type;
@@ -4314,10 +4325,10 @@
 }
 
 mirror::ArtField* ClassLinker::ResolveField(const DexFile& dex_file, uint32_t field_idx,
-                                            const SirtRef<mirror::DexCache>& dex_cache,
-                                            const SirtRef<mirror::ClassLoader>& class_loader,
+                                            const Handle<mirror::DexCache>& dex_cache,
+                                            const Handle<mirror::ClassLoader>& class_loader,
                                             bool is_static) {
-  DCHECK(dex_cache.get() != nullptr);
+  DCHECK(dex_cache.Get() != nullptr);
   mirror::ArtField* resolved = dex_cache->GetResolvedField(field_idx);
   if (resolved != NULL) {
     return resolved;
@@ -4330,9 +4341,9 @@
   }
 
   if (is_static) {
-    resolved = klass->FindStaticField(dex_cache.get(), field_idx);
+    resolved = klass->FindStaticField(dex_cache.Get(), field_idx);
   } else {
-    resolved = klass->FindInstanceField(dex_cache.get(), field_idx);
+    resolved = klass->FindInstanceField(dex_cache.Get(), field_idx);
   }
 
   if (resolved == NULL) {
@@ -4354,9 +4365,9 @@
 
 mirror::ArtField* ClassLinker::ResolveFieldJLS(const DexFile& dex_file,
                                                uint32_t field_idx,
-                                               const SirtRef<mirror::DexCache>& dex_cache,
-                                               const SirtRef<mirror::ClassLoader>& class_loader) {
-  DCHECK(dex_cache.get() != nullptr);
+                                               const Handle<mirror::DexCache>& dex_cache,
+                                               const Handle<mirror::ClassLoader>& class_loader) {
+  DCHECK(dex_cache.Get() != nullptr);
   mirror::ArtField* resolved = dex_cache->GetResolvedField(field_idx);
   if (resolved != NULL) {
     return resolved;
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 2c6873e..3dac6e5 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -47,7 +47,7 @@
 class InternTable;
 template<class T> class ObjectLock;
 class ScopedObjectAccess;
-template<class T> class SirtRef;
+template<class T> class Handle;
 
 typedef bool (ClassVisitor)(mirror::Class* c, void* arg);
 
@@ -75,7 +75,7 @@
   // Finds a class by its descriptor, loading it if necessary.
   // If class_loader is null, searches boot_class_path_.
   mirror::Class* FindClass(Thread* self, const char* descriptor,
-                           const SirtRef<mirror::ClassLoader>& class_loader)
+                           const Handle<mirror::ClassLoader>& class_loader)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Finds a class by its descriptor using the "system" class loader, ie by searching the
@@ -92,7 +92,7 @@
 
   // Define a new a class based on a ClassDef from a DexFile
   mirror::Class* DefineClass(const char* descriptor,
-                             const SirtRef<mirror::ClassLoader>& class_loader,
+                             const Handle<mirror::ClassLoader>& class_loader,
                              const DexFile& dex_file, const DexFile::ClassDef& dex_class_def)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -136,7 +136,7 @@
   // Resolve a String with the given index from the DexFile, storing the
   // result in the DexCache.
   mirror::String* ResolveString(const DexFile& dex_file, uint32_t string_idx,
-                                const SirtRef<mirror::DexCache>& dex_cache)
+                                const Handle<mirror::DexCache>& dex_cache)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Resolve a Type with the given index from the DexFile, storing the
@@ -159,8 +159,8 @@
   // type, since it may be referenced from but not contained within
   // the given DexFile.
   mirror::Class* ResolveType(const DexFile& dex_file, uint16_t type_idx,
-                             const SirtRef<mirror::DexCache>& dex_cache,
-                             const SirtRef<mirror::ClassLoader>& class_loader)
+                             const Handle<mirror::DexCache>& dex_cache,
+                             const Handle<mirror::ClassLoader>& class_loader)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Resolve a method with a given ID from the DexFile, storing the
@@ -170,8 +170,8 @@
   // virtual method.
   mirror::ArtMethod* ResolveMethod(const DexFile& dex_file,
                                    uint32_t method_idx,
-                                   const SirtRef<mirror::DexCache>& dex_cache,
-                                   const SirtRef<mirror::ClassLoader>& class_loader,
+                                   const Handle<mirror::DexCache>& dex_cache,
+                                   const Handle<mirror::ClassLoader>& class_loader,
                                    mirror::ArtMethod* referrer,
                                    InvokeType type)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -191,8 +191,8 @@
   // field.
   mirror::ArtField* ResolveField(const DexFile& dex_file,
                                  uint32_t field_idx,
-                                 const SirtRef<mirror::DexCache>& dex_cache,
-                                 const SirtRef<mirror::ClassLoader>& class_loader,
+                                 const Handle<mirror::DexCache>& dex_cache,
+                                 const Handle<mirror::ClassLoader>& class_loader,
                                  bool is_static)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -202,8 +202,8 @@
   // field resolution semantics are followed.
   mirror::ArtField* ResolveFieldJLS(const DexFile& dex_file,
                                     uint32_t field_idx,
-                                    const SirtRef<mirror::DexCache>& dex_cache,
-                                    const SirtRef<mirror::ClassLoader>& class_loader)
+                                    const Handle<mirror::DexCache>& dex_cache,
+                                    const Handle<mirror::ClassLoader>& class_loader)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Get shorty from method index without resolution. Used to do handlerization.
@@ -213,7 +213,7 @@
   // Returns true on success, false if there's an exception pending.
   // can_run_clinit=false allows the compiler to attempt to init a class,
   // given the restriction that no <clinit> execution is possible.
-  bool EnsureInitialized(const SirtRef<mirror::Class>& c,
+  bool EnsureInitialized(const Handle<mirror::Class>& c,
                          bool can_init_fields, bool can_init_parents)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -224,7 +224,7 @@
   void RegisterDexFile(const DexFile& dex_file)
       LOCKS_EXCLUDED(dex_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void RegisterDexFile(const DexFile& dex_file, const SirtRef<mirror::DexCache>& dex_cache)
+  void RegisterDexFile(const DexFile& dex_file, const Handle<mirror::DexCache>& dex_cache)
       LOCKS_EXCLUDED(dex_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -315,12 +315,12 @@
                                                                               size_t length)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void VerifyClass(const SirtRef<mirror::Class>& klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void VerifyClass(const Handle<mirror::Class>& klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   bool VerifyClassUsingOatFile(const DexFile& dex_file, mirror::Class* klass,
                                mirror::Class::Status& oat_file_class_status)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void ResolveClassExceptionHandlerTypes(const DexFile& dex_file,
-                                         const SirtRef<mirror::Class>& klass)
+                                         const Handle<mirror::Class>& klass)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void ResolveMethodExceptionHandlerTypes(const DexFile& dex_file, mirror::ArtMethod* klass)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -418,12 +418,12 @@
 
 
   mirror::Class* CreateArrayClass(Thread* self, const char* descriptor,
-                                  const SirtRef<mirror::ClassLoader>& class_loader)
+                                  const Handle<mirror::ClassLoader>& class_loader)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void AppendToBootClassPath(const DexFile& dex_file)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void AppendToBootClassPath(const DexFile& dex_file, const SirtRef<mirror::DexCache>& dex_cache)
+  void AppendToBootClassPath(const DexFile& dex_file, const Handle<mirror::DexCache>& dex_cache)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void ConstructFieldMap(const DexFile& dex_file, const DexFile::ClassDef& dex_class_def,
@@ -435,23 +435,23 @@
 
   void LoadClass(const DexFile& dex_file,
                  const DexFile::ClassDef& dex_class_def,
-                 const SirtRef<mirror::Class>& klass,
+                 const Handle<mirror::Class>& klass,
                  mirror::ClassLoader* class_loader)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void LoadClassMembers(const DexFile& dex_file,
                         const byte* class_data,
-                        const SirtRef<mirror::Class>& klass,
+                        const Handle<mirror::Class>& klass,
                         mirror::ClassLoader* class_loader,
                         const OatFile::OatClass* oat_class)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void LoadField(const DexFile& dex_file, const ClassDataItemIterator& it,
-                 const SirtRef<mirror::Class>& klass, const SirtRef<mirror::ArtField>& dst)
+                 const Handle<mirror::Class>& klass, const Handle<mirror::ArtField>& dst)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   mirror::ArtMethod* LoadMethod(Thread* self, const DexFile& dex_file,
                                 const ClassDataItemIterator& dex_method,
-                                const SirtRef<mirror::Class>& klass)
+                                const Handle<mirror::Class>& klass)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void FixupStaticTrampolines(mirror::Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -460,23 +460,23 @@
   OatFile::OatClass GetOatClass(const DexFile& dex_file, uint16_t class_def_idx)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void RegisterDexFileLocked(const DexFile& dex_file, const SirtRef<mirror::DexCache>& dex_cache)
+  void RegisterDexFileLocked(const DexFile& dex_file, const Handle<mirror::DexCache>& dex_cache)
       EXCLUSIVE_LOCKS_REQUIRED(dex_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   bool IsDexFileRegisteredLocked(const DexFile& dex_file) const
       SHARED_LOCKS_REQUIRED(dex_lock_, Locks::mutator_lock_);
 
-  bool InitializeClass(const SirtRef<mirror::Class>& klass, bool can_run_clinit,
+  bool InitializeClass(const Handle<mirror::Class>& klass, bool can_run_clinit,
                        bool can_init_parents)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  bool WaitForInitializeClass(const SirtRef<mirror::Class>& klass, Thread* self,
+  bool WaitForInitializeClass(const Handle<mirror::Class>& klass, Thread* self,
                               ObjectLock<mirror::Class>& lock);
-  bool ValidateSuperClassDescriptors(const SirtRef<mirror::Class>& klass)
+  bool ValidateSuperClassDescriptors(const Handle<mirror::Class>& klass)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   bool IsSameDescriptorInDifferentClassContexts(Thread* self, const char* descriptor,
-                                                SirtRef<mirror::ClassLoader>& class_loader1,
-                                                SirtRef<mirror::ClassLoader>& class_loader2)
+                                                Handle<mirror::ClassLoader>& class_loader1,
+                                                Handle<mirror::ClassLoader>& class_loader2)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   bool IsSameMethodSignatureInDifferentClassContexts(Thread* self, mirror::ArtMethod* method,
@@ -484,40 +484,40 @@
                                                      mirror::Class* klass2)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  bool LinkClass(Thread* self, const SirtRef<mirror::Class>& klass,
-                 const SirtRef<mirror::ObjectArray<mirror::Class> >& interfaces)
+  bool LinkClass(Thread* self, const Handle<mirror::Class>& klass,
+                 const Handle<mirror::ObjectArray<mirror::Class> >& interfaces)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  bool LinkSuperClass(const SirtRef<mirror::Class>& klass)
+  bool LinkSuperClass(const Handle<mirror::Class>& klass)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  bool LoadSuperAndInterfaces(const SirtRef<mirror::Class>& klass, const DexFile& dex_file)
+  bool LoadSuperAndInterfaces(const Handle<mirror::Class>& klass, const DexFile& dex_file)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  bool LinkMethods(const SirtRef<mirror::Class>& klass,
-                   const SirtRef<mirror::ObjectArray<mirror::Class> >& interfaces)
+  bool LinkMethods(const Handle<mirror::Class>& klass,
+                   const Handle<mirror::ObjectArray<mirror::Class> >& interfaces)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  bool LinkVirtualMethods(const SirtRef<mirror::Class>& klass)
+  bool LinkVirtualMethods(const Handle<mirror::Class>& klass)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  bool LinkInterfaceMethods(const SirtRef<mirror::Class>& klass,
-                            const SirtRef<mirror::ObjectArray<mirror::Class> >& interfaces)
+  bool LinkInterfaceMethods(const Handle<mirror::Class>& klass,
+                            const Handle<mirror::ObjectArray<mirror::Class> >& interfaces)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  bool LinkStaticFields(const SirtRef<mirror::Class>& klass)
+  bool LinkStaticFields(const Handle<mirror::Class>& klass)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  bool LinkInstanceFields(const SirtRef<mirror::Class>& klass)
+  bool LinkInstanceFields(const Handle<mirror::Class>& klass)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  bool LinkFields(const SirtRef<mirror::Class>& klass, bool is_static)
+  bool LinkFields(const Handle<mirror::Class>& klass, bool is_static)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 
-  void CreateReferenceInstanceOffsets(const SirtRef<mirror::Class>& klass)
+  void CreateReferenceInstanceOffsets(const Handle<mirror::Class>& klass)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void CreateReferenceStaticOffsets(const SirtRef<mirror::Class>& klass)
+  void CreateReferenceStaticOffsets(const Handle<mirror::Class>& klass)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void CreateReferenceOffsets(const SirtRef<mirror::Class>& klass, bool is_static,
+  void CreateReferenceOffsets(const Handle<mirror::Class>& klass, bool is_static,
                               uint32_t reference_offsets)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -546,11 +546,11 @@
                                                  bool* open_failed)
       LOCKS_EXCLUDED(dex_lock_);
 
-  mirror::ArtMethod* CreateProxyConstructor(Thread* self, const SirtRef<mirror::Class>& klass,
+  mirror::ArtMethod* CreateProxyConstructor(Thread* self, const Handle<mirror::Class>& klass,
                                             mirror::Class* proxy_class)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  mirror::ArtMethod* CreateProxyMethod(Thread* self, const SirtRef<mirror::Class>& klass,
-                                       const SirtRef<mirror::ArtMethod>& prototype)
+  mirror::ArtMethod* CreateProxyMethod(Thread* self, const Handle<mirror::Class>& klass,
+                                       const Handle<mirror::ArtMethod>& prototype)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   std::vector<const DexFile*> boot_class_path_;
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 1218357..0db08aa 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -34,7 +34,7 @@
 #include "mirror/proxy.h"
 #include "mirror/reference.h"
 #include "mirror/stack_trace_element.h"
-#include "sirt_ref.h"
+#include "handle_scope-inl.h"
 
 namespace art {
 
@@ -99,9 +99,10 @@
                         mirror::ClassLoader* class_loader)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     Thread* self = Thread::Current();
-    SirtRef<mirror::ClassLoader> loader(self, class_loader);
-    SirtRef<mirror::Class> array(self,
-                                 class_linker_->FindClass(self, array_descriptor.c_str(), loader));
+    StackHandleScope<2> hs(self);
+    Handle<mirror::ClassLoader> loader(hs.NewHandle(class_loader));
+    Handle<mirror::Class> array(
+        hs.NewHandle(class_linker_->FindClass(self, array_descriptor.c_str(), loader)));
     ClassHelper array_component_ch(array->GetComponentType());
     EXPECT_STREQ(component_type.c_str(), array_component_ch.GetDescriptor());
     EXPECT_EQ(class_loader, array->GetClassLoader());
@@ -109,10 +110,10 @@
     AssertArrayClass(array_descriptor, array);
   }
 
-  void AssertArrayClass(const std::string& array_descriptor, const SirtRef<mirror::Class>& array)
+  void AssertArrayClass(const std::string& array_descriptor, const Handle<mirror::Class>& array)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    ClassHelper kh(array.get());
-    ASSERT_TRUE(array.get() != NULL);
+    ClassHelper kh(array.Get());
+    ASSERT_TRUE(array.Get() != NULL);
     ASSERT_TRUE(array->GetClass() != NULL);
     ASSERT_EQ(array->GetClass(), array->GetClass()->GetClass());
     EXPECT_TRUE(array->GetClass()->GetSuperClass() != NULL);
@@ -141,17 +142,17 @@
     EXPECT_EQ(0U, array->NumVirtualMethods());
     EXPECT_EQ(0U, array->NumInstanceFields());
     EXPECT_EQ(0U, array->NumStaticFields());
-    kh.ChangeClass(array.get());
+    kh.ChangeClass(array.Get());
     EXPECT_EQ(2U, kh.NumDirectInterfaces());
     EXPECT_TRUE(array->GetVTable() != NULL);
     EXPECT_EQ(2, array->GetIfTableCount());
     ASSERT_TRUE(array->GetIfTable() != NULL);
     kh.ChangeClass(kh.GetDirectInterface(0));
     EXPECT_STREQ(kh.GetDescriptor(), "Ljava/lang/Cloneable;");
-    kh.ChangeClass(array.get());
+    kh.ChangeClass(array.Get());
     kh.ChangeClass(kh.GetDirectInterface(1));
     EXPECT_STREQ(kh.GetDescriptor(), "Ljava/io/Serializable;");
-    EXPECT_EQ(class_linker_->FindArrayClass(self, array->GetComponentType()), array.get());
+    EXPECT_EQ(class_linker_->FindArrayClass(self, array->GetComponentType()), array.Get());
   }
 
   void AssertMethod(mirror::ArtMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -182,9 +183,9 @@
     EXPECT_TRUE(fh.GetType() != NULL);
   }
 
-  void AssertClass(const std::string& descriptor, const SirtRef<mirror::Class>& klass)
+  void AssertClass(const std::string& descriptor, const Handle<mirror::Class>& klass)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    ClassHelper kh(klass.get());
+    ClassHelper kh(klass.Get());
     EXPECT_STREQ(descriptor.c_str(), kh.GetDescriptor());
     if (descriptor == "Ljava/lang/Object;") {
       EXPECT_FALSE(klass->HasSuperClass());
@@ -200,7 +201,7 @@
     EXPECT_FALSE(klass->IsErroneous());
     EXPECT_FALSE(klass->IsArrayClass());
     EXPECT_TRUE(klass->GetComponentType() == NULL);
-    EXPECT_TRUE(klass->IsInSamePackage(klass.get()));
+    EXPECT_TRUE(klass->IsInSamePackage(klass.Get()));
     EXPECT_TRUE(mirror::Class::IsInSamePackage(kh.GetDescriptor(), kh.GetDescriptor()));
     if (klass->IsInterface()) {
       EXPECT_TRUE(klass->IsAbstract());
@@ -242,31 +243,31 @@
     }
 
     EXPECT_FALSE(klass->IsPrimitive());
-    EXPECT_TRUE(klass->CanAccess(klass.get()));
+    EXPECT_TRUE(klass->CanAccess(klass.Get()));
 
     for (size_t i = 0; i < klass->NumDirectMethods(); i++) {
       mirror::ArtMethod* method = klass->GetDirectMethod(i);
       AssertMethod(method);
       EXPECT_TRUE(method->IsDirect());
-      EXPECT_EQ(klass.get(), method->GetDeclaringClass());
+      EXPECT_EQ(klass.Get(), method->GetDeclaringClass());
     }
 
     for (size_t i = 0; i < klass->NumVirtualMethods(); i++) {
       mirror::ArtMethod* method = klass->GetVirtualMethod(i);
       AssertMethod(method);
       EXPECT_FALSE(method->IsDirect());
-      EXPECT_TRUE(method->GetDeclaringClass()->IsAssignableFrom(klass.get()));
+      EXPECT_TRUE(method->GetDeclaringClass()->IsAssignableFrom(klass.Get()));
     }
 
     for (size_t i = 0; i < klass->NumInstanceFields(); i++) {
       mirror::ArtField* field = klass->GetInstanceField(i);
-      AssertField(klass.get(), field);
+      AssertField(klass.Get(), field);
       EXPECT_FALSE(field->IsStatic());
     }
 
     for (size_t i = 0; i < klass->NumStaticFields(); i++) {
       mirror::ArtField* field = klass->GetStaticField(i);
-      AssertField(klass.get(), field);
+      AssertField(klass.Get(), field);
       EXPECT_TRUE(field->IsStatic());
     }
 
@@ -294,7 +295,7 @@
     }
 
     size_t total_num_reference_instance_fields = 0;
-    mirror::Class* k = klass.get();
+    mirror::Class* k = klass.Get();
     while (k != NULL) {
       total_num_reference_instance_fields += k->NumReferenceInstanceFields();
       k = k->GetSuperClass();
@@ -306,12 +307,14 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     ASSERT_TRUE(descriptor != NULL);
     Thread* self = Thread::Current();
-    SirtRef<mirror::Class> klass(self, class_linker_->FindSystemClass(self, descriptor.c_str()));
-    ASSERT_TRUE(klass.get() != nullptr);
-    EXPECT_STREQ(descriptor.c_str(), ClassHelper(klass.get()).GetDescriptor());
+    StackHandleScope<1> hs(self);
+    Handle<mirror::Class> klass(
+        hs.NewHandle(class_linker_->FindSystemClass(self, descriptor.c_str())));
+    ASSERT_TRUE(klass.Get() != nullptr);
+    EXPECT_STREQ(descriptor.c_str(), ClassHelper(klass.Get()).GetDescriptor());
     EXPECT_EQ(class_loader, klass->GetClassLoader());
     if (klass->IsPrimitive()) {
-      AssertPrimitiveClass(descriptor, klass.get());
+      AssertPrimitiveClass(descriptor, klass.Get());
     } else if (klass->IsArrayClass()) {
       AssertArrayClass(descriptor, klass);
     } else {
@@ -491,9 +494,6 @@
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, dex_code_item_offset_),           "dexCodeItemOffset"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, dex_method_index_),               "dexMethodIndex"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, method_index_),                   "methodIndex"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, quick_core_spill_mask_),          "quickCoreSpillMask"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, quick_fp_spill_mask_),            "quickFpSpillMask"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, quick_frame_size_in_bytes_),      "quickFrameSizeInBytes"));
   };
 };
 
@@ -674,7 +674,9 @@
 
 TEST_F(ClassLinkerTest, FindClassNested) {
   ScopedObjectAccess soa(Thread::Current());
-  SirtRef<mirror::ClassLoader> class_loader(soa.Self(), soa.Decode<mirror::ClassLoader*>(LoadDex("Nested")));
+  StackHandleScope<1> hs(soa.Self());
+  Handle<mirror::ClassLoader> class_loader(
+      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Nested"))));
 
   mirror::Class* outer = class_linker_->FindClass(soa.Self(), "LNested;", class_loader);
   ASSERT_TRUE(outer != NULL);
@@ -748,7 +750,9 @@
   EXPECT_EQ(0U, JavaLangObject->NumStaticFields());
   EXPECT_EQ(0U, kh.NumDirectInterfaces());
 
-  SirtRef<mirror::ClassLoader> class_loader(soa.Self(), soa.Decode<mirror::ClassLoader*>(LoadDex("MyClass")));
+  StackHandleScope<1> hs(soa.Self());
+  Handle<mirror::ClassLoader> class_loader(
+      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("MyClass"))));
   AssertNonExistentClass("LMyClass;");
   mirror::Class* MyClass = class_linker_->FindClass(soa.Self(), "LMyClass;", class_loader);
   kh.ChangeClass(MyClass);
@@ -759,7 +763,7 @@
   ASSERT_STREQ(kh.GetDescriptor(), "LMyClass;");
   EXPECT_TRUE(MyClass->GetSuperClass() == JavaLangObject);
   EXPECT_TRUE(MyClass->HasSuperClass());
-  EXPECT_EQ(class_loader.get(), MyClass->GetClassLoader());
+  EXPECT_EQ(class_loader.Get(), MyClass->GetClassLoader());
   EXPECT_EQ(mirror::Class::kStatusResolved, MyClass->GetStatus());
   EXPECT_FALSE(MyClass->IsErroneous());
   EXPECT_TRUE(MyClass->IsLoaded());
@@ -787,7 +791,7 @@
   AssertArrayClass("[Ljava/lang/Object;", "Ljava/lang/Object;", NULL);
   // synthesized on the fly
   AssertArrayClass("[[C", "[C", NULL);
-  AssertArrayClass("[[[LMyClass;", "[[LMyClass;", class_loader.get());
+  AssertArrayClass("[[[LMyClass;", "[[LMyClass;", class_loader.Get());
   // or not available at all
   AssertNonExistentClass("[[[[LNonExistentClass;");
 }
@@ -816,27 +820,28 @@
 
 TEST_F(ClassLinkerTest, ValidatePrimitiveArrayElementsOffset) {
   ScopedObjectAccess soa(Thread::Current());
-  SirtRef<mirror::LongArray> long_array(soa.Self(), mirror::LongArray::Alloc(soa.Self(), 0));
+  StackHandleScope<5> hs(soa.Self());
+  Handle<mirror::LongArray> long_array(hs.NewHandle(mirror::LongArray::Alloc(soa.Self(), 0)));
   EXPECT_EQ(class_linker_->FindSystemClass(soa.Self(), "[J"), long_array->GetClass());
   uintptr_t data_offset = reinterpret_cast<uintptr_t>(long_array->GetData());
   EXPECT_TRUE(IsAligned<8>(data_offset));  // Longs require 8 byte alignment
 
-  SirtRef<mirror::DoubleArray> double_array(soa.Self(), mirror::DoubleArray::Alloc(soa.Self(), 0));
+  Handle<mirror::DoubleArray> double_array(hs.NewHandle(mirror::DoubleArray::Alloc(soa.Self(), 0)));
   EXPECT_EQ(class_linker_->FindSystemClass(soa.Self(), "[D"), double_array->GetClass());
   data_offset = reinterpret_cast<uintptr_t>(double_array->GetData());
   EXPECT_TRUE(IsAligned<8>(data_offset));  // Doubles require 8 byte alignment
 
-  SirtRef<mirror::IntArray> int_array(soa.Self(), mirror::IntArray::Alloc(soa.Self(), 0));
+  Handle<mirror::IntArray> int_array(hs.NewHandle(mirror::IntArray::Alloc(soa.Self(), 0)));
   EXPECT_EQ(class_linker_->FindSystemClass(soa.Self(), "[I"), int_array->GetClass());
   data_offset = reinterpret_cast<uintptr_t>(int_array->GetData());
   EXPECT_TRUE(IsAligned<4>(data_offset));  // Ints require 4 byte alignment
 
-  SirtRef<mirror::CharArray> char_array(soa.Self(), mirror::CharArray::Alloc(soa.Self(), 0));
+  Handle<mirror::CharArray> char_array(hs.NewHandle(mirror::CharArray::Alloc(soa.Self(), 0)));
   EXPECT_EQ(class_linker_->FindSystemClass(soa.Self(), "[C"), char_array->GetClass());
   data_offset = reinterpret_cast<uintptr_t>(char_array->GetData());
   EXPECT_TRUE(IsAligned<2>(data_offset));  // Chars require 2 byte alignment
 
-  SirtRef<mirror::ShortArray> short_array(soa.Self(), mirror::ShortArray::Alloc(soa.Self(), 0));
+  Handle<mirror::ShortArray> short_array(hs.NewHandle(mirror::ShortArray::Alloc(soa.Self(), 0)));
   EXPECT_EQ(class_linker_->FindSystemClass(soa.Self(), "[S"), short_array->GetClass());
   data_offset = reinterpret_cast<uintptr_t>(short_array->GetData());
   EXPECT_TRUE(IsAligned<2>(data_offset));  // Shorts require 2 byte alignment
@@ -848,7 +853,8 @@
   // Validate that the "value" field is always the 0th field in each of java.lang's box classes.
   // This lets UnboxPrimitive avoid searching for the field by name at runtime.
   ScopedObjectAccess soa(Thread::Current());
-  SirtRef<mirror::ClassLoader> class_loader(soa.Self(), nullptr);
+  StackHandleScope<1> hs(soa.Self());
+  auto class_loader(hs.NewHandle<mirror::ClassLoader>(nullptr));
   mirror::Class* c;
   c = class_linker_->FindClass(soa.Self(), "Ljava/lang/Boolean;", class_loader);
   FieldHelper fh(c->GetIFields()->Get(0));
@@ -878,21 +884,25 @@
 
 TEST_F(ClassLinkerTest, TwoClassLoadersOneClass) {
   ScopedObjectAccess soa(Thread::Current());
-  SirtRef<mirror::ClassLoader> class_loader_1(soa.Self(), soa.Decode<mirror::ClassLoader*>(LoadDex("MyClass")));
-  SirtRef<mirror::ClassLoader> class_loader_2(soa.Self(), soa.Decode<mirror::ClassLoader*>(LoadDex("MyClass")));
+  StackHandleScope<2> hs(soa.Self());
+  Handle<mirror::ClassLoader> class_loader_1(
+      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("MyClass"))));
+  Handle<mirror::ClassLoader> class_loader_2(
+      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 != NULL);
-  EXPECT_TRUE(MyClass_2 != NULL);
+  EXPECT_TRUE(MyClass_1 != nullptr);
+  EXPECT_TRUE(MyClass_2 != nullptr);
   EXPECT_NE(MyClass_1, MyClass_2);
 }
 
 TEST_F(ClassLinkerTest, StaticFields) {
   ScopedObjectAccess soa(Thread::Current());
-  SirtRef<mirror::ClassLoader> class_loader(soa.Self(),
-                                            soa.Decode<mirror::ClassLoader*>(LoadDex("Statics")));
-  SirtRef<mirror::Class> statics(soa.Self(), class_linker_->FindClass(soa.Self(), "LStatics;",
-                                                                      class_loader));
+  StackHandleScope<2> hs(soa.Self());
+  Handle<mirror::ClassLoader> class_loader(
+      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(statics, true, true);
 
   // Static final primitives that are initialized by a compile-time constant
@@ -907,74 +917,76 @@
   FieldHelper fh(s0);
   EXPECT_STREQ(ClassHelper(s0->GetClass()).GetDescriptor(), "Ljava/lang/reflect/ArtField;");
   EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimBoolean);
-  EXPECT_EQ(true, s0->GetBoolean(statics.get()));
-  s0->SetBoolean<false>(statics.get(), false);
+  EXPECT_EQ(true, s0->GetBoolean(statics.Get()));
+  s0->SetBoolean<false>(statics.Get(), false);
 
   mirror::ArtField* s1 = statics->FindStaticField("s1", "B");
   fh.ChangeField(s1);
   EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimByte);
-  EXPECT_EQ(5, s1->GetByte(statics.get()));
-  s1->SetByte<false>(statics.get(), 6);
+  EXPECT_EQ(5, s1->GetByte(statics.Get()));
+  s1->SetByte<false>(statics.Get(), 6);
 
   mirror::ArtField* s2 = statics->FindStaticField("s2", "C");
   fh.ChangeField(s2);
   EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimChar);
-  EXPECT_EQ('a', s2->GetChar(statics.get()));
-  s2->SetChar<false>(statics.get(), 'b');
+  EXPECT_EQ('a', s2->GetChar(statics.Get()));
+  s2->SetChar<false>(statics.Get(), 'b');
 
   mirror::ArtField* s3 = statics->FindStaticField("s3", "S");
   fh.ChangeField(s3);
   EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimShort);
-  EXPECT_EQ(-536, s3->GetShort(statics.get()));
-  s3->SetShort<false>(statics.get(), -535);
+  EXPECT_EQ(-536, s3->GetShort(statics.Get()));
+  s3->SetShort<false>(statics.Get(), -535);
 
   mirror::ArtField* s4 = statics->FindStaticField("s4", "I");
   fh.ChangeField(s4);
   EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimInt);
-  EXPECT_EQ(2000000000, s4->GetInt(statics.get()));
-  s4->SetInt<false>(statics.get(), 2000000001);
+  EXPECT_EQ(2000000000, s4->GetInt(statics.Get()));
+  s4->SetInt<false>(statics.Get(), 2000000001);
 
   mirror::ArtField* s5 = statics->FindStaticField("s5", "J");
   fh.ChangeField(s5);
   EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimLong);
-  EXPECT_EQ(0x1234567890abcdefLL, s5->GetLong(statics.get()));
-  s5->SetLong<false>(statics.get(), INT64_C(0x34567890abcdef12));
+  EXPECT_EQ(0x1234567890abcdefLL, s5->GetLong(statics.Get()));
+  s5->SetLong<false>(statics.Get(), INT64_C(0x34567890abcdef12));
 
   mirror::ArtField* s6 = statics->FindStaticField("s6", "F");
   fh.ChangeField(s6);
   EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimFloat);
-  EXPECT_EQ(0.5, s6->GetFloat(statics.get()));
-  s6->SetFloat<false>(statics.get(), 0.75);
+  EXPECT_EQ(0.5, s6->GetFloat(statics.Get()));
+  s6->SetFloat<false>(statics.Get(), 0.75);
 
   mirror::ArtField* s7 = statics->FindStaticField("s7", "D");
   fh.ChangeField(s7);
   EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimDouble);
-  EXPECT_EQ(16777217, s7->GetDouble(statics.get()));
-  s7->SetDouble<false>(statics.get(), 16777219);
+  EXPECT_EQ(16777217, s7->GetDouble(statics.Get()));
+  s7->SetDouble<false>(statics.Get(), 16777219);
 
   mirror::ArtField* s8 = statics->FindStaticField("s8", "Ljava/lang/String;");
   fh.ChangeField(s8);
   EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimNot);
-  EXPECT_TRUE(s8->GetObject(statics.get())->AsString()->Equals("android"));
+  EXPECT_TRUE(s8->GetObject(statics.Get())->AsString()->Equals("android"));
   s8->SetObject<false>(s8->GetDeclaringClass(),
                        mirror::String::AllocFromModifiedUtf8(soa.Self(), "robot"));
 
   // TODO: Remove EXPECT_FALSE when GCC can handle EXPECT_EQ
   // http://code.google.com/p/googletest/issues/detail?id=322
-  EXPECT_FALSE(s0->GetBoolean(statics.get()));
-  EXPECT_EQ(6, s1->GetByte(statics.get()));
-  EXPECT_EQ('b', s2->GetChar(statics.get()));
-  EXPECT_EQ(-535, s3->GetShort(statics.get()));
-  EXPECT_EQ(2000000001, s4->GetInt(statics.get()));
-  EXPECT_EQ(INT64_C(0x34567890abcdef12), s5->GetLong(statics.get()));
-  EXPECT_EQ(0.75, s6->GetFloat(statics.get()));
-  EXPECT_EQ(16777219, s7->GetDouble(statics.get()));
-  EXPECT_TRUE(s8->GetObject(statics.get())->AsString()->Equals("robot"));
+  EXPECT_FALSE(s0->GetBoolean(statics.Get()));
+  EXPECT_EQ(6, s1->GetByte(statics.Get()));
+  EXPECT_EQ('b', s2->GetChar(statics.Get()));
+  EXPECT_EQ(-535, s3->GetShort(statics.Get()));
+  EXPECT_EQ(2000000001, s4->GetInt(statics.Get()));
+  EXPECT_EQ(INT64_C(0x34567890abcdef12), s5->GetLong(statics.Get()));
+  EXPECT_EQ(0.75, s6->GetFloat(statics.Get()));
+  EXPECT_EQ(16777219, s7->GetDouble(statics.Get()));
+  EXPECT_TRUE(s8->GetObject(statics.Get())->AsString()->Equals("robot"));
 }
 
 TEST_F(ClassLinkerTest, Interfaces) {
   ScopedObjectAccess soa(Thread::Current());
-  SirtRef<mirror::ClassLoader> class_loader(soa.Self(), soa.Decode<mirror::ClassLoader*>(LoadDex("Interfaces")));
+  StackHandleScope<1> hs(soa.Self());
+  Handle<mirror::ClassLoader> class_loader(
+      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Interfaces"))));
   mirror::Class* I = class_linker_->FindClass(soa.Self(), "LInterfaces$I;", class_loader);
   mirror::Class* J = class_linker_->FindClass(soa.Self(), "LInterfaces$J;", class_loader);
   mirror::Class* K = class_linker_->FindClass(soa.Self(), "LInterfaces$K;", class_loader);
@@ -1035,7 +1047,9 @@
 
   ScopedObjectAccess soa(Thread::Current());
   jobject jclass_loader = LoadDex("StaticsFromCode");
-  SirtRef<mirror::ClassLoader> class_loader(soa.Self(), soa.Decode<mirror::ClassLoader*>(jclass_loader));
+  StackHandleScope<1> hs(soa.Self());
+  Handle<mirror::ClassLoader> class_loader(
+      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
   const DexFile* dex_file = Runtime::Current()->GetCompileTimeClassPath(jclass_loader)[0];
   CHECK(dex_file != NULL);
   mirror::Class* klass = class_linker_->FindClass(soa.Self(), "LStaticsFromCode;", class_loader);
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index b7564e1..be60ee2 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -28,6 +28,7 @@
 #include "gc/accounting/card_table-inl.h"
 #include "gc/space/large_object_space.h"
 #include "gc/space/space-inl.h"
+#include "handle_scope.h"
 #include "jdwp/object_registry.h"
 #include "mirror/art_field-inl.h"
 #include "mirror/art_method-inl.h"
@@ -45,8 +46,7 @@
 #include "scoped_thread_state_change.h"
 #include "ScopedLocalRef.h"
 #include "ScopedPrimitiveArray.h"
-#include "sirt_ref.h"
-#include "stack_indirect_reference_table.h"
+#include "handle_scope-inl.h"
 #include "thread_list.h"
 #include "throw_location.h"
 #include "utf.h"
@@ -2808,8 +2808,9 @@
     // should never be null. We could just check we never encounter this case.
     return false;
   }
-  SirtRef<mirror::DexCache> dex_cache(self, mh.GetDexCache());
-  SirtRef<mirror::ClassLoader> class_loader(self, mh.GetClassLoader());
+  StackHandleScope<2> hs(self);
+  Handle<mirror::DexCache> dex_cache(hs.NewHandle(mh.GetDexCache()));
+  Handle<mirror::ClassLoader> class_loader(hs.NewHandle(mh.GetClassLoader()));
   verifier::MethodVerifier verifier(&mh.GetDexFile(), &dex_cache, &class_loader,
                                     &mh.GetClassDef(), code_item, m->GetDexMethodIndex(), m,
                                     m->GetAccessFlags(), false, true);
@@ -3340,43 +3341,44 @@
 
   // We can be called while an exception is pending. We need
   // to preserve that across the method invocation.
-  SirtRef<mirror::Object> old_throw_this_object(soa.Self(), NULL);
-  SirtRef<mirror::ArtMethod> old_throw_method(soa.Self(), NULL);
-  SirtRef<mirror::Throwable> old_exception(soa.Self(), NULL);
+  StackHandleScope<4> hs(soa.Self());
+  auto old_throw_this_object = hs.NewHandle<mirror::Object>(nullptr);
+  auto old_throw_method = hs.NewHandle<mirror::ArtMethod>(nullptr);
+  auto old_exception = hs.NewHandle<mirror::Throwable>(nullptr);
   uint32_t old_throw_dex_pc;
   {
     ThrowLocation old_throw_location;
     mirror::Throwable* old_exception_obj = soa.Self()->GetException(&old_throw_location);
-    old_throw_this_object.reset(old_throw_location.GetThis());
-    old_throw_method.reset(old_throw_location.GetMethod());
-    old_exception.reset(old_exception_obj);
+    old_throw_this_object.Assign(old_throw_location.GetThis());
+    old_throw_method.Assign(old_throw_location.GetMethod());
+    old_exception.Assign(old_exception_obj);
     old_throw_dex_pc = old_throw_location.GetDexPc();
     soa.Self()->ClearException();
   }
 
   // Translate the method through the vtable, unless the debugger wants to suppress it.
-  SirtRef<mirror::ArtMethod> m(soa.Self(), pReq->method);
+  Handle<mirror::ArtMethod> m(hs.NewHandle(pReq->method));
   if ((pReq->options & JDWP::INVOKE_NONVIRTUAL) == 0 && pReq->receiver != NULL) {
-    mirror::ArtMethod* actual_method = pReq->klass->FindVirtualMethodForVirtualOrInterface(m.get());
-    if (actual_method != m.get()) {
-      VLOG(jdwp) << "ExecuteMethod translated " << PrettyMethod(m.get()) << " to " << PrettyMethod(actual_method);
-      m.reset(actual_method);
+    mirror::ArtMethod* actual_method = pReq->klass->FindVirtualMethodForVirtualOrInterface(m.Get());
+    if (actual_method != m.Get()) {
+      VLOG(jdwp) << "ExecuteMethod translated " << PrettyMethod(m.Get()) << " to " << PrettyMethod(actual_method);
+      m.Assign(actual_method);
     }
   }
-  VLOG(jdwp) << "ExecuteMethod " << PrettyMethod(m.get())
+  VLOG(jdwp) << "ExecuteMethod " << PrettyMethod(m.Get())
              << " receiver=" << pReq->receiver
              << " arg_count=" << pReq->arg_count;
-  CHECK(m.get() != nullptr);
+  CHECK(m.Get() != nullptr);
 
   CHECK_EQ(sizeof(jvalue), sizeof(uint64_t));
 
-  pReq->result_value = InvokeWithJValues(soa, pReq->receiver, soa.EncodeMethod(m.get()),
+  pReq->result_value = InvokeWithJValues(soa, pReq->receiver, soa.EncodeMethod(m.Get()),
                                          reinterpret_cast<jvalue*>(pReq->arg_values));
 
   mirror::Throwable* exception = soa.Self()->GetException(NULL);
   soa.Self()->ClearException();
   pReq->exception = gRegistry->Add(exception);
-  pReq->result_tag = BasicTagFromDescriptor(MethodHelper(m.get()).GetShorty());
+  pReq->result_tag = BasicTagFromDescriptor(MethodHelper(m.Get()).GetShorty());
   if (pReq->exception != 0) {
     VLOG(jdwp) << "  JDWP invocation returning with exception=" << exception
         << " " << exception->Dump();
@@ -3401,10 +3403,10 @@
     gRegistry->Add(pReq->result_value.GetL());
   }
 
-  if (old_exception.get() != NULL) {
-    ThrowLocation gc_safe_throw_location(old_throw_this_object.get(), old_throw_method.get(),
+  if (old_exception.Get() != NULL) {
+    ThrowLocation gc_safe_throw_location(old_throw_this_object.Get(), old_throw_method.Get(),
                                          old_throw_dex_pc);
-    soa.Self()->SetException(gc_safe_throw_location, old_exception.get());
+    soa.Self()->SetException(gc_safe_throw_location, old_exception.Get());
   }
 }
 
@@ -3546,9 +3548,10 @@
   } else {
     CHECK(type == CHUNK_TYPE("THCR") || type == CHUNK_TYPE("THNM")) << type;
     ScopedObjectAccessUnchecked soa(Thread::Current());
-    SirtRef<mirror::String> name(soa.Self(), t->GetThreadName(soa));
-    size_t char_count = (name.get() != NULL) ? name->GetLength() : 0;
-    const jchar* chars = (name.get() != NULL) ? name->GetCharArray()->GetData() : NULL;
+    StackHandleScope<1> hs(soa.Self());
+    Handle<mirror::String> name(hs.NewHandle(t->GetThreadName(soa)));
+    size_t char_count = (name.Get() != NULL) ? name->GetLength() : 0;
+    const jchar* chars = (name.Get() != NULL) ? name->GetCharArray()->GetData() : NULL;
 
     std::vector<uint8_t> bytes;
     JDWP::Append4BE(bytes, t->GetThreadId());
diff --git a/runtime/deoptimize_stack_visitor.cc b/runtime/deoptimize_stack_visitor.cc
index 3eb1792..c7fbc87 100644
--- a/runtime/deoptimize_stack_visitor.cc
+++ b/runtime/deoptimize_stack_visitor.cc
@@ -19,7 +19,7 @@
 #include "mirror/art_method-inl.h"
 #include "object_utils.h"
 #include "quick_exception_handler.h"
-#include "sirt_ref-inl.h"
+#include "handle_scope-inl.h"
 #include "verifier/method_verifier.h"
 
 namespace art {
@@ -50,8 +50,9 @@
   const Instruction* inst = Instruction::At(code_item->insns_ + dex_pc);
   uint32_t new_dex_pc = dex_pc + inst->SizeInCodeUnits();
   ShadowFrame* new_frame = ShadowFrame::Create(num_regs, nullptr, m, new_dex_pc);
-  SirtRef<mirror::DexCache> dex_cache(self_, mh.GetDexCache());
-  SirtRef<mirror::ClassLoader> class_loader(self_, mh.GetClassLoader());
+  StackHandleScope<2> hs(self_);
+  Handle<mirror::DexCache> dex_cache(hs.NewHandle(mh.GetDexCache()));
+  Handle<mirror::ClassLoader> class_loader(hs.NewHandle(mh.GetClassLoader()));
   verifier::MethodVerifier verifier(&mh.GetDexFile(), &dex_cache, &class_loader,
                                     &mh.GetClassDef(), code_item, m->GetDexMethodIndex(), m,
                                     m->GetAccessFlags(), false, true);
diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc
index 6adfc1f..f3d4621 100644
--- a/runtime/dex_file.cc
+++ b/runtime/dex_file.cc
@@ -37,7 +37,7 @@
 #include "os.h"
 #include "safe_map.h"
 #include "ScopedFd.h"
-#include "sirt_ref.h"
+#include "handle_scope-inl.h"
 #include "thread.h"
 #include "UniquePtr.h"
 #include "utf-inl.h"
@@ -1005,8 +1005,8 @@
 }
 
 EncodedStaticFieldValueIterator::EncodedStaticFieldValueIterator(const DexFile& dex_file,
-                                                                 SirtRef<mirror::DexCache>* dex_cache,
-                                                                 SirtRef<mirror::ClassLoader>* class_loader,
+                                                                 Handle<mirror::DexCache>* dex_cache,
+                                                                 Handle<mirror::ClassLoader>* class_loader,
                                                                  ClassLinker* linker,
                                                                  const DexFile::ClassDef& class_def)
     : dex_file_(dex_file), dex_cache_(dex_cache), class_loader_(class_loader), linker_(linker),
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index c782ab1..cfa2555 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -42,8 +42,7 @@
 }  // namespace mirror
 class ClassLinker;
 class Signature;
-template <typename T>
-class SirtRef;
+template<class T> class Handle;
 class StringPiece;
 class ZipArchive;
 
@@ -1127,8 +1126,8 @@
 
 class EncodedStaticFieldValueIterator {
  public:
-  EncodedStaticFieldValueIterator(const DexFile& dex_file, SirtRef<mirror::DexCache>* dex_cache,
-                                  SirtRef<mirror::ClassLoader>* class_loader,
+  EncodedStaticFieldValueIterator(const DexFile& dex_file, Handle<mirror::DexCache>* dex_cache,
+                                  Handle<mirror::ClassLoader>* class_loader,
                                   ClassLinker* linker, const DexFile::ClassDef& class_def)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -1163,8 +1162,8 @@
   static const byte kEncodedValueArgShift = 5;
 
   const DexFile& dex_file_;
-  SirtRef<mirror::DexCache>* const dex_cache_;  // Dex cache to resolve literal objects.
-  SirtRef<mirror::ClassLoader>* const class_loader_;  // ClassLoader to resolve types.
+  Handle<mirror::DexCache>* const dex_cache_;  // Dex cache to resolve literal objects.
+  Handle<mirror::ClassLoader>* const class_loader_;  // ClassLoader to resolve types.
   ClassLinker* linker_;  // Linker to resolve literal objects.
   size_t array_size_;  // Size of array.
   size_t pos_;  // Current position.
diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h
index e52a8fb..6998e21 100644
--- a/runtime/entrypoints/entrypoint_utils.h
+++ b/runtime/entrypoints/entrypoint_utils.h
@@ -30,7 +30,7 @@
 #include "mirror/object-inl.h"
 #include "mirror/throwable.h"
 #include "object_utils.h"
-#include "sirt_ref-inl.h"
+#include "handle_scope-inl.h"
 #include "thread.h"
 
 namespace art {
@@ -72,7 +72,8 @@
     }
   }
   if (UNLIKELY(!klass->IsInitialized())) {
-    SirtRef<mirror::Class> sirt_klass(self, klass);
+    StackHandleScope<1> hs(self);
+    Handle<mirror::Class> h_klass(hs.NewHandle(klass));
     // EnsureInitialized (the class initializer) might cause a GC.
     // may cause us to suspend meaning that another thread may try to
     // change the allocator while we are stuck in the entrypoints of
@@ -82,11 +83,11 @@
     // has changed and to null-check the return value in case the
     // initialization fails.
     *slow_path = true;
-    if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(sirt_klass, true, true)) {
+    if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(h_klass, true, true)) {
       DCHECK(self->IsExceptionPending());
       return nullptr;  // Failure
     }
-    return sirt_klass.get();
+    return h_klass.Get();
   }
   return klass;
 }
@@ -96,7 +97,8 @@
                                                                                Thread* self, bool* slow_path)
     NO_THREAD_SAFETY_ANALYSIS {
   if (UNLIKELY(!klass->IsInitialized())) {
-    SirtRef<mirror::Class> sirt_class(self, klass);
+    StackHandleScope<1> hs(self);
+    Handle<mirror::Class> h_class(hs.NewHandle(klass));
     // EnsureInitialized (the class initializer) might cause a GC.
     // may cause us to suspend meaning that another thread may try to
     // change the allocator while we are stuck in the entrypoints of
@@ -106,11 +108,11 @@
     // has changed and to null-check the return value in case the
     // initialization fails.
     *slow_path = true;
-    if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(sirt_class, true, true)) {
+    if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(h_class, true, true)) {
       DCHECK(self->IsExceptionPending());
       return nullptr;  // Failure
     }
-    return sirt_class.get();
+    return h_class.Get();
   }
   return klass;
 }
@@ -346,14 +348,14 @@
     if (LIKELY(fields_class->IsInitialized())) {
       return resolved_field;
     } else {
-      SirtRef<mirror::Class> sirt_class(self, fields_class);
-      if (LIKELY(class_linker->EnsureInitialized(sirt_class, true, true))) {
+      StackHandleScope<1> hs(self);
+      Handle<mirror::Class> h_class(hs.NewHandle(fields_class));
+      if (LIKELY(class_linker->EnsureInitialized(h_class, true, true))) {
         // Otherwise let's ensure the class is initialized before resolving the field.
         return resolved_field;
-      } else {
-        DCHECK(self->IsExceptionPending());  // Throw exception and unwind
-        return nullptr;  // Failure.
       }
+      DCHECK(self->IsExceptionPending());  // Throw exception and unwind
+      return nullptr;  // Failure.
     }
   }
 }
@@ -386,12 +388,13 @@
                                                     mirror::Object* this_object,
                                                     mirror::ArtMethod* referrer, Thread* self) {
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  SirtRef<mirror::Object> sirt_this(self, type == kStatic ? nullptr : this_object);
+  StackHandleScope<1> hs(self);
+  Handle<mirror::Object> handle_scope_this(hs.NewHandle(type == kStatic ? nullptr : this_object));
   mirror::ArtMethod* resolved_method = class_linker->ResolveMethod(method_idx, referrer, type);
   if (UNLIKELY(resolved_method == nullptr)) {
     DCHECK(self->IsExceptionPending());  // Throw exception and unwind.
     return nullptr;  // Failure.
-  } else if (UNLIKELY(sirt_this.get() == nullptr && type != kStatic)) {
+  } else if (UNLIKELY(handle_scope_this.Get() == nullptr && type != kStatic)) {
     // Maintain interpreter-like semantics where NullPointerException is thrown
     // after potential NoSuchMethodError from class linker.
     ThrowLocation throw_location = self->GetCurrentLocationForThrow();
@@ -420,7 +423,7 @@
     case kDirect:
       return resolved_method;
     case kVirtual: {
-      mirror::ObjectArray<mirror::ArtMethod>* vtable = sirt_this->GetClass()->GetVTable();
+      mirror::ObjectArray<mirror::ArtMethod>* vtable = handle_scope_this->GetClass()->GetVTable();
       uint16_t vtable_index = resolved_method->GetMethodIndex();
       if (access_check &&
           (vtable == nullptr || vtable_index >= static_cast<uint32_t>(vtable->GetLength()))) {
@@ -457,16 +460,16 @@
     }
     case kInterface: {
       uint32_t imt_index = resolved_method->GetDexMethodIndex() % ClassLinker::kImtSize;
-      mirror::ObjectArray<mirror::ArtMethod>* imt_table = sirt_this->GetClass()->GetImTable();
+      mirror::ObjectArray<mirror::ArtMethod>* imt_table = handle_scope_this->GetClass()->GetImTable();
       mirror::ArtMethod* imt_method = imt_table->Get(imt_index);
       if (!imt_method->IsImtConflictMethod()) {
         return imt_method;
       } else {
         mirror::ArtMethod* interface_method =
-            sirt_this->GetClass()->FindVirtualMethodForInterface(resolved_method);
+            handle_scope_this->GetClass()->FindVirtualMethodForInterface(resolved_method);
         if (UNLIKELY(interface_method == nullptr)) {
           ThrowIncompatibleClassChangeErrorClassForInterfaceDispatch(resolved_method,
-                                                                     sirt_this.get(), referrer);
+                                                                     handle_scope_this.Get(), referrer);
           return nullptr;  // Failure.
         } else {
           return interface_method;
@@ -625,12 +628,13 @@
   if (klass == referring_class && referrer->IsConstructor() && referrer->IsStatic()) {
     return klass;
   }
-  SirtRef<mirror::Class> sirt_class(self, klass);
-  if (!class_linker->EnsureInitialized(sirt_class, true, true)) {
+  StackHandleScope<1> hs(self);
+  Handle<mirror::Class> h_class(hs.NewHandle(klass));
+  if (!class_linker->EnsureInitialized(h_class, true, true)) {
     CHECK(self->IsExceptionPending());
     return nullptr;  // Failure - Indicate to caller to deliver exception
   }
-  return sirt_class.get();
+  return h_class.Get();
 }
 
 extern void ThrowStackOverflowError(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/entrypoints/interpreter/interpreter_entrypoints.cc b/runtime/entrypoints/interpreter/interpreter_entrypoints.cc
index a0ba6b9..3f02ec7 100644
--- a/runtime/entrypoints/interpreter/interpreter_entrypoints.cc
+++ b/runtime/entrypoints/interpreter/interpreter_entrypoints.cc
@@ -34,14 +34,15 @@
     mirror::Class* declaringClass = method->GetDeclaringClass();
     if (UNLIKELY(!declaringClass->IsInitializing())) {
       self->PushShadowFrame(shadow_frame);
-      SirtRef<mirror::Class> sirt_c(self, declaringClass);
-      if (UNLIKELY(!Runtime::Current()->GetClassLinker()->EnsureInitialized(sirt_c, true, true))) {
+      StackHandleScope<1> hs(self);
+      Handle<mirror::Class> h_class(hs.NewHandle(declaringClass));
+      if (UNLIKELY(!Runtime::Current()->GetClassLinker()->EnsureInitialized(h_class, true, true))) {
         self->PopShadowFrame();
         DCHECK(self->IsExceptionPending());
         return;
       }
       self->PopShadowFrame();
-      CHECK(sirt_c->IsInitializing());
+      CHECK(h_class->IsInitializing());
     }
   }
   uint16_t arg_offset = (code_item == NULL) ? 0 : code_item->registers_size_ - code_item->ins_size_;
diff --git a/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc b/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc
index f1b15b5..17c3222 100644
--- a/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc
@@ -214,8 +214,9 @@
 
     if (method->IsStatic() && !method->GetDeclaringClass()->IsInitializing()) {
       // Ensure static method's class is initialized.
-      SirtRef<mirror::Class> sirt_c(self, method->GetDeclaringClass());
-      if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(sirt_c, true, true)) {
+      StackHandleScope<1> hs(self);
+      Handle<mirror::Class> h_class(hs.NewHandle(method->GetDeclaringClass()));
+      if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(h_class, true, true)) {
         DCHECK(Thread::Current()->IsExceptionPending());
         self->PopManagedStackFragment(fragment);
         return 0;
@@ -396,7 +397,8 @@
   const void* code = nullptr;
   if (LIKELY(!thread->IsExceptionPending())) {
     // Ensure that the called method's class is initialized.
-    SirtRef<mirror::Class> called_class(thread, called->GetDeclaringClass());
+    StackHandleScope<1> hs(Thread::Current());
+    Handle<mirror::Class> called_class(hs.NewHandle(called->GetDeclaringClass()));
     linker->EnsureInitialized(called_class, true, true);
     if (LIKELY(called_class->IsInitialized())) {
       code = called->GetEntryPointFromPortableCompiledCode();
diff --git a/runtime/entrypoints/quick/quick_jni_entrypoints.cc b/runtime/entrypoints/quick/quick_jni_entrypoints.cc
index 116957d..9c9cca8 100644
--- a/runtime/entrypoints/quick/quick_jni_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_jni_entrypoints.cc
@@ -65,7 +65,7 @@
   JNIEnvExt* env = self->GetJniEnv();
   env->locals.SetSegmentState(env->local_ref_cookie);
   env->local_ref_cookie = saved_local_ref_cookie;
-  self->PopSirt();
+  self->PopHandleScope();
 }
 
 extern void JniMethodEnd(uint32_t saved_local_ref_cookie, Thread* self) {
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 5d2603f..887bd6f 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -489,8 +489,9 @@
 
     if (method->IsStatic() && !method->GetDeclaringClass()->IsInitializing()) {
       // Ensure static method's class is initialized.
-      SirtRef<mirror::Class> sirt_c(self, method->GetDeclaringClass());
-      if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(sirt_c, true, true)) {
+      StackHandleScope<1> hs(self);
+      Handle<mirror::Class> h_class(hs.NewHandle(method->GetDeclaringClass()));
+      if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(h_class, true, true)) {
         DCHECK(Thread::Current()->IsExceptionPending()) << PrettyMethod(method);
         self->PopManagedStackFragment(fragment);
         return 0;
@@ -755,9 +756,10 @@
   bool virtual_or_interface = invoke_type == kVirtual || invoke_type == kInterface;
   // Resolve method filling in dex cache.
   if (called->IsRuntimeMethod()) {
-    SirtRef<mirror::Object> sirt_receiver(soa.Self(), virtual_or_interface ? receiver : nullptr);
+    StackHandleScope<1> hs(self);
+    Handle<mirror::Object> handle_scope_receiver(hs.NewHandle(virtual_or_interface ? receiver : nullptr));
     called = linker->ResolveMethod(dex_method_idx, caller, invoke_type);
-    receiver = sirt_receiver.get();
+    receiver = handle_scope_receiver.Get();
   }
   const void* code = NULL;
   if (LIKELY(!self->IsExceptionPending())) {
@@ -796,7 +798,8 @@
       }
     }
     // Ensure that the called method's class is initialized.
-    SirtRef<mirror::Class> called_class(soa.Self(), called->GetDeclaringClass());
+    StackHandleScope<1> hs(soa.Self());
+    Handle<mirror::Class> called_class(hs.NewHandle(called->GetDeclaringClass()));
     linker->EnsureInitialized(called_class, true, true);
     if (LIKELY(called_class->IsInitialized())) {
       code = called->GetEntryPointFromQuickCompiledCode();
@@ -857,10 +860,10 @@
  *
  * void PushStack(uintptr_t): Push a value to the stack.
  *
- * uintptr_t PushSirt(mirror::Object* ref): Add a reference to the Sirt. This _will_ have nullptr,
+ * uintptr_t PushHandleScope(mirror::Object* ref): Add a reference to the HandleScope. This _will_ have nullptr,
  *                                          as this might be important for null initialization.
  *                                          Must return the jobject, that is, the reference to the
- *                                          entry in the Sirt (nullptr if necessary).
+ *                                          entry in the HandleScope (nullptr if necessary).
  *
  */
 template <class T> class BuildGenericJniFrameStateMachine {
@@ -956,18 +959,18 @@
   }
 
 
-  bool HaveSirtGpr() {
+  bool HaveHandleScopeGpr() {
     return gpr_index_ > 0;
   }
 
-  void AdvanceSirt(mirror::Object* ptr) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    uintptr_t sirtRef = PushSirt(ptr);
-    if (HaveSirtGpr()) {
+  void AdvanceHandleScope(mirror::Object* ptr) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    uintptr_t handle = PushHandle(ptr);
+    if (HaveHandleScopeGpr()) {
       gpr_index_--;
-      PushGpr(sirtRef);
+      PushGpr(handle);
     } else {
       stack_entries_++;
-      PushStack(sirtRef);
+      PushStack(handle);
       gpr_index_ = 0;
     }
   }
@@ -1147,8 +1150,8 @@
   void PushStack(uintptr_t val) {
     delegate_->PushStack(val);
   }
-  uintptr_t PushSirt(mirror::Object* ref) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return delegate_->PushSirt(ref);
+  uintptr_t PushHandle(mirror::Object* ref) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    return delegate_->PushHandle(ref);
   }
 
   uint32_t gpr_index_;      // Number of free GPRs
@@ -1160,7 +1163,7 @@
 
 class ComputeGenericJniFrameSize FINAL {
  public:
-  ComputeGenericJniFrameSize() : num_sirt_references_(0), num_stack_entries_(0) {}
+  ComputeGenericJniFrameSize() : num_handle_scope_references_(0), num_stack_entries_(0) {}
 
   uint32_t GetStackSize() {
     return num_stack_entries_ * sizeof(uintptr_t);
@@ -1168,7 +1171,7 @@
 
   // WARNING: After this, *sp won't be pointing to the method anymore!
   void ComputeLayout(mirror::ArtMethod*** m, bool is_static, const char* shorty, uint32_t shorty_len,
-                     void* sp, StackIndirectReferenceTable** table, uint32_t* sirt_entries,
+                     void* sp, HandleScope** table, uint32_t* handle_scope_entries,
                      uintptr_t** start_stack, uintptr_t** start_gpr, uint32_t** start_fpr,
                      void** code_return, size_t* overall_size)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -1179,17 +1182,17 @@
     uint8_t* sp8 = reinterpret_cast<uint8_t*>(sp);
 
     // First, fix up the layout of the callee-save frame.
-    // We have to squeeze in the Sirt, and relocate the method pointer.
+    // We have to squeeze in the HandleScope, and relocate the method pointer.
 
     // "Free" the slot for the method.
     sp8 += kPointerSize;
 
-    // Add the Sirt.
-    *sirt_entries = num_sirt_references_;
-    size_t sirt_size = StackIndirectReferenceTable::GetAlignedSirtSize(num_sirt_references_);
-    sp8 -= sirt_size;
-    *table = reinterpret_cast<StackIndirectReferenceTable*>(sp8);
-    (*table)->SetNumberOfReferences(num_sirt_references_);
+    // Add the HandleScope.
+    *handle_scope_entries = num_handle_scope_references_;
+    size_t handle_scope_size = HandleScope::GetAlignedHandleScopeSize(num_handle_scope_references_);
+    sp8 -= handle_scope_size;
+    *table = reinterpret_cast<HandleScope*>(sp8);
+    (*table)->SetNumberOfReferences(num_handle_scope_references_);
 
     // Add a slot for the method pointer, and fill it. Fix the pointer-pointer given to us.
     sp8 -= kPointerSize;
@@ -1199,8 +1202,8 @@
 
     // Reference cookie and padding
     sp8 -= 8;
-    // Store Sirt size
-    *reinterpret_cast<uint32_t*>(sp8) = static_cast<uint32_t>(sirt_size & 0xFFFFFFFF);
+    // Store HandleScope size
+    *reinterpret_cast<uint32_t*>(sp8) = static_cast<uint32_t>(handle_scope_size & 0xFFFFFFFF);
 
     // Next comes the native call stack.
     sp8 -= GetStackSize();
@@ -1229,7 +1232,7 @@
     *(reinterpret_cast<uint8_t**>(sp8)) = method_pointer;
   }
 
-  void ComputeSirtOffset() { }  // nothing to do, static right now
+  void ComputeHandleScopeOffset() { }  // nothing to do, static right now
 
   void ComputeAll(bool is_static, const char* shorty, uint32_t shorty_len)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -1239,13 +1242,13 @@
     sm.AdvancePointer(nullptr);
 
     // Class object or this as first argument
-    sm.AdvanceSirt(reinterpret_cast<mirror::Object*>(0x12345678));
+    sm.AdvanceHandleScope(reinterpret_cast<mirror::Object*>(0x12345678));
 
     for (uint32_t i = 1; i < shorty_len; ++i) {
       Primitive::Type cur_type_ = Primitive::GetType(shorty[i]);
       switch (cur_type_) {
         case Primitive::kPrimNot:
-          sm.AdvanceSirt(reinterpret_cast<mirror::Object*>(0x12345678));
+          sm.AdvanceHandleScope(reinterpret_cast<mirror::Object*>(0x12345678));
           break;
 
         case Primitive::kPrimBoolean:
@@ -1288,13 +1291,13 @@
     // counting is already done in the superclass
   }
 
-  uintptr_t PushSirt(mirror::Object* /* ptr */) {
-    num_sirt_references_++;
+  uintptr_t PushHandle(mirror::Object* /* ptr */) {
+    num_handle_scope_references_++;
     return reinterpret_cast<uintptr_t>(nullptr);
   }
 
  private:
-  uint32_t num_sirt_references_;
+  uint32_t num_handle_scope_references_;
   uint32_t num_stack_entries_;
 };
 
@@ -1306,26 +1309,26 @@
                               uint32_t shorty_len, Thread* self) :
       QuickArgumentVisitor(*sp, is_static, shorty, shorty_len), sm_(this) {
     ComputeGenericJniFrameSize fsc;
-    fsc.ComputeLayout(sp, is_static, shorty, shorty_len, *sp, &sirt_, &sirt_expected_refs_,
+    fsc.ComputeLayout(sp, is_static, shorty, shorty_len, *sp, &handle_scope_, &handle_scope_expected_refs_,
                       &cur_stack_arg_, &cur_gpr_reg_, &cur_fpr_reg_, &code_return_,
                       &alloca_used_size_);
-    sirt_number_of_references_ = 0;
-    cur_sirt_entry_ = reinterpret_cast<StackReference<mirror::Object>*>(GetFirstSirtEntry());
+    handle_scope_number_of_references_ = 0;
+    cur_hs_entry_ = reinterpret_cast<StackReference<mirror::Object>*>(GetFirstHandleScopeEntry());
 
     // jni environment is always first argument
     sm_.AdvancePointer(self->GetJniEnv());
 
     if (is_static) {
-      sm_.AdvanceSirt((**sp)->GetDeclaringClass());
+      sm_.AdvanceHandleScope((**sp)->GetDeclaringClass());
     }
   }
 
   void Visit() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) OVERRIDE;
 
-  void FinalizeSirt(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void FinalizeHandleScope(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  jobject GetFirstSirtEntry() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return reinterpret_cast<jobject>(sirt_->GetStackReference(0));
+  jobject GetFirstHandleScopeEntry() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    return handle_scope_->GetHandle(0).ToJObject();
   }
 
   void PushGpr(uintptr_t val) {
@@ -1349,17 +1352,17 @@
     cur_stack_arg_++;
   }
 
-  uintptr_t PushSirt(mirror::Object* ref) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  uintptr_t PushHandle(mirror::Object* ref) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     uintptr_t tmp;
     if (ref == nullptr) {
-      *cur_sirt_entry_ = StackReference<mirror::Object>();
+      *cur_hs_entry_ = StackReference<mirror::Object>();
       tmp = reinterpret_cast<uintptr_t>(nullptr);
     } else {
-      *cur_sirt_entry_ = StackReference<mirror::Object>::FromMirrorPtr(ref);
-      tmp = reinterpret_cast<uintptr_t>(cur_sirt_entry_);
+      *cur_hs_entry_ = StackReference<mirror::Object>::FromMirrorPtr(ref);
+      tmp = reinterpret_cast<uintptr_t>(cur_hs_entry_);
     }
-    cur_sirt_entry_++;
-    sirt_number_of_references_++;
+    cur_hs_entry_++;
+    handle_scope_number_of_references_++;
     return tmp;
   }
 
@@ -1373,14 +1376,14 @@
   }
 
  private:
-  uint32_t sirt_number_of_references_;
-  StackReference<mirror::Object>* cur_sirt_entry_;
-  StackIndirectReferenceTable* sirt_;
-  uint32_t sirt_expected_refs_;
+  uint32_t handle_scope_number_of_references_;
+  StackReference<mirror::Object>* cur_hs_entry_;
+  HandleScope* handle_scope_;
+  uint32_t handle_scope_expected_refs_;
   uintptr_t* cur_gpr_reg_;
   uint32_t* cur_fpr_reg_;
   uintptr_t* cur_stack_arg_;
-  // StackReference<mirror::Object>* top_of_sirt_;
+  // StackReference<mirror::Object>* top_of_handle_scope_;
   void* code_return_;
   size_t alloca_used_size_;
 
@@ -1416,7 +1419,7 @@
     case Primitive::kPrimNot: {
       StackReference<mirror::Object>* stack_ref =
           reinterpret_cast<StackReference<mirror::Object>*>(GetParamAddress());
-      sm_.AdvanceSirt(stack_ref->AsMirrorPtr());
+      sm_.AdvanceHandleScope(stack_ref->AsMirrorPtr());
       break;
     }
     case Primitive::kPrimFloat:
@@ -1435,17 +1438,17 @@
   }
 }
 
-void BuildGenericJniFrameVisitor::FinalizeSirt(Thread* self) {
+void BuildGenericJniFrameVisitor::FinalizeHandleScope(Thread* self) {
   // Initialize padding entries.
-  while (sirt_number_of_references_ < sirt_expected_refs_) {
-    *cur_sirt_entry_ = StackReference<mirror::Object>();
-    cur_sirt_entry_++;
-    sirt_number_of_references_++;
+  while (handle_scope_number_of_references_ < handle_scope_expected_refs_) {
+    *cur_hs_entry_ = StackReference<mirror::Object>();
+    cur_hs_entry_++;
+    handle_scope_number_of_references_++;
   }
-  sirt_->SetNumberOfReferences(sirt_expected_refs_);
-  DCHECK_NE(sirt_expected_refs_, 0U);
-  // Install Sirt.
-  self->PushSirt(sirt_);
+  handle_scope_->SetNumberOfReferences(handle_scope_expected_refs_);
+  DCHECK_NE(handle_scope_expected_refs_, 0U);
+  // Install HandleScope.
+  self->PushHandleScope(handle_scope_);
 }
 
 extern "C" void* artFindNativeMethod();
@@ -1468,11 +1471,11 @@
 
 /*
  * Initializes an alloca region assumed to be directly below sp for a native call:
- * Create a Sirt and call stack and fill a mini stack with values to be pushed to registers.
+ * Create a HandleScope and call stack and fill a mini stack with values to be pushed to registers.
  * The final element on the stack is a pointer to the native code.
  *
  * On entry, the stack has a standard callee-save frame above sp, and an alloca below it.
- * We need to fix this, as the Sirt needs to go into the callee-save frame.
+ * We need to fix this, as the handle scope needs to go into the callee-save frame.
  *
  * The return of this function denotes:
  * 1) How many bytes of the alloca can be released, if the value is non-negative.
@@ -1489,7 +1492,7 @@
   BuildGenericJniFrameVisitor visitor(&sp, called->IsStatic(), mh.GetShorty(), mh.GetShortyLength(),
                                       self);
   visitor.VisitArguments();
-  visitor.FinalizeSirt(self);
+  visitor.FinalizeHandleScope(self);
 
   // fix up managed-stack things in Thread
   self->SetTopOfStack(sp, 0);
@@ -1499,9 +1502,9 @@
   // Start JNI, save the cookie.
   uint32_t cookie;
   if (called->IsSynchronized()) {
-    cookie = JniMethodStartSynchronized(visitor.GetFirstSirtEntry(), self);
+    cookie = JniMethodStartSynchronized(visitor.GetFirstHandleScopeEntry(), self);
     if (self->IsExceptionPending()) {
-      self->PopSirt();
+      self->PopHandleScope();
       // A negative value denotes an error.
       return -1;
     }
@@ -1527,7 +1530,7 @@
       DCHECK(self->IsExceptionPending());    // There should be an exception pending now.
 
       // End JNI, as the assembly will move to deliver the exception.
-      jobject lock = called->IsSynchronized() ? visitor.GetFirstSirtEntry() : nullptr;
+      jobject lock = called->IsSynchronized() ? visitor.GetFirstHandleScopeEntry() : nullptr;
       if (mh.GetShorty()[0] == 'L') {
         artQuickGenericJniEndJNIRef(self, cookie, nullptr, lock);
       } else {
@@ -1549,7 +1552,7 @@
 }
 
 /*
- * Is called after the native JNI code. Responsible for cleanup (SIRT, saved state) and
+ * Is called after the native JNI code. Responsible for cleanup (handle scope, saved state) and
  * unlocking.
  */
 extern "C" uint64_t artQuickGenericJniEndTrampoline(Thread* self, mirror::ArtMethod** sp,
@@ -1561,10 +1564,9 @@
 
   jobject lock = nullptr;
   if (called->IsSynchronized()) {
-    StackIndirectReferenceTable* table =
-        reinterpret_cast<StackIndirectReferenceTable*>(
-            reinterpret_cast<uint8_t*>(sp) + kPointerSize);
-    lock = reinterpret_cast<jobject>(table->GetStackReference(0));
+    HandleScope* table = reinterpret_cast<HandleScope*>(
+        reinterpret_cast<uint8_t*>(sp) + kPointerSize);
+    lock = table->GetHandle(0).ToJObject();
   }
 
   MethodHelper mh(called);
diff --git a/runtime/exception_test.cc b/runtime/exception_test.cc
index 97a8367..91a0176 100644
--- a/runtime/exception_test.cc
+++ b/runtime/exception_test.cc
@@ -25,7 +25,7 @@
 #include "mirror/stack_trace_element.h"
 #include "runtime.h"
 #include "scoped_thread_state_change.h"
-#include "sirt_ref.h"
+#include "handle_scope-inl.h"
 #include "thread.h"
 #include "UniquePtr.h"
 #include "vmap_table.h"
@@ -38,13 +38,14 @@
     CommonRuntimeTest::SetUp();
 
     ScopedObjectAccess soa(Thread::Current());
-    SirtRef<mirror::ClassLoader> class_loader(
-        soa.Self(), soa.Decode<mirror::ClassLoader*>(LoadDex("ExceptionHandle")));
+    StackHandleScope<2> hs(soa.Self());
+    Handle<mirror::ClassLoader> class_loader(
+        hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("ExceptionHandle"))));
     my_klass_ = class_linker_->FindClass(soa.Self(), "LExceptionHandle;", class_loader);
     ASSERT_TRUE(my_klass_ != NULL);
-    SirtRef<mirror::Class> sirt_klass(soa.Self(), my_klass_);
-    class_linker_->EnsureInitialized(sirt_klass, true, true);
-    my_klass_ = sirt_klass.get();
+    Handle<mirror::Class> klass(hs.NewHandle(my_klass_));
+    class_linker_->EnsureInitialized(klass, true, true);
+    my_klass_ = klass.Get();
 
     dex_ = my_klass_->GetDexCache()->GetDexFile();
 
@@ -72,9 +73,10 @@
 
     const std::vector<uint8_t>& fake_vmap_table_data = fake_vmap_table_data_.GetData();
     const std::vector<uint8_t>& fake_mapping_data = fake_mapping_data_.GetData();
-    uint32_t vmap_table_offset = sizeof(OatMethodHeader) + fake_vmap_table_data.size();
+    uint32_t vmap_table_offset = sizeof(OatQuickMethodHeader) + fake_vmap_table_data.size();
     uint32_t mapping_table_offset = vmap_table_offset + fake_mapping_data.size();
-    OatMethodHeader method_header(vmap_table_offset, mapping_table_offset, code_size);
+    OatQuickMethodHeader method_header(mapping_table_offset, vmap_table_offset,
+                                       4 * kPointerSize, 0u, 0u, code_size);
     fake_header_code_and_maps_.resize(sizeof(method_header));
     memcpy(&fake_header_code_and_maps_[0], &method_header, sizeof(method_header));
     fake_header_code_and_maps_.insert(fake_header_code_and_maps_.begin(),
@@ -91,13 +93,11 @@
 
     method_f_ = my_klass_->FindVirtualMethod("f", "()I");
     ASSERT_TRUE(method_f_ != NULL);
-    method_f_->SetFrameSizeInBytes(4 * kPointerSize);
     method_f_->SetEntryPointFromQuickCompiledCode(code_ptr);
     method_f_->SetNativeGcMap(&fake_gc_map_[0]);
 
     method_g_ = my_klass_->FindVirtualMethod("g", "(I)V");
     ASSERT_TRUE(method_g_ != NULL);
-    method_g_->SetFrameSizeInBytes(4 * kPointerSize);
     method_g_->SetEntryPointFromQuickCompiledCode(code_ptr);
     method_g_->SetNativeGcMap(&fake_gc_map_[0]);
   }
diff --git a/runtime/fault_handler.h b/runtime/fault_handler.h
index ea2f7c8..97d3c2f 100644
--- a/runtime/fault_handler.h
+++ b/runtime/fault_handler.h
@@ -112,7 +112,7 @@
 };
 
 
-// Statically allocated so the the signal handler can get access to it.
+// Statically allocated so the the signal handler can Get access to it.
 extern FaultManager fault_manager;
 
 }       // namespace art
diff --git a/runtime/gc/collector/garbage_collector.h b/runtime/gc/collector/garbage_collector.h
index d05f45b..02dd4d9 100644
--- a/runtime/gc/collector/garbage_collector.h
+++ b/runtime/gc/collector/garbage_collector.h
@@ -142,7 +142,7 @@
   virtual void RevokeAllThreadLocalBuffers() = 0;
 
   // Record that you have freed some objects or large objects, calls Heap::RecordFree.
-  // TODO: These are not thread safe, add a lock if we get have parallel sweeping.
+  // TODO: These are not thread safe, add a lock if we get parallel sweeping.
   void RecordFree(uint64_t freed_objects, int64_t freed_bytes);
   void RecordFreeLargeObjects(uint64_t freed_objects, int64_t freed_bytes);
 
diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc
index 5de7026..cc258f5 100644
--- a/runtime/gc/collector/mark_sweep.cc
+++ b/runtime/gc/collector/mark_sweep.cc
@@ -106,7 +106,7 @@
 
 void MarkSweep::InitializePhase() {
   TimingLogger::ScopedSplit split("InitializePhase", &timings_);
-  mark_stack_ = heap_->mark_stack_.get();
+  mark_stack_ = heap_->GetMarkStack();
   DCHECK(mark_stack_ != nullptr);
   immune_region_.Reset();
   class_count_ = 0;
@@ -123,7 +123,7 @@
   mark_fastpath_count_ = 0;
   mark_slowpath_count_ = 0;
   {
-    // TODO: I don't think we should need heap bitmap lock to get the mark bitmap.
+    // TODO: I don't think we should need heap bitmap lock to Get the mark bitmap.
     ReaderMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
     mark_bitmap_ = heap_->GetMarkBitmap();
   }
diff --git a/runtime/gc/collector/mark_sweep.h b/runtime/gc/collector/mark_sweep.h
index 3ebc0af..cfb0b5e 100644
--- a/runtime/gc/collector/mark_sweep.h
+++ b/runtime/gc/collector/mark_sweep.h
@@ -264,7 +264,7 @@
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  // Used to get around thread safety annotations. The call is from MarkingPhase and is guarded by
+  // Used to Get around thread safety annotations. The call is from MarkingPhase and is guarded by
   // IsExclusiveHeld.
   void RevokeAllThreadLocalAllocationStacks(Thread* self) NO_THREAD_SAFETY_ANALYSIS;
 
diff --git a/runtime/gc/collector/semi_space-inl.h b/runtime/gc/collector/semi_space-inl.h
index 55140f6..47682cc 100644
--- a/runtime/gc/collector/semi_space-inl.h
+++ b/runtime/gc/collector/semi_space-inl.h
@@ -50,7 +50,7 @@
   return reinterpret_cast<mirror::Object*>(lock_word.ForwardingAddress());
 }
 
-// Used to mark and copy objects. Any newly-marked objects who are in the from space get moved to
+// Used to mark and copy objects. Any newly-marked objects who are in the from space Get moved to
 // the to-space and have their forward address updated. Objects which have been newly marked are
 // pushed on the mark stack.
 template<bool kPoisonReferences>
@@ -72,7 +72,7 @@
         forward_address = MarkNonForwardedObject(obj);
         DCHECK(forward_address != nullptr);
         // Make sure to only update the forwarding address AFTER you copy the object so that the
-        // monitor word doesn't get stomped over.
+        // monitor word doesn't Get stomped over.
         obj->SetLockWord(
             LockWord::FromForwardingAddress(reinterpret_cast<size_t>(forward_address)), false);
         // Push the object onto the mark stack for later processing.
diff --git a/runtime/gc/collector/semi_space.cc b/runtime/gc/collector/semi_space.cc
index a406f6d..95a2c96 100644
--- a/runtime/gc/collector/semi_space.cc
+++ b/runtime/gc/collector/semi_space.cc
@@ -142,7 +142,7 @@
 
 void SemiSpace::InitializePhase() {
   TimingLogger::ScopedSplit split("InitializePhase", &timings_);
-  mark_stack_ = heap_->mark_stack_.get();
+  mark_stack_ = heap_->GetMarkStack();
   DCHECK(mark_stack_ != nullptr);
   immune_region_.Reset();
   is_large_object_space_immune_ = false;
@@ -154,7 +154,7 @@
   // Set the initial bitmap.
   to_space_live_bitmap_ = to_space_->GetLiveBitmap();
   {
-    // TODO: I don't think we should need heap bitmap lock to get the mark bitmap.
+    // TODO: I don't think we should need heap bitmap lock to Get the mark bitmap.
     ReaderMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
     mark_bitmap_ = heap_->GetMarkBitmap();
   }
@@ -172,7 +172,7 @@
   CHECK(Locks::mutator_lock_->IsExclusiveHeld(self_));
   if (kStoreStackTraces) {
     Locks::mutator_lock_->AssertExclusiveHeld(self_);
-    // Store the stack traces into the runtime fault string in case we get a heap corruption
+    // Store the stack traces into the runtime fault string in case we Get a heap corruption
     // related crash later.
     ThreadState old_state = self_->SetStateUnsafe(kRunnable);
     std::ostringstream oss;
@@ -231,7 +231,7 @@
   BindBitmaps();
   // Process dirty cards and add dirty cards to mod-union tables.
   heap_->ProcessCards(timings_, kUseRememberedSet && generational_);
-  // Clear the whole card table since we can not get any additional dirty cards during the
+  // Clear the whole card table since we can not Get any additional dirty cards during the
   // paused GC. This saves memory but only works for pause the world collectors.
   timings_.NewSplit("ClearCardTable");
   heap_->GetCardTable()->ClearCardTable();
diff --git a/runtime/gc/collector/semi_space.h b/runtime/gc/collector/semi_space.h
index 9fdf471..4b1ecc4 100644
--- a/runtime/gc/collector/semi_space.h
+++ b/runtime/gc/collector/semi_space.h
@@ -242,7 +242,7 @@
   // heap. When false, collect only the bump pointer spaces.
   bool whole_heap_collection_;
 
-  // How many objects and bytes we moved, used so that we don't need to get the size of the
+  // How many objects and bytes we moved, used so that we don't need to Get the size of the
   // to_space_ when calculating how many objects and bytes we freed.
   size_t bytes_moved_;
   size_t objects_moved_;
diff --git a/runtime/gc/collector/sticky_mark_sweep.cc b/runtime/gc/collector/sticky_mark_sweep.cc
index ce51ac5..5a58446 100644
--- a/runtime/gc/collector/sticky_mark_sweep.cc
+++ b/runtime/gc/collector/sticky_mark_sweep.cc
@@ -49,7 +49,7 @@
 
 void StickyMarkSweep::MarkReachableObjects() {
   // All reachable objects must be referenced by a root or a dirty card, so we can clear the mark
-  // stack here since all objects in the mark stack will get scanned by the card scanning anyways.
+  // stack here since all objects in the mark stack will Get scanned by the card scanning anyways.
   // TODO: Not put these objects in the mark stack in the first place.
   mark_stack_->Reset();
   RecursiveMarkDirtyObjects(false, accounting::CardTable::kCardDirty - 1);
diff --git a/runtime/gc/heap-inl.h b/runtime/gc/heap-inl.h
index a06f272..7cee5a0 100644
--- a/runtime/gc/heap-inl.h
+++ b/runtime/gc/heap-inl.h
@@ -27,7 +27,7 @@
 #include "gc/space/large_object_space.h"
 #include "gc/space/rosalloc_space-inl.h"
 #include "runtime.h"
-#include "sirt_ref-inl.h"
+#include "handle_scope-inl.h"
 #include "thread.h"
 #include "thread-inl.h"
 #include "verify_object-inl.h"
@@ -144,10 +144,10 @@
       mirror::Object** end_address;
       while (!allocation_stack_->AtomicBumpBack(kThreadLocalAllocationStackSize,
                                                 &start_address, &end_address)) {
-        // Disable verify object in SirtRef as obj isn't on the alloc stack yet.
-        SirtRefNoVerify<mirror::Object> ref(self, *obj);
+        // TODO: Add handle VerifyObject.
+        StackHandleScope<1> hs(self);
+        HandleWrapper<mirror::Object> wrapper(hs.NewHandleWrapper(obj));
         CollectGarbageInternal(collector::kGcTypeSticky, kGcCauseForAlloc, false);
-        *obj = ref.get();
       }
       self->SetThreadLocalAllocationStack(start_address, end_address);
       // Retry on the new thread-local allocation stack.
@@ -159,10 +159,10 @@
     // This is safe to do since the GC will never free objects which are neither in the allocation
     // stack or the live bitmap.
     while (!allocation_stack_->AtomicPushBack(*obj)) {
-      // Disable verify object in SirtRef as obj isn't on the alloc stack yet.
-      SirtRefNoVerify<mirror::Object> ref(self, *obj);
+      // TODO: Add handle VerifyObject.
+      StackHandleScope<1> hs(self);
+      HandleWrapper<mirror::Object> wrapper(hs.NewHandleWrapper(obj));
       CollectGarbageInternal(collector::kGcTypeSticky, kGcCauseForAlloc, false);
-      *obj = ref.get();
     }
   }
 }
@@ -300,11 +300,7 @@
 inline void Heap::CheckConcurrentGC(Thread* self, size_t new_num_bytes_allocated,
                                     mirror::Object** obj) {
   if (UNLIKELY(new_num_bytes_allocated >= concurrent_start_bytes_)) {
-    // The SirtRef is necessary since the calls in RequestConcurrentGC are a safepoint.
-    SirtRef<mirror::Object> ref(self, *obj);
-    RequestConcurrentGC(self);
-    // Restore obj in case it moved.
-    *obj = ref.get();
+    RequestConcurrentGCAndSaveObject(self, obj);
   }
 }
 
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index f2919e8..4642a98 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -62,7 +62,7 @@
 #include "runtime.h"
 #include "ScopedLocalRef.h"
 #include "scoped_thread_state_change.h"
-#include "sirt_ref.h"
+#include "handle_scope-inl.h"
 #include "thread_list.h"
 #include "UniquePtr.h"
 #include "well_known_classes.h"
@@ -1070,10 +1070,11 @@
                                              size_t alloc_size, size_t* bytes_allocated,
                                              size_t* usable_size,
                                              mirror::Class** klass) {
-  mirror::Object* ptr = nullptr;
   bool was_default_allocator = allocator == GetCurrentAllocator();
   DCHECK(klass != nullptr);
-  SirtRef<mirror::Class> sirt_klass(self, *klass);
+  StackHandleScope<1> hs(self);
+  HandleWrapper<mirror::Class> h(hs.NewHandleWrapper(klass));
+  klass = nullptr;  // Invalidate for safety.
   // The allocation failed. If the GC is running, block until it completes, and then retry the
   // allocation.
   collector::GcType last_gc = WaitForGcToComplete(kGcCauseForAlloc, self);
@@ -1081,31 +1082,32 @@
     // If we were the default allocator but the allocator changed while we were suspended,
     // abort the allocation.
     if (was_default_allocator && allocator != GetCurrentAllocator()) {
-      *klass = sirt_klass.get();
       return nullptr;
     }
     // A GC was in progress and we blocked, retry allocation now that memory has been freed.
-    ptr = TryToAllocate<true, false>(self, allocator, alloc_size, bytes_allocated, usable_size);
+    mirror::Object* ptr = TryToAllocate<true, false>(self, allocator, alloc_size, bytes_allocated,
+                                                     usable_size);
+    if (ptr != nullptr) {
+      return ptr;
+    }
   }
 
   collector::GcType tried_type = next_gc_type_;
-  if (ptr == nullptr) {
-    const bool gc_ran =
-        CollectGarbageInternal(tried_type, kGcCauseForAlloc, false) != collector::kGcTypeNone;
-    if (was_default_allocator && allocator != GetCurrentAllocator()) {
-      *klass = sirt_klass.get();
-      return nullptr;
-    }
-    if (gc_ran) {
-      ptr = TryToAllocate<true, false>(self, allocator, alloc_size, bytes_allocated, usable_size);
+  const bool gc_ran =
+      CollectGarbageInternal(tried_type, kGcCauseForAlloc, false) != collector::kGcTypeNone;
+  if (was_default_allocator && allocator != GetCurrentAllocator()) {
+    return nullptr;
+  }
+  if (gc_ran) {
+    mirror::Object* ptr = TryToAllocate<true, false>(self, allocator, alloc_size, bytes_allocated,
+                                                     usable_size);
+    if (ptr != nullptr) {
+      return ptr;
     }
   }
 
   // Loop through our different Gc types and try to Gc until we get enough free memory.
   for (collector::GcType gc_type : gc_plan_) {
-    if (ptr != nullptr) {
-      break;
-    }
     if (gc_type == tried_type) {
       continue;
     }
@@ -1113,40 +1115,41 @@
     const bool gc_ran =
         CollectGarbageInternal(gc_type, kGcCauseForAlloc, false) != collector::kGcTypeNone;
     if (was_default_allocator && allocator != GetCurrentAllocator()) {
-      *klass = sirt_klass.get();
       return nullptr;
     }
     if (gc_ran) {
       // Did we free sufficient memory for the allocation to succeed?
-      ptr = TryToAllocate<true, false>(self, allocator, alloc_size, bytes_allocated, usable_size);
+      mirror::Object* ptr = TryToAllocate<true, false>(self, allocator, alloc_size, bytes_allocated,
+                                                       usable_size);
+      if (ptr != nullptr) {
+        return ptr;
+      }
     }
   }
   // Allocations have failed after GCs;  this is an exceptional state.
-  if (ptr == nullptr) {
-    // Try harder, growing the heap if necessary.
-    ptr = TryToAllocate<true, true>(self, allocator, alloc_size, bytes_allocated, usable_size);
+  // Try harder, growing the heap if necessary.
+  mirror::Object* ptr = TryToAllocate<true, true>(self, allocator, alloc_size, bytes_allocated,
+                                                  usable_size);
+  if (ptr != nullptr) {
+    return ptr;
   }
-  if (ptr == nullptr) {
-    // Most allocations should have succeeded by now, so the heap is really full, really fragmented,
-    // or the requested size is really big. Do another GC, collecting SoftReferences this time. The
-    // VM spec requires that all SoftReferences have been collected and cleared before throwing
-    // OOME.
-    VLOG(gc) << "Forcing collection of SoftReferences for " << PrettySize(alloc_size)
-             << " allocation";
-    // TODO: Run finalization, but this may cause more allocations to occur.
-    // We don't need a WaitForGcToComplete here either.
-    DCHECK(!gc_plan_.empty());
-    CollectGarbageInternal(gc_plan_.back(), kGcCauseForAlloc, true);
-    if (was_default_allocator && allocator != GetCurrentAllocator()) {
-      *klass = sirt_klass.get();
-      return nullptr;
-    }
-    ptr = TryToAllocate<true, true>(self, allocator, alloc_size, bytes_allocated, usable_size);
-    if (ptr == nullptr) {
-      ThrowOutOfMemoryError(self, alloc_size, false);
-    }
+  // Most allocations should have succeeded by now, so the heap is really full, really fragmented,
+  // or the requested size is really big. Do another GC, collecting SoftReferences this time. The
+  // VM spec requires that all SoftReferences have been collected and cleared before throwing
+  // OOME.
+  VLOG(gc) << "Forcing collection of SoftReferences for " << PrettySize(alloc_size)
+           << " allocation";
+  // TODO: Run finalization, but this may cause more allocations to occur.
+  // We don't need a WaitForGcToComplete here either.
+  DCHECK(!gc_plan_.empty());
+  CollectGarbageInternal(gc_plan_.back(), kGcCauseForAlloc, true);
+  if (was_default_allocator && allocator != GetCurrentAllocator()) {
+    return nullptr;
   }
-  *klass = sirt_klass.get();
+  ptr = TryToAllocate<true, true>(self, allocator, alloc_size, bytes_allocated, usable_size);
+  if (ptr == nullptr) {
+    ThrowOutOfMemoryError(self, alloc_size, false);
+  }
   return ptr;
 }
 
@@ -1331,11 +1334,6 @@
       if (collector_type == collector_type_) {
         return;
       }
-      if (Runtime::Current()->IsShuttingDown(self)) {
-        // Don't allow heap transitions to happen if the runtime is shutting down since these can
-        // cause objects to get finalized.
-        return;
-      }
       // GC can be disabled if someone has a used GetPrimitiveArrayCritical but not yet released.
       if (!copying_transition || disable_moving_gc_count_ == 0) {
         // TODO: Not hard code in semi-space collector?
@@ -1345,6 +1343,12 @@
     }
     usleep(1000);
   }
+  if (Runtime::Current()->IsShuttingDown(self)) {
+    // Don't allow heap transitions to happen if the runtime is shutting down since these can
+    // cause objects to get finalized.
+    FinishGC(self, collector::kGcTypeNone);
+    return;
+  }
   tl->SuspendAll();
   switch (collector_type) {
     case kCollectorTypeSS:
@@ -2535,6 +2539,12 @@
   *object = soa.Decode<mirror::Object*>(arg.get());
 }
 
+void Heap::RequestConcurrentGCAndSaveObject(Thread* self, mirror::Object** obj) {
+  StackHandleScope<1> hs(self);
+  HandleWrapper<mirror::Object> wrapper(hs.NewHandleWrapper(obj));
+  RequestConcurrentGC(self);
+}
+
 void Heap::RequestConcurrentGC(Thread* self) {
   // Make sure that we can do a concurrent GC.
   Runtime* runtime = Runtime::Current();
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index f71de1a..3b071d1 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -412,7 +412,7 @@
     return GetTotalMemory() - num_bytes_allocated_;
   }
 
-  // Get the space that corresponds to an object's address. Current implementation searches all
+  // get the space that corresponds to an object's address. Current implementation searches all
   // spaces in turn. If fail_ok is false then failing to find a space will cause an abort.
   // TODO: consider using faster data structure like binary tree.
   space::ContinuousSpace* FindContinuousSpaceFromObject(const mirror::Object*, bool fail_ok) const;
@@ -582,6 +582,10 @@
                                        mirror::Object** obj)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  accounting::ObjectStack* GetMarkStack() {
+    return mark_stack_.get();
+  }
+
   // We don't force this to be inlined since it is a slow path.
   template <bool kInstrumented, typename PreFenceVisitor>
   mirror::Object* AllocLargeObject(Thread* self, mirror::Class* klass, size_t byte_count,
@@ -634,7 +638,10 @@
   void RequestCollectorTransition(CollectorType desired_collector_type, uint64_t delta_time)
       LOCKS_EXCLUDED(heap_trim_request_lock_);
   void RequestHeapTrim() LOCKS_EXCLUDED(Locks::runtime_shutdown_lock_);
-  void RequestConcurrentGC(Thread* self) LOCKS_EXCLUDED(Locks::runtime_shutdown_lock_);
+  void RequestConcurrentGCAndSaveObject(Thread* self, mirror::Object** obj)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void RequestConcurrentGC(Thread* self)
+      LOCKS_EXCLUDED(Locks::runtime_shutdown_lock_);
   bool IsGCRequestPending() const;
 
   // Sometimes CollectGarbageInternal decides to run a different Gc than you requested. Returns
diff --git a/runtime/gc/heap_test.cc b/runtime/gc/heap_test.cc
index a85ad4d..8850b92 100644
--- a/runtime/gc/heap_test.cc
+++ b/runtime/gc/heap_test.cc
@@ -20,7 +20,7 @@
 #include "mirror/class-inl.h"
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
-#include "sirt_ref.h"
+#include "handle_scope-inl.h"
 
 namespace art {
 namespace gc {
@@ -43,14 +43,16 @@
     ScopedObjectAccess soa(Thread::Current());
     // garbage is created during ClassLinker::Init
 
-    SirtRef<mirror::Class> c(soa.Self(), class_linker_->FindSystemClass(soa.Self(),
-                                                                        "[Ljava/lang/Object;"));
+    StackHandleScope<1> hs(soa.Self());
+    Handle<mirror::Class> c(
+        hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "[Ljava/lang/Object;")));
     for (size_t i = 0; i < 1024; ++i) {
-      SirtRef<mirror::ObjectArray<mirror::Object> > array(soa.Self(),
-          mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), c.get(), 2048));
+      StackHandleScope<1> hs(soa.Self());
+      Handle<mirror::ObjectArray<mirror::Object> > array(hs.NewHandle(
+          mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), c.Get(), 2048)));
       for (size_t j = 0; j < 2048; ++j) {
         mirror::String* string = mirror::String::AllocFromModifiedUtf8(soa.Self(), "hello, world!");
-        // SIRT operator -> deferences the SIRT before running the method.
+        // handle scope operator -> deferences the handle scope before running the method.
         array->Set<false>(j, string);
       }
     }
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 858582e..446f898 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -144,8 +144,8 @@
   std::string error_msg;
   bool is_system = false;
   if (FindImageFilename(image_location, image_isa, &image_filename, &is_system)) {
-    ImageSpace* space = ImageSpace::Init(image_filename.c_str(), image_location,
-                                         !is_system, &error_msg);
+    ImageSpace* space = ImageSpace::Init(image_filename.c_str(), image_location, !is_system,
+                                         &error_msg);
     if (space != nullptr) {
       return space;
     }
@@ -245,21 +245,6 @@
     return nullptr;
   }
 
-  Runtime* runtime = Runtime::Current();
-  mirror::Object* resolution_method = image_header.GetImageRoot(ImageHeader::kResolutionMethod);
-  runtime->SetResolutionMethod(down_cast<mirror::ArtMethod*>(resolution_method));
-  mirror::Object* imt_conflict_method = image_header.GetImageRoot(ImageHeader::kImtConflictMethod);
-  runtime->SetImtConflictMethod(down_cast<mirror::ArtMethod*>(imt_conflict_method));
-  mirror::Object* default_imt = image_header.GetImageRoot(ImageHeader::kDefaultImt);
-  runtime->SetDefaultImt(down_cast<mirror::ObjectArray<mirror::ArtMethod>*>(default_imt));
-
-  mirror::Object* callee_save_method = image_header.GetImageRoot(ImageHeader::kCalleeSaveMethod);
-  runtime->SetCalleeSaveMethod(down_cast<mirror::ArtMethod*>(callee_save_method), Runtime::kSaveAll);
-  callee_save_method = image_header.GetImageRoot(ImageHeader::kRefsOnlySaveMethod);
-  runtime->SetCalleeSaveMethod(down_cast<mirror::ArtMethod*>(callee_save_method), Runtime::kRefsOnly);
-  callee_save_method = image_header.GetImageRoot(ImageHeader::kRefsAndArgsSaveMethod);
-  runtime->SetCalleeSaveMethod(down_cast<mirror::ArtMethod*>(callee_save_method), Runtime::kRefsAndArgs);
-
   UniquePtr<ImageSpace> space(new ImageSpace(image_filename, image_location,
                                              map.release(), bitmap.release()));
   if (kIsDebugBuild) {
@@ -277,6 +262,23 @@
     return nullptr;
   }
 
+  Runtime* runtime = Runtime::Current();
+  runtime->SetInstructionSet(space->oat_file_->GetOatHeader().GetInstructionSet());
+
+  mirror::Object* resolution_method = image_header.GetImageRoot(ImageHeader::kResolutionMethod);
+  runtime->SetResolutionMethod(down_cast<mirror::ArtMethod*>(resolution_method));
+  mirror::Object* imt_conflict_method = image_header.GetImageRoot(ImageHeader::kImtConflictMethod);
+  runtime->SetImtConflictMethod(down_cast<mirror::ArtMethod*>(imt_conflict_method));
+  mirror::Object* default_imt = image_header.GetImageRoot(ImageHeader::kDefaultImt);
+  runtime->SetDefaultImt(down_cast<mirror::ObjectArray<mirror::ArtMethod>*>(default_imt));
+
+  mirror::Object* callee_save_method = image_header.GetImageRoot(ImageHeader::kCalleeSaveMethod);
+  runtime->SetCalleeSaveMethod(down_cast<mirror::ArtMethod*>(callee_save_method), Runtime::kSaveAll);
+  callee_save_method = image_header.GetImageRoot(ImageHeader::kRefsOnlySaveMethod);
+  runtime->SetCalleeSaveMethod(down_cast<mirror::ArtMethod*>(callee_save_method), Runtime::kRefsOnly);
+  callee_save_method = image_header.GetImageRoot(ImageHeader::kRefsAndArgsSaveMethod);
+  runtime->SetCalleeSaveMethod(down_cast<mirror::ArtMethod*>(callee_save_method), Runtime::kRefsAndArgs);
+
   if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
     LOG(INFO) << "ImageSpace::Init exiting (" << PrettyDuration(NanoTime() - start_time)
              << ") " << *space.get();
diff --git a/runtime/gc/space/malloc_space.cc b/runtime/gc/space/malloc_space.cc
index 7493c19..ba46dcc 100644
--- a/runtime/gc/space/malloc_space.cc
+++ b/runtime/gc/space/malloc_space.cc
@@ -24,7 +24,7 @@
 #include "mirror/class-inl.h"
 #include "mirror/object-inl.h"
 #include "runtime.h"
-#include "sirt_ref-inl.h"
+#include "handle_scope-inl.h"
 #include "thread.h"
 #include "thread_list.h"
 #include "utils.h"
diff --git a/runtime/gc/space/space_test.h b/runtime/gc/space/space_test.h
index 3335e72..ce101e4 100644
--- a/runtime/gc/space/space_test.h
+++ b/runtime/gc/space/space_test.h
@@ -48,7 +48,8 @@
   }
 
   mirror::Class* GetByteArrayClass(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    SirtRef<mirror::ClassLoader> null_loader(self, nullptr);
+    StackHandleScope<1> hs(self);
+    auto null_loader(hs.NewHandle<mirror::ClassLoader>(nullptr));
     if (byte_array_class_ == nullptr) {
       mirror::Class* byte_array_class =
           Runtime::Current()->GetClassLinker()->FindClass(self, "[B", null_loader);
@@ -62,10 +63,11 @@
   mirror::Object* Alloc(space::MallocSpace* alloc_space, Thread* self, size_t bytes,
                         size_t* bytes_allocated, size_t* usable_size)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    SirtRef<mirror::Class> byte_array_class(self, GetByteArrayClass(self));
+    StackHandleScope<1> hs(self);
+    Handle<mirror::Class> byte_array_class(hs.NewHandle(GetByteArrayClass(self)));
     mirror::Object* obj = alloc_space->Alloc(self, bytes, bytes_allocated, usable_size);
     if (obj != nullptr) {
-      InstallClass(obj, byte_array_class.get(), bytes);
+      InstallClass(obj, byte_array_class.Get(), bytes);
     }
     return obj;
   }
@@ -73,10 +75,11 @@
   mirror::Object* AllocWithGrowth(space::MallocSpace* alloc_space, Thread* self, size_t bytes,
                                   size_t* bytes_allocated, size_t* usable_size)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    SirtRef<mirror::Class> byte_array_class(self, GetByteArrayClass(self));
+    StackHandleScope<1> hs(self);
+    Handle<mirror::Class> byte_array_class(hs.NewHandle(GetByteArrayClass(self)));
     mirror::Object* obj = alloc_space->AllocWithGrowth(self, bytes, bytes_allocated, usable_size);
     if (obj != nullptr) {
-      InstallClass(obj, byte_array_class.get(), bytes);
+      InstallClass(obj, byte_array_class.Get(), bytes);
     }
     return obj;
   }
@@ -177,9 +180,10 @@
 
   // Succeeds, fits without adjusting the footprint limit.
   size_t ptr1_bytes_allocated, ptr1_usable_size;
-  SirtRef<mirror::Object> ptr1(self, Alloc(space, self, 1 * MB, &ptr1_bytes_allocated,
-                                           &ptr1_usable_size));
-  EXPECT_TRUE(ptr1.get() != nullptr);
+  StackHandleScope<3> hs(soa.Self());
+  Handle<mirror::Object> ptr1(
+      hs.NewHandle(Alloc(space, self, 1 * MB, &ptr1_bytes_allocated, &ptr1_usable_size)));
+  EXPECT_TRUE(ptr1.Get() != nullptr);
   EXPECT_LE(1U * MB, ptr1_bytes_allocated);
   EXPECT_LE(1U * MB, ptr1_usable_size);
   EXPECT_LE(ptr1_usable_size, ptr1_bytes_allocated);
@@ -190,9 +194,9 @@
 
   // Succeeds, adjusts the footprint.
   size_t ptr3_bytes_allocated, ptr3_usable_size;
-  SirtRef<mirror::Object> ptr3(self, AllocWithGrowth(space, self, 8 * MB, &ptr3_bytes_allocated,
-                                                     &ptr3_usable_size));
-  EXPECT_TRUE(ptr3.get() != nullptr);
+  Handle<mirror::Object> ptr3(
+      hs.NewHandle(AllocWithGrowth(space, self, 8 * MB, &ptr3_bytes_allocated, &ptr3_usable_size)));
+  EXPECT_TRUE(ptr3.Get() != nullptr);
   EXPECT_LE(8U * MB, ptr3_bytes_allocated);
   EXPECT_LE(8U * MB, ptr3_usable_size);
   EXPECT_LE(ptr3_usable_size, ptr3_bytes_allocated);
@@ -206,23 +210,23 @@
   EXPECT_TRUE(ptr5 == nullptr);
 
   // Release some memory.
-  size_t free3 = space->AllocationSize(ptr3.get(), nullptr);
+  size_t free3 = space->AllocationSize(ptr3.Get(), nullptr);
   EXPECT_EQ(free3, ptr3_bytes_allocated);
-  EXPECT_EQ(free3, space->Free(self, ptr3.reset(nullptr)));
+  EXPECT_EQ(free3, space->Free(self, ptr3.Assign(nullptr)));
   EXPECT_LE(8U * MB, free3);
 
   // Succeeds, now that memory has been freed.
   size_t ptr6_bytes_allocated, ptr6_usable_size;
-  SirtRef<mirror::Object> ptr6(self, AllocWithGrowth(space, self, 9 * MB, &ptr6_bytes_allocated,
-                                                     &ptr6_usable_size));
-  EXPECT_TRUE(ptr6.get() != nullptr);
+  Handle<mirror::Object> ptr6(
+      hs.NewHandle(AllocWithGrowth(space, self, 9 * MB, &ptr6_bytes_allocated, &ptr6_usable_size)));
+  EXPECT_TRUE(ptr6.Get() != nullptr);
   EXPECT_LE(9U * MB, ptr6_bytes_allocated);
   EXPECT_LE(9U * MB, ptr6_usable_size);
   EXPECT_LE(ptr6_usable_size, ptr6_bytes_allocated);
 
   // Final clean up.
-  size_t free1 = space->AllocationSize(ptr1.get(), nullptr);
-  space->Free(self, ptr1.reset(nullptr));
+  size_t free1 = space->AllocationSize(ptr1.Get(), nullptr);
+  space->Free(self, ptr1.Assign(nullptr));
   EXPECT_LE(1U * MB, free1);
 
   // Make sure that the zygote space isn't directly at the start of the space.
@@ -243,8 +247,8 @@
   AddSpace(space, false);
 
   // Succeeds, fits without adjusting the footprint limit.
-  ptr1.reset(Alloc(space, self, 1 * MB, &ptr1_bytes_allocated, &ptr1_usable_size));
-  EXPECT_TRUE(ptr1.get() != nullptr);
+  ptr1.Assign(Alloc(space, self, 1 * MB, &ptr1_bytes_allocated, &ptr1_usable_size));
+  EXPECT_TRUE(ptr1.Get() != nullptr);
   EXPECT_LE(1U * MB, ptr1_bytes_allocated);
   EXPECT_LE(1U * MB, ptr1_usable_size);
   EXPECT_LE(ptr1_usable_size, ptr1_bytes_allocated);
@@ -254,16 +258,16 @@
   EXPECT_TRUE(ptr2 == nullptr);
 
   // Succeeds, adjusts the footprint.
-  ptr3.reset(AllocWithGrowth(space, self, 2 * MB, &ptr3_bytes_allocated, &ptr3_usable_size));
-  EXPECT_TRUE(ptr3.get() != nullptr);
+  ptr3.Assign(AllocWithGrowth(space, self, 2 * MB, &ptr3_bytes_allocated, &ptr3_usable_size));
+  EXPECT_TRUE(ptr3.Get() != nullptr);
   EXPECT_LE(2U * MB, ptr3_bytes_allocated);
   EXPECT_LE(2U * MB, ptr3_usable_size);
   EXPECT_LE(ptr3_usable_size, ptr3_bytes_allocated);
-  space->Free(self, ptr3.reset(nullptr));
+  space->Free(self, ptr3.Assign(nullptr));
 
   // Final clean up.
-  free1 = space->AllocationSize(ptr1.get(), nullptr);
-  space->Free(self, ptr1.reset(nullptr));
+  free1 = space->AllocationSize(ptr1.Get(), nullptr);
+  space->Free(self, ptr1.Assign(nullptr));
   EXPECT_LE(1U * MB, free1);
 }
 
@@ -279,9 +283,10 @@
 
   // Succeeds, fits without adjusting the footprint limit.
   size_t ptr1_bytes_allocated, ptr1_usable_size;
-  SirtRef<mirror::Object> ptr1(self, Alloc(space, self, 1 * MB, &ptr1_bytes_allocated,
-                                           &ptr1_usable_size));
-  EXPECT_TRUE(ptr1.get() != nullptr);
+  StackHandleScope<3> hs(soa.Self());
+  Handle<mirror::Object> ptr1(
+      hs.NewHandle(Alloc(space, self, 1 * MB, &ptr1_bytes_allocated, &ptr1_usable_size)));
+  EXPECT_TRUE(ptr1.Get() != nullptr);
   EXPECT_LE(1U * MB, ptr1_bytes_allocated);
   EXPECT_LE(1U * MB, ptr1_usable_size);
   EXPECT_LE(ptr1_usable_size, ptr1_bytes_allocated);
@@ -292,9 +297,9 @@
 
   // Succeeds, adjusts the footprint.
   size_t ptr3_bytes_allocated, ptr3_usable_size;
-  SirtRef<mirror::Object> ptr3(self, AllocWithGrowth(space, self, 8 * MB, &ptr3_bytes_allocated,
-                                                     &ptr3_usable_size));
-  EXPECT_TRUE(ptr3.get() != nullptr);
+  Handle<mirror::Object> ptr3(
+      hs.NewHandle(AllocWithGrowth(space, self, 8 * MB, &ptr3_bytes_allocated, &ptr3_usable_size)));
+  EXPECT_TRUE(ptr3.Get() != nullptr);
   EXPECT_LE(8U * MB, ptr3_bytes_allocated);
   EXPECT_LE(8U * MB, ptr3_usable_size);
   EXPECT_LE(ptr3_usable_size, ptr3_bytes_allocated);
@@ -308,23 +313,23 @@
   EXPECT_TRUE(ptr5 == nullptr);
 
   // Release some memory.
-  size_t free3 = space->AllocationSize(ptr3.get(), nullptr);
+  size_t free3 = space->AllocationSize(ptr3.Get(), nullptr);
   EXPECT_EQ(free3, ptr3_bytes_allocated);
-  space->Free(self, ptr3.reset(nullptr));
+  space->Free(self, ptr3.Assign(nullptr));
   EXPECT_LE(8U * MB, free3);
 
   // Succeeds, now that memory has been freed.
   size_t ptr6_bytes_allocated, ptr6_usable_size;
-  SirtRef<mirror::Object> ptr6(self, AllocWithGrowth(space, self, 9 * MB, &ptr6_bytes_allocated,
-                                                     &ptr6_usable_size));
-  EXPECT_TRUE(ptr6.get() != nullptr);
+  Handle<mirror::Object> ptr6(
+      hs.NewHandle(AllocWithGrowth(space, self, 9 * MB, &ptr6_bytes_allocated, &ptr6_usable_size)));
+  EXPECT_TRUE(ptr6.Get() != nullptr);
   EXPECT_LE(9U * MB, ptr6_bytes_allocated);
   EXPECT_LE(9U * MB, ptr6_usable_size);
   EXPECT_LE(ptr6_usable_size, ptr6_bytes_allocated);
 
   // Final clean up.
-  size_t free1 = space->AllocationSize(ptr1.get(), nullptr);
-  space->Free(self, ptr1.reset(nullptr));
+  size_t free1 = space->AllocationSize(ptr1.Get(), nullptr);
+  space->Free(self, ptr1.Assign(nullptr));
   EXPECT_LE(1U * MB, free1);
 }
 
@@ -345,8 +350,6 @@
     lots_of_objects[i] = Alloc(space, self, size_of_zero_length_byte_array, &allocation_size,
                                &usable_size);
     EXPECT_TRUE(lots_of_objects[i] != nullptr);
-    SirtRef<mirror::Object> obj(self, lots_of_objects[i]);
-    lots_of_objects[i] = obj.get();
     size_t computed_usable_size;
     EXPECT_EQ(allocation_size, space->AllocationSize(lots_of_objects[i], &computed_usable_size));
     EXPECT_EQ(usable_size, computed_usable_size);
@@ -360,8 +363,6 @@
     size_t allocation_size, usable_size;
     lots_of_objects[i] = AllocWithGrowth(space, self, 1024, &allocation_size, &usable_size);
     EXPECT_TRUE(lots_of_objects[i] != nullptr);
-    SirtRef<mirror::Object> obj(self, lots_of_objects[i]);
-    lots_of_objects[i] = obj.get();
     size_t computed_usable_size;
     EXPECT_EQ(allocation_size, space->AllocationSize(lots_of_objects[i], &computed_usable_size));
     EXPECT_EQ(usable_size, computed_usable_size);
@@ -418,18 +419,19 @@
           alloc_size = size_of_zero_length_byte_array;
         }
       }
-      SirtRef<mirror::Object> object(self, nullptr);
+      StackHandleScope<1> hs(soa.Self());
+      auto object(hs.NewHandle<mirror::Object>(nullptr));
       size_t bytes_allocated = 0;
       if (round <= 1) {
-        object.reset(Alloc(space, self, alloc_size, &bytes_allocated, nullptr));
+        object.Assign(Alloc(space, self, alloc_size, &bytes_allocated, nullptr));
       } else {
-        object.reset(AllocWithGrowth(space, self, alloc_size, &bytes_allocated, nullptr));
+        object.Assign(AllocWithGrowth(space, self, alloc_size, &bytes_allocated, nullptr));
       }
       footprint = space->GetFootprint();
       EXPECT_GE(space->Size(), footprint);  // invariant
-      if (object.get() != nullptr) {  // allocation succeeded
-        lots_of_objects[i] = object.get();
-        size_t allocation_size = space->AllocationSize(object.get(), nullptr);
+      if (object.Get() != nullptr) {  // allocation succeeded
+        lots_of_objects[i] = object.Get();
+        size_t allocation_size = space->AllocationSize(object.Get(), nullptr);
         EXPECT_EQ(bytes_allocated, allocation_size);
         if (object_size > 0) {
           EXPECT_GE(allocation_size, static_cast<size_t>(object_size));
@@ -509,16 +511,17 @@
   space->RevokeAllThreadLocalBuffers();
 
   // All memory was released, try a large allocation to check freed memory is being coalesced
-  SirtRef<mirror::Object> large_object(self, nullptr);
+  StackHandleScope<1> hs(soa.Self());
+  auto large_object(hs.NewHandle<mirror::Object>(nullptr));
   size_t three_quarters_space = (growth_limit / 2) + (growth_limit / 4);
   size_t bytes_allocated = 0;
   if (round <= 1) {
-    large_object.reset(Alloc(space, self, three_quarters_space, &bytes_allocated, nullptr));
+    large_object.Assign(Alloc(space, self, three_quarters_space, &bytes_allocated, nullptr));
   } else {
-    large_object.reset(AllocWithGrowth(space, self, three_quarters_space, &bytes_allocated,
-                                       nullptr));
+    large_object.Assign(AllocWithGrowth(space, self, three_quarters_space, &bytes_allocated,
+                                        nullptr));
   }
-  EXPECT_TRUE(large_object.get() != nullptr);
+  EXPECT_TRUE(large_object.Get() != nullptr);
 
   // Sanity check footprint
   footprint = space->GetFootprint();
@@ -527,7 +530,7 @@
   EXPECT_LE(space->Size(), growth_limit);
 
   // Clean up
-  space->Free(self, large_object.reset(nullptr));
+  space->Free(self, large_object.Assign(nullptr));
 
   // Sanity check footprint
   footprint = space->GetFootprint();
diff --git a/runtime/handle.h b/runtime/handle.h
new file mode 100644
index 0000000..3127864
--- /dev/null
+++ b/runtime/handle.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2014 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_HANDLE_H_
+#define ART_RUNTIME_HANDLE_H_
+
+#include "base/casts.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "stack.h"
+
+namespace art {
+
+class Thread;
+
+template<class T>
+class Handle {
+ public:
+  Handle() : reference_(nullptr) {
+  }
+  Handle(const Handle<T>& handle) ALWAYS_INLINE : reference_(handle.reference_) {
+  }
+  Handle<T>& operator=(const Handle<T>& handle) ALWAYS_INLINE {
+    reference_ = handle.reference_;
+    return *this;
+  }
+  explicit Handle(StackReference<T>* reference) ALWAYS_INLINE : reference_(reference) {
+  }
+  T& operator*() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE {
+    return *Get();
+  }
+  T* operator->() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE {
+    return Get();
+  }
+  T* Get() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE {
+    return reference_->AsMirrorPtr();
+  }
+  T* Assign(T* reference) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE {
+    T* old = reference_->AsMirrorPtr();
+    reference_->Assign(reference);
+    return old;
+  }
+  jobject ToJObject() const ALWAYS_INLINE {
+    return reinterpret_cast<jobject>(reference_);
+  }
+
+ private:
+  StackReference<T>* reference_;
+
+  template<typename S>
+  explicit Handle(StackReference<S>* reference)
+      : reference_(reinterpret_cast<StackReference<T>*>(reference)) {
+  }
+
+  template<typename S>
+  explicit Handle(const Handle<S>& handle)
+      : reference_(reinterpret_cast<StackReference<T>*>(handle.reference_)) {
+  }
+
+  template<class S> friend class Handle;
+  friend class HandleScope;
+  template<class S> friend class HandleWrapper;
+  template<size_t kNumReferences> friend class StackHandleScope;
+};
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_HANDLE_H_
diff --git a/runtime/handle_scope-inl.h b/runtime/handle_scope-inl.h
new file mode 100644
index 0000000..634f2be
--- /dev/null
+++ b/runtime/handle_scope-inl.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2014 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_HANDLE_SCOPE_INL_H_
+#define ART_RUNTIME_HANDLE_SCOPE_INL_H_
+
+#include "handle_scope-inl.h"
+
+#include "handle.h"
+#include "thread.h"
+
+namespace art {
+
+template<size_t kNumReferences>
+inline StackHandleScope<kNumReferences>::StackHandleScope(Thread* self)
+    : HandleScope(kNumReferences), self_(self), pos_(0) {
+  // TODO: Figure out how to use a compile assert.
+  DCHECK_EQ(OFFSETOF_MEMBER(HandleScope, references_),
+            OFFSETOF_MEMBER(StackHandleScope<1>, references_storage_));
+  for (size_t i = 0; i < kNumReferences; ++i) {
+    SetReference(i, nullptr);
+  }
+  self_->PushHandleScope(this);
+}
+
+template<size_t kNumReferences>
+inline StackHandleScope<kNumReferences>::~StackHandleScope() {
+  HandleScope* top_handle_scope = self_->PopHandleScope();
+  DCHECK_EQ(top_handle_scope, this);
+}
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_HANDLE_SCOPE_INL_H_
diff --git a/runtime/handle_scope.h b/runtime/handle_scope.h
new file mode 100644
index 0000000..27c1bdc
--- /dev/null
+++ b/runtime/handle_scope.h
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2014 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_HANDLE_SCOPE_H_
+#define ART_RUNTIME_HANDLE_SCOPE_H_
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "handle.h"
+#include "stack.h"
+#include "utils.h"
+
+namespace art {
+namespace mirror {
+class Object;
+}
+class Thread;
+
+// HandleScopes can be allocated within the bridge frame between managed and native code backed by
+// stack storage or manually allocated in native.
+class HandleScope {
+ public:
+  ~HandleScope() {}
+
+  // Number of references contained within this handle scope.
+  uint32_t NumberOfReferences() const {
+    return number_of_references_;
+  }
+
+  // We have versions with and without explicit pointer size of the following. The first two are
+  // used at runtime, so OFFSETOF_MEMBER computes the right offsets automatically. The last one
+  // takes the pointer size explicitly so that at compile time we can cross-compile correctly.
+
+  // Returns the size of a HandleScope containing num_references handles.
+  static size_t SizeOf(uint32_t num_references) {
+    size_t header_size = OFFSETOF_MEMBER(HandleScope, references_);
+    size_t data_size = sizeof(StackReference<mirror::Object>) * num_references;
+    return header_size + data_size;
+  }
+
+  // Get the size of the handle scope for the number of entries, with padding added for potential alignment.
+  static size_t GetAlignedHandleScopeSize(uint32_t num_references) {
+    size_t handle_scope_size = SizeOf(num_references);
+    return RoundUp(handle_scope_size, 8);
+  }
+
+  // Get the size of the handle scope for the number of entries, with padding added for potential alignment.
+  static size_t GetAlignedHandleScopeSizeTarget(size_t pointer_size, uint32_t num_references) {
+    // Assume that the layout is packed.
+    size_t header_size = pointer_size + sizeof(number_of_references_);
+    // This assumes there is no layout change between 32 and 64b.
+    size_t data_size = sizeof(StackReference<mirror::Object>) * num_references;
+    size_t handle_scope_size = header_size + data_size;
+    return RoundUp(handle_scope_size, 8);
+  }
+
+  // Link to previous HandleScope or null.
+  HandleScope* GetLink() const {
+    return link_;
+  }
+
+  void SetLink(HandleScope* link) {
+    DCHECK_NE(this, link);
+    link_ = link;
+  }
+
+  // Sets the number_of_references_ field for constructing tables out of raw memory. Warning: will
+  // not resize anything.
+  void SetNumberOfReferences(uint32_t num_references) {
+    number_of_references_ = num_references;
+  }
+
+  mirror::Object* GetReference(size_t i) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      ALWAYS_INLINE {
+    DCHECK_LT(i, number_of_references_);
+    return references_[i].AsMirrorPtr();
+  }
+
+  Handle<mirror::Object> GetHandle(size_t i) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      ALWAYS_INLINE {
+    DCHECK_LT(i, number_of_references_);
+    return Handle<mirror::Object>(&references_[i]);
+  }
+
+  void SetReference(size_t i, mirror::Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      ALWAYS_INLINE {
+    DCHECK_LT(i, number_of_references_);
+    references_[i].Assign(object);
+  }
+
+  bool Contains(StackReference<mirror::Object>* handle_scope_entry) const {
+    // A HandleScope should always contain something. One created by the
+    // jni_compiler should have a jobject/jclass as a native method is
+    // passed in a this pointer or a class
+    DCHECK_GT(number_of_references_, 0U);
+    return ((&references_[0] <= handle_scope_entry)
+            && (handle_scope_entry <= (&references_[number_of_references_ - 1])));
+  }
+
+  // Offset of link within HandleScope, used by generated code
+  static size_t LinkOffset(size_t pointer_size) {
+    return 0;
+  }
+
+  // Offset of length within handle scope, used by generated code
+  static size_t NumberOfReferencesOffset(size_t pointer_size) {
+    return pointer_size;
+  }
+
+  // Offset of link within handle scope, used by generated code
+  static size_t ReferencesOffset(size_t pointer_size) {
+    return pointer_size + sizeof(number_of_references_);
+  }
+
+ protected:
+  explicit HandleScope(size_t number_of_references) :
+      link_(nullptr), number_of_references_(number_of_references) {
+  }
+
+  HandleScope* link_;
+  uint32_t number_of_references_;
+
+  // number_of_references_ are available if this is allocated and filled in by jni_compiler.
+  StackReference<mirror::Object> references_[0];
+
+ private:
+  template<size_t kNumReferences> friend class StackHandleScope;
+  DISALLOW_COPY_AND_ASSIGN(HandleScope);
+};
+
+// A wrapper which wraps around Object** and restores the pointer in the destructor.
+// TODO: Add more functionality.
+template<class T>
+class HandleWrapper {
+ public:
+  HandleWrapper(T** obj, const Handle<T>& handle)
+     : obj_(obj), handle_(handle) {
+  }
+
+  ~HandleWrapper() {
+    *obj_ = handle_.Get();
+  }
+
+ private:
+  T** obj_;
+  Handle<T> handle_;
+};
+
+// Scoped handle storage of a fixed size that is usually stack allocated.
+template<size_t kNumReferences>
+class StackHandleScope : public HandleScope {
+ public:
+  explicit StackHandleScope(Thread* self);
+  ~StackHandleScope();
+
+  template<class T>
+  Handle<T> NewHandle(T* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    SetReference(pos_, object);
+    return Handle<T>(GetHandle(pos_++));
+  }
+
+  template<class T>
+  HandleWrapper<T> NewHandleWrapper(T** object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    SetReference(pos_, *object);
+    Handle<T> h(GetHandle(pos_++));
+    return HandleWrapper<T>(object, h);
+  }
+
+ private:
+  // references_storage_ needs to be first so that it matches the address of references_.
+  StackReference<mirror::Object> references_storage_[kNumReferences];
+  Thread* const self_;
+  size_t pos_;
+
+  template<size_t kNumRefs> friend class StackHandleScope;
+};
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_HANDLE_SCOPE_H_
diff --git a/runtime/stack_indirect_reference_table_test.cc b/runtime/handle_scope_test.cc
similarity index 60%
rename from runtime/stack_indirect_reference_table_test.cc
rename to runtime/handle_scope_test.cc
index 72ef6b6..de563c1 100644
--- a/runtime/stack_indirect_reference_table_test.cc
+++ b/runtime/handle_scope_test.cc
@@ -14,33 +14,49 @@
  * limitations under the License.
  */
 
-#include "stack_indirect_reference_table.h"
 #include "gtest/gtest.h"
+#include "handle_scope-inl.h"
+#include "scoped_thread_state_change.h"
+#include "thread.h"
 
 namespace art {
 
-// Test the offsets computed for members of StackIndirectReferenceTable. Because of cross-compiling
+// Handle scope with a fixed size which is allocated on the stack.
+template<size_t kNumReferences>
+class NoThreadStackHandleScope : public HandleScope {
+ public:
+  explicit NoThreadStackHandleScope() : HandleScope(kNumReferences) {
+  }
+  ~NoThreadStackHandleScope() {
+  }
+
+ private:
+  // references_storage_ needs to be first so that it matches the address of references_
+  StackReference<mirror::Object> references_storage_[kNumReferences];
+};
+
+// Test the offsets computed for members of HandleScope. Because of cross-compiling
 // it is impossible the use OFFSETOF_MEMBER, so we do some reasonable computations ourselves. This
 // test checks whether we do the right thing.
-TEST(StackIndirectReferenceTableTest, Offsets) {
-  // As the members of StackIndirectReferenceTable are private, we cannot use OFFSETOF_MEMBER
+TEST(HandleScopeTest, Offsets) NO_THREAD_SAFETY_ANALYSIS {
+  // As the members of HandleScope are private, we cannot use OFFSETOF_MEMBER
   // here. So do the inverse: set some data, and access it through pointers created from the offsets.
-
-  StackIndirectReferenceTable test_table(reinterpret_cast<mirror::Object*>(0x1234));
-  test_table.SetLink(reinterpret_cast<StackIndirectReferenceTable*>(0x5678));
+  NoThreadStackHandleScope<1> test_table;
+  test_table.SetReference(0, reinterpret_cast<mirror::Object*>(0x1234));
+  test_table.SetLink(reinterpret_cast<HandleScope*>(0x5678));
   test_table.SetNumberOfReferences(0x9ABC);
 
   byte* table_base_ptr = reinterpret_cast<byte*>(&test_table);
 
   {
     uintptr_t* link_ptr = reinterpret_cast<uintptr_t*>(table_base_ptr +
-        StackIndirectReferenceTable::LinkOffset(kPointerSize));
+        HandleScope::LinkOffset(kPointerSize));
     EXPECT_EQ(*link_ptr, static_cast<size_t>(0x5678));
   }
 
   {
     uint32_t* num_ptr = reinterpret_cast<uint32_t*>(table_base_ptr +
-        StackIndirectReferenceTable::NumberOfReferencesOffset(kPointerSize));
+        HandleScope::NumberOfReferencesOffset(kPointerSize));
     EXPECT_EQ(*num_ptr, static_cast<size_t>(0x9ABC));
   }
 
@@ -50,7 +66,7 @@
     EXPECT_EQ(sizeof(StackReference<mirror::Object>), sizeof(uint32_t));
 
     uint32_t* ref_ptr = reinterpret_cast<uint32_t*>(table_base_ptr +
-        StackIndirectReferenceTable::ReferencesOffset(kPointerSize));
+        HandleScope::ReferencesOffset(kPointerSize));
     EXPECT_EQ(*ref_ptr, static_cast<uint32_t>(0x1234));
   }
 }
diff --git a/runtime/image.h b/runtime/image.h
index ce2bc58..abe1ad8 100644
--- a/runtime/image.h
+++ b/runtime/image.h
@@ -91,7 +91,7 @@
   static std::string GetOatLocationFromImageLocation(const std::string& image) {
     std::string oat_filename = image;
     if (oat_filename.length() <= 3) {
-      return oat_filename + ".oat";
+      oat_filename += ".oat";
     } else {
       oat_filename.replace(oat_filename.length() - 3, 3, "oat");
     }
diff --git a/runtime/indirect_reference_table-inl.h b/runtime/indirect_reference_table-inl.h
index 1a28347..42a9757 100644
--- a/runtime/indirect_reference_table-inl.h
+++ b/runtime/indirect_reference_table-inl.h
@@ -33,7 +33,7 @@
     LOG(WARNING) << "Attempt to look up NULL " << kind_;
     return false;
   }
-  if (UNLIKELY(GetIndirectRefKind(iref) == kSirtOrInvalid)) {
+  if (UNLIKELY(GetIndirectRefKind(iref) == kHandleScopeOrInvalid)) {
     LOG(ERROR) << "JNI ERROR (app bug): invalid " << kind_ << " " << iref;
     AbortIfNoCheckJNI();
     return false;
diff --git a/runtime/indirect_reference_table.cc b/runtime/indirect_reference_table.cc
index b81e43a..432481b 100644
--- a/runtime/indirect_reference_table.cc
+++ b/runtime/indirect_reference_table.cc
@@ -66,7 +66,7 @@
                                                size_t maxCount, IndirectRefKind desiredKind) {
   CHECK_GT(initialCount, 0U);
   CHECK_LE(initialCount, maxCount);
-  CHECK_NE(desiredKind, kSirtOrInvalid);
+  CHECK_NE(desiredKind, kHandleScopeOrInvalid);
 
   std::string error_str;
   const size_t initial_bytes = initialCount * sizeof(const mirror::Object*);
@@ -184,9 +184,9 @@
 
   int idx = ExtractIndex(iref);
 
-  if (GetIndirectRefKind(iref) == kSirtOrInvalid &&
-      Thread::Current()->SirtContains(reinterpret_cast<jobject>(iref))) {
-    LOG(WARNING) << "Attempt to remove local SIRT entry from IRT, ignoring";
+  if (GetIndirectRefKind(iref) == kHandleScopeOrInvalid &&
+      Thread::Current()->HandleScopeContains(reinterpret_cast<jobject>(iref))) {
+    LOG(WARNING) << "Attempt to remove local handle scope entry from IRT, ignoring";
     return true;
   }
 
diff --git a/runtime/indirect_reference_table.h b/runtime/indirect_reference_table.h
index f365acc..833b07a 100644
--- a/runtime/indirect_reference_table.h
+++ b/runtime/indirect_reference_table.h
@@ -111,7 +111,7 @@
  * For convenience these match up with enum jobjectRefType from jni.h.
  */
 enum IndirectRefKind {
-  kSirtOrInvalid = 0,  // <<stack indirect reference table or invalid reference>>
+  kHandleScopeOrInvalid = 0,  // <<stack indirect reference table or invalid reference>>
   kLocal         = 1,  // <<local reference>>
   kGlobal        = 2,  // <<global reference>>
   kWeakGlobal    = 3   // <<weak global reference>>
diff --git a/runtime/intern_table_test.cc b/runtime/intern_table_test.cc
index 8987127..5995d9e 100644
--- a/runtime/intern_table_test.cc
+++ b/runtime/intern_table_test.cc
@@ -18,7 +18,7 @@
 
 #include "common_runtime_test.h"
 #include "mirror/object.h"
-#include "sirt_ref.h"
+#include "handle_scope-inl.h"
 
 namespace art {
 
@@ -27,19 +27,21 @@
 TEST_F(InternTableTest, Intern) {
   ScopedObjectAccess soa(Thread::Current());
   InternTable intern_table;
-  SirtRef<mirror::String> foo_1(soa.Self(), intern_table.InternStrong(3, "foo"));
-  SirtRef<mirror::String> foo_2(soa.Self(), intern_table.InternStrong(3, "foo"));
-  SirtRef<mirror::String> foo_3(soa.Self(), mirror::String::AllocFromModifiedUtf8(soa.Self(), "foo"));
-  SirtRef<mirror::String> bar(soa.Self(), intern_table.InternStrong(3, "bar"));
+  StackHandleScope<4> hs(soa.Self());
+  Handle<mirror::String> foo_1(hs.NewHandle(intern_table.InternStrong(3, "foo")));
+  Handle<mirror::String> foo_2(hs.NewHandle(intern_table.InternStrong(3, "foo")));
+  Handle<mirror::String> foo_3(
+      hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "foo")));
+  Handle<mirror::String> bar(hs.NewHandle(intern_table.InternStrong(3, "bar")));
   EXPECT_TRUE(foo_1->Equals("foo"));
   EXPECT_TRUE(foo_2->Equals("foo"));
   EXPECT_TRUE(foo_3->Equals("foo"));
-  EXPECT_TRUE(foo_1.get() != NULL);
-  EXPECT_TRUE(foo_2.get() != NULL);
-  EXPECT_EQ(foo_1.get(), foo_2.get());
-  EXPECT_NE(foo_1.get(), bar.get());
-  EXPECT_NE(foo_2.get(), bar.get());
-  EXPECT_NE(foo_3.get(), bar.get());
+  EXPECT_TRUE(foo_1.Get() != NULL);
+  EXPECT_TRUE(foo_2.Get() != NULL);
+  EXPECT_EQ(foo_1.Get(), foo_2.Get());
+  EXPECT_NE(foo_1.Get(), bar.Get());
+  EXPECT_NE(foo_2.Get(), bar.Get());
+  EXPECT_NE(foo_3.Get(), bar.Get());
 }
 
 TEST_F(InternTableTest, Size) {
@@ -47,8 +49,10 @@
   InternTable t;
   EXPECT_EQ(0U, t.Size());
   t.InternStrong(3, "foo");
-  SirtRef<mirror::String> foo(soa.Self(), mirror::String::AllocFromModifiedUtf8(soa.Self(), "foo"));
-  t.InternWeak(foo.get());
+  StackHandleScope<1> hs(soa.Self());
+  Handle<mirror::String> foo(
+      hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "foo")));
+  t.InternWeak(foo.Get());
   EXPECT_EQ(1U, t.Size());
   t.InternStrong(3, "bar");
   EXPECT_EQ(2U, t.Size());
@@ -93,19 +97,20 @@
   InternTable t;
   t.InternStrong(3, "foo");
   t.InternStrong(3, "bar");
-  SirtRef<mirror::String> hello(soa.Self(),
-                                mirror::String::AllocFromModifiedUtf8(soa.Self(), "hello"));
-  SirtRef<mirror::String> world(soa.Self(),
-                                mirror::String::AllocFromModifiedUtf8(soa.Self(), "world"));
-  SirtRef<mirror::String> s0(soa.Self(), t.InternWeak(hello.get()));
-  SirtRef<mirror::String> s1(soa.Self(), t.InternWeak(world.get()));
+  StackHandleScope<5> hs(soa.Self());
+  Handle<mirror::String> hello(
+      hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "hello")));
+  Handle<mirror::String> world(
+      hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "world")));
+  Handle<mirror::String> s0(hs.NewHandle(t.InternWeak(hello.Get())));
+  Handle<mirror::String> s1(hs.NewHandle(t.InternWeak(world.Get())));
 
   EXPECT_EQ(4U, t.Size());
 
   // We should traverse only the weaks...
   TestPredicate p;
-  p.Expect(s0.get());
-  p.Expect(s1.get());
+  p.Expect(s0.Get());
+  p.Expect(s1.Get());
   {
     ReaderMutexLock mu(soa.Self(), *Locks::heap_bitmap_lock_);
     t.SweepInternTableWeaks(IsMarkedSweepingCallback, &p);
@@ -114,9 +119,9 @@
   EXPECT_EQ(2U, t.Size());
 
   // Just check that we didn't corrupt the map.
-  SirtRef<mirror::String> still_here(soa.Self(),
-                                     mirror::String::AllocFromModifiedUtf8(soa.Self(), "still here"));
-  t.InternWeak(still_here.get());
+  Handle<mirror::String> still_here(
+      hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "still here")));
+  t.InternWeak(still_here.Get());
   EXPECT_EQ(3U, t.Size());
 }
 
@@ -125,48 +130,53 @@
   {
     // Strongs are never weak.
     InternTable t;
-    SirtRef<mirror::String> interned_foo_1(soa.Self(), t.InternStrong(3, "foo"));
-    EXPECT_FALSE(t.ContainsWeak(interned_foo_1.get()));
-    SirtRef<mirror::String> interned_foo_2(soa.Self(), t.InternStrong(3, "foo"));
-    EXPECT_FALSE(t.ContainsWeak(interned_foo_2.get()));
-    EXPECT_EQ(interned_foo_1.get(), interned_foo_2.get());
+    StackHandleScope<2> hs(soa.Self());
+    Handle<mirror::String> interned_foo_1(hs.NewHandle(t.InternStrong(3, "foo")));
+    EXPECT_FALSE(t.ContainsWeak(interned_foo_1.Get()));
+    Handle<mirror::String> interned_foo_2(hs.NewHandle(t.InternStrong(3, "foo")));
+    EXPECT_FALSE(t.ContainsWeak(interned_foo_2.Get()));
+    EXPECT_EQ(interned_foo_1.Get(), interned_foo_2.Get());
   }
 
   {
     // Weaks are always weak.
     InternTable t;
-    SirtRef<mirror::String> foo_1(soa.Self(),
-                                  mirror::String::AllocFromModifiedUtf8(soa.Self(), "foo"));
-    SirtRef<mirror::String> foo_2(soa.Self(),
-                                  mirror::String::AllocFromModifiedUtf8(soa.Self(), "foo"));
-    EXPECT_NE(foo_1.get(), foo_2.get());
-    SirtRef<mirror::String> interned_foo_1(soa.Self(), t.InternWeak(foo_1.get()));
-    SirtRef<mirror::String> interned_foo_2(soa.Self(), t.InternWeak(foo_2.get()));
-    EXPECT_TRUE(t.ContainsWeak(interned_foo_2.get()));
-    EXPECT_EQ(interned_foo_1.get(), interned_foo_2.get());
+    StackHandleScope<4> hs(soa.Self());
+    Handle<mirror::String> foo_1(
+        hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "foo")));
+    Handle<mirror::String> foo_2(
+        hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "foo")));
+    EXPECT_NE(foo_1.Get(), foo_2.Get());
+    Handle<mirror::String> interned_foo_1(hs.NewHandle(t.InternWeak(foo_1.Get())));
+    Handle<mirror::String> interned_foo_2(hs.NewHandle(t.InternWeak(foo_2.Get())));
+    EXPECT_TRUE(t.ContainsWeak(interned_foo_2.Get()));
+    EXPECT_EQ(interned_foo_1.Get(), interned_foo_2.Get());
   }
 
   {
     // A weak can be promoted to a strong.
     InternTable t;
-    SirtRef<mirror::String> foo(soa.Self(), mirror::String::AllocFromModifiedUtf8(soa.Self(), "foo"));
-    SirtRef<mirror::String> interned_foo_1(soa.Self(), t.InternWeak(foo.get()));
-    EXPECT_TRUE(t.ContainsWeak(interned_foo_1.get()));
-    SirtRef<mirror::String> interned_foo_2(soa.Self(), t.InternStrong(3, "foo"));
-    EXPECT_FALSE(t.ContainsWeak(interned_foo_2.get()));
-    EXPECT_EQ(interned_foo_1.get(), interned_foo_2.get());
+    StackHandleScope<3> hs(soa.Self());
+    Handle<mirror::String> foo(
+        hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "foo")));
+    Handle<mirror::String> interned_foo_1(hs.NewHandle(t.InternWeak(foo.Get())));
+    EXPECT_TRUE(t.ContainsWeak(interned_foo_1.Get()));
+    Handle<mirror::String> interned_foo_2(hs.NewHandle(t.InternStrong(3, "foo")));
+    EXPECT_FALSE(t.ContainsWeak(interned_foo_2.Get()));
+    EXPECT_EQ(interned_foo_1.Get(), interned_foo_2.Get());
   }
 
   {
     // Interning a weak after a strong gets you the strong.
     InternTable t;
-    SirtRef<mirror::String> interned_foo_1(soa.Self(), t.InternStrong(3, "foo"));
-    EXPECT_FALSE(t.ContainsWeak(interned_foo_1.get()));
-    SirtRef<mirror::String> foo(soa.Self(),
-                                mirror::String::AllocFromModifiedUtf8(soa.Self(), "foo"));
-    SirtRef<mirror::String> interned_foo_2(soa.Self(), t.InternWeak(foo.get()));
-    EXPECT_FALSE(t.ContainsWeak(interned_foo_2.get()));
-    EXPECT_EQ(interned_foo_1.get(), interned_foo_2.get());
+    StackHandleScope<3> hs(soa.Self());
+    Handle<mirror::String> interned_foo_1(hs.NewHandle(t.InternStrong(3, "foo")));
+    EXPECT_FALSE(t.ContainsWeak(interned_foo_1.Get()));
+    Handle<mirror::String> foo(
+        hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "foo")));
+    Handle<mirror::String> interned_foo_2(hs.NewHandle(t.InternWeak(foo.Get())));
+    EXPECT_FALSE(t.ContainsWeak(interned_foo_2.Get()));
+    EXPECT_EQ(interned_foo_1.Get(), interned_foo_2.Get());
   }
 }
 
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index a87f95c..20e2b8d 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -71,10 +71,10 @@
   } else if (name == "int java.lang.String.fastIndexOf(int, int)") {
     result->SetI(receiver->AsString()->FastIndexOf(args[0], args[1]));
   } else if (name == "java.lang.Object java.lang.reflect.Array.createMultiArray(java.lang.Class, int[])") {
-    SirtRef<mirror::Class> sirt_class(self, reinterpret_cast<Object*>(args[0])->AsClass());
-    SirtRef<mirror::IntArray> sirt_dimensions(self,
-                                              reinterpret_cast<Object*>(args[1])->AsIntArray());
-    result->SetL(Array::CreateMultiArray(self, sirt_class, sirt_dimensions));
+    StackHandleScope<2> hs(self);
+    auto h_class(hs.NewHandle(reinterpret_cast<mirror::Class*>(args[0])->AsClass()));
+    auto h_dimensions(hs.NewHandle(reinterpret_cast<mirror::IntArray*>(args[1])->AsIntArray()));
+    result->SetL(Array::CreateMultiArray(self, h_class, h_dimensions));
   } else if (name == "java.lang.Object java.lang.Throwable.nativeFillInStackTrace()") {
     ScopedObjectAccessUnchecked soa(self);
     if (Runtime::Current()->IsActiveTransaction()) {
@@ -455,8 +455,9 @@
   // Do this after populating the shadow frame in case EnsureInitialized causes a GC.
   if (method->IsStatic() && UNLIKELY(!method->GetDeclaringClass()->IsInitializing())) {
     ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-    SirtRef<mirror::Class> sirt_c(self, method->GetDeclaringClass());
-    if (UNLIKELY(!class_linker->EnsureInitialized(sirt_c, true, true))) {
+    StackHandleScope<1> hs(self);
+    Handle<mirror::Class> h_class(hs.NewHandle(method->GetDeclaringClass()));
+    if (UNLIKELY(!class_linker->EnsureInitialized(h_class, true, true))) {
       CHECK(self->IsExceptionPending());
       self->PopShadowFrame();
       return;
@@ -522,7 +523,8 @@
   ArtMethod* method = shadow_frame->GetMethod();
   // Ensure static methods are initialized.
   if (method->IsStatic()) {
-    SirtRef<Class> declaringClass(self, method->GetDeclaringClass());
+    StackHandleScope<1> hs(self);
+    Handle<Class> declaringClass(hs.NewHandle(method->GetDeclaringClass()));
     if (UNLIKELY(!declaringClass->IsInitializing())) {
       if (UNLIKELY(!Runtime::Current()->GetClassLinker()->EnsureInitialized(declaringClass, true,
                                                                             true))) {
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index ee6a869..c5fb0d8 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -296,7 +296,9 @@
     // other variants that take more arguments should also be added.
     std::string descriptor(DotToDescriptor(shadow_frame->GetVRegReference(arg_offset)->AsString()->ToModifiedUtf8().c_str()));
 
-    SirtRef<ClassLoader> class_loader(self, nullptr);  // shadow_frame.GetMethod()->GetDeclaringClass()->GetClassLoader();
+    StackHandleScope<1> hs(self);
+    // shadow_frame.GetMethod()->GetDeclaringClass()->GetClassLoader();
+    auto class_loader = hs.NewHandle<ClassLoader>(nullptr);
     Class* found = Runtime::Current()->GetClassLinker()->FindClass(self, descriptor.c_str(),
                                                                    class_loader);
     CHECK(found != NULL) << "Class.forName failed in un-started runtime for class: "
@@ -305,7 +307,9 @@
   } else if (name == "java.lang.Class java.lang.Void.lookupType()") {
     result->SetL(Runtime::Current()->GetClassLinker()->FindPrimitiveClass('V'));
   } else if (name == "java.lang.Class java.lang.VMClassLoader.findLoadedClass(java.lang.ClassLoader, java.lang.String)") {
-    SirtRef<ClassLoader> class_loader(self, down_cast<mirror::ClassLoader*>(shadow_frame->GetVRegReference(arg_offset)));
+    StackHandleScope<1> hs(self);
+    Handle<ClassLoader> class_loader(
+        hs.NewHandle(down_cast<mirror::ClassLoader*>(shadow_frame->GetVRegReference(arg_offset))));
     std::string descriptor(DotToDescriptor(shadow_frame->GetVRegReference(arg_offset + 1)->AsString()->ToModifiedUtf8().c_str()));
 
     Class* found = Runtime::Current()->GetClassLinker()->FindClass(self, descriptor.c_str(),
@@ -315,10 +319,11 @@
     Class* klass = shadow_frame->GetVRegReference(arg_offset)->AsClass();
     ArtMethod* c = klass->FindDeclaredDirectMethod("<init>", "()V");
     CHECK(c != NULL);
-    SirtRef<Object> obj(self, klass->AllocObject(self));
-    CHECK(obj.get() != NULL);
-    EnterInterpreterFromInvoke(self, c, obj.get(), NULL, NULL);
-    result->SetL(obj.get());
+    StackHandleScope<1> hs(self);
+    Handle<Object> obj(hs.NewHandle(klass->AllocObject(self)));
+    CHECK(obj.Get() != NULL);
+    EnterInterpreterFromInvoke(self, c, obj.Get(), NULL, NULL);
+    result->SetL(obj.Get());
   } else if (name == "java.lang.reflect.Field java.lang.Class.getDeclaredField(java.lang.String)") {
     // Special managed code cut-out to allow field lookup in a un-started runtime that'd fail
     // going the reflective Dex way.
@@ -350,13 +355,14 @@
     // TODO: getDeclaredField calls GetType once the field is found to ensure a
     //       NoClassDefFoundError is thrown if the field's type cannot be resolved.
     Class* jlr_Field = self->DecodeJObject(WellKnownClasses::java_lang_reflect_Field)->AsClass();
-    SirtRef<Object> field(self, jlr_Field->AllocNonMovableObject(self));
-    CHECK(field.get() != NULL);
+    StackHandleScope<1> hs(self);
+    Handle<Object> field(hs.NewHandle(jlr_Field->AllocNonMovableObject(self)));
+    CHECK(field.Get() != NULL);
     ArtMethod* c = jlr_Field->FindDeclaredDirectMethod("<init>", "(Ljava/lang/reflect/ArtField;)V");
     uint32_t args[1];
     args[0] = StackReference<mirror::Object>::FromMirrorPtr(found).AsVRegValue();
-    EnterInterpreterFromInvoke(self, c, field.get(), args, NULL);
-    result->SetL(field.get());
+    EnterInterpreterFromInvoke(self, c, field.Get(), args, NULL);
+    result->SetL(field.Get());
   } else if (name == "int java.lang.Object.hashCode()") {
     Object* obj = shadow_frame->GetVRegReference(arg_offset);
     result->SetI(obj->IdentityHashCode());
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index 819b79d..9b03334 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -410,8 +410,9 @@
   Class* java_lang_string_class = String::GetJavaLangString();
   if (UNLIKELY(!java_lang_string_class->IsInitialized())) {
     ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-    SirtRef<mirror::Class> sirt_class(self, java_lang_string_class);
-    if (UNLIKELY(!class_linker->EnsureInitialized(sirt_class, true, true))) {
+    StackHandleScope<1> hs(self);
+    Handle<mirror::Class> h_class(hs.NewHandle(java_lang_string_class));
+    if (UNLIKELY(!class_linker->EnsureInitialized(h_class, true, true))) {
       DCHECK(self->IsExceptionPending());
       return nullptr;
     }
@@ -571,9 +572,16 @@
   ThrowLocation throw_location;
   mirror::Throwable* exception = self->GetException(&throw_location);
   bool clear_exception = false;
-  SirtRef<mirror::Class> exception_class(self, exception->GetClass());
+  bool new_exception = false;
+  StackHandleScope<3> hs(self);
+  Handle<mirror::Class> exception_class(hs.NewHandle(exception->GetClass()));
   uint32_t found_dex_pc = shadow_frame.GetMethod()->FindCatchBlock(exception_class, dex_pc,
-                                                                   &clear_exception);
+                                                                   &clear_exception,
+                                                                   &new_exception);
+  if (UNLIKELY(new_exception)) {
+    // Update the exception.
+    exception = self->GetException(&throw_location);
+  }
   if (found_dex_pc == DexFile::kDexNoIndex) {
     instrumentation->MethodUnwindEvent(self, this_object,
                                        shadow_frame.GetMethod(), dex_pc);
diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc
index 915f2c9..21dab8d 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -117,11 +117,12 @@
   if (LIKELY(klass->IsInitialized())) {
     return klass;
   }
-  SirtRef<mirror::Class> sirt_klass(self, klass);
-  if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(sirt_klass, true, true)) {
+  StackHandleScope<1> hs(self);
+  Handle<mirror::Class> h_klass(hs.NewHandle(klass));
+  if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(h_klass, true, true)) {
     return nullptr;
   }
-  return sirt_klass.get();
+  return h_klass.Get();
 }
 
 static jmethodID FindMethodID(ScopedObjectAccess& soa, jclass jni_class,
@@ -180,16 +181,17 @@
 static jfieldID FindFieldID(const ScopedObjectAccess& soa, jclass jni_class, const char* name,
                             const char* sig, bool is_static)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  SirtRef<mirror::Class> c(soa.Self(), EnsureInitialized(soa.Self(),
-                                                         soa.Decode<mirror::Class*>(jni_class)));
-  if (c.get() == nullptr) {
+  StackHandleScope<2> hs(soa.Self());
+  Handle<mirror::Class> c(
+      hs.NewHandle(EnsureInitialized(soa.Self(), soa.Decode<mirror::Class*>(jni_class))));
+  if (c.Get() == nullptr) {
     return nullptr;
   }
   mirror::ArtField* field = nullptr;
   mirror::Class* field_type;
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   if (sig[1] != '\0') {
-    SirtRef<mirror::ClassLoader> class_loader(soa.Self(), c->GetClassLoader());
+    Handle<mirror::ClassLoader> class_loader(hs.NewHandle(c->GetClassLoader()));
     field_type = class_linker->FindClass(soa.Self(), sig, class_loader);
   } else {
     field_type = class_linker->FindPrimitiveClass(*sig);
@@ -198,13 +200,14 @@
     // Failed to find type from the signature of the field.
     DCHECK(soa.Self()->IsExceptionPending());
     ThrowLocation throw_location;
-    SirtRef<mirror::Throwable> cause(soa.Self(), soa.Self()->GetException(&throw_location));
+    StackHandleScope<1> hs(soa.Self());
+    Handle<mirror::Throwable> cause(hs.NewHandle(soa.Self()->GetException(&throw_location)));
     soa.Self()->ClearException();
     soa.Self()->ThrowNewExceptionF(throw_location, "Ljava/lang/NoSuchFieldError;",
                                    "no type \"%s\" found and so no field \"%s\" "
                                    "could be found in class \"%s\" or its superclasses", sig, name,
-                                   ClassHelper(c.get()).GetDescriptor());
-    soa.Self()->GetException(nullptr)->SetCause(cause.get());
+                                   ClassHelper(c.Get()).GetDescriptor());
+    soa.Self()->GetException(nullptr)->SetCause(cause.Get());
     return nullptr;
   }
   if (is_static) {
@@ -216,7 +219,7 @@
     ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow();
     soa.Self()->ThrowNewExceptionF(throw_location, "Ljava/lang/NoSuchFieldError;",
                                    "no \"%s\" field \"%s\" in class \"%s\" or its superclasses",
-                                   sig, name, ClassHelper(c.get()).GetDescriptor());
+                                   sig, name, ClassHelper(c.Get()).GetDescriptor());
     return nullptr;
   }
   return soa.EncodeField(field);
@@ -515,16 +518,28 @@
   SafeMap<std::string, SharedLibrary*> libraries_;
 };
 
-#define CHECK_NON_NULL_ARGUMENT(value) CHECK_NON_NULL_ARGUMENT_FN_NAME(__FUNCTION__, value)
+#define CHECK_NON_NULL_ARGUMENT(value) \
+    CHECK_NON_NULL_ARGUMENT_FN_NAME(__FUNCTION__, value, nullptr)
 
-#define CHECK_NON_NULL_ARGUMENT_FN_NAME(name, value) \
+#define CHECK_NON_NULL_ARGUMENT_RETURN_VOID(value) \
+    CHECK_NON_NULL_ARGUMENT_FN_NAME(__FUNCTION__, value, )
+
+#define CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(value) \
+    CHECK_NON_NULL_ARGUMENT_FN_NAME(__FUNCTION__, value, 0)
+
+#define CHECK_NON_NULL_ARGUMENT_RETURN(value, return_val) \
+    CHECK_NON_NULL_ARGUMENT_FN_NAME(__FUNCTION__, value, return_val)
+
+#define CHECK_NON_NULL_ARGUMENT_FN_NAME(name, value, return_val) \
   if (UNLIKELY(value == nullptr)) { \
     JniAbortF(name, #value " == null"); \
+    return return_val; \
   }
 
 #define CHECK_NON_NULL_MEMCPY_ARGUMENT(length, value) \
   if (UNLIKELY(length != 0 && value == nullptr)) { \
     JniAbortF(__FUNCTION__, #value " == null"); \
+    return; \
   }
 
 class JNI {
@@ -546,7 +561,8 @@
     ScopedObjectAccess soa(env);
     mirror::Class* c = nullptr;
     if (runtime->IsStarted()) {
-      SirtRef<mirror::ClassLoader> class_loader(soa.Self(), GetClassLoader(soa));
+      StackHandleScope<1> hs(soa.Self());
+      Handle<mirror::ClassLoader> class_loader(hs.NewHandle(GetClassLoader(soa)));
       c = class_linker->FindClass(soa.Self(), descriptor.c_str(), class_loader);
     } else {
       c = class_linker->FindSystemClass(soa.Self(), descriptor.c_str());
@@ -610,8 +626,8 @@
   }
 
   static jboolean IsAssignableFrom(JNIEnv* env, jclass java_class1, jclass java_class2) {
-    CHECK_NON_NULL_ARGUMENT(java_class1);
-    CHECK_NON_NULL_ARGUMENT(java_class2);
+    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);
@@ -619,7 +635,7 @@
   }
 
   static jboolean IsInstanceOf(JNIEnv* env, jobject jobj, jclass java_class) {
-    CHECK_NON_NULL_ARGUMENT(java_class);
+    CHECK_NON_NULL_ARGUMENT_RETURN(java_class, JNI_FALSE);
     if (jobj == nullptr) {
       // Note: JNI is different from regular Java instanceof in this respect
       return JNI_TRUE;
@@ -643,7 +659,7 @@
   }
 
   static jint ThrowNew(JNIEnv* env, jclass c, const char* msg) {
-    CHECK_NON_NULL_ARGUMENT(c);
+    CHECK_NON_NULL_ARGUMENT_RETURN(c, JNI_ERR);
     return ThrowNewException(env, c, msg, nullptr);
   }
 
@@ -658,26 +674,28 @@
   static void ExceptionDescribe(JNIEnv* env) {
     ScopedObjectAccess soa(env);
 
-    SirtRef<mirror::Object> old_throw_this_object(soa.Self(), nullptr);
-    SirtRef<mirror::ArtMethod> old_throw_method(soa.Self(), nullptr);
-    SirtRef<mirror::Throwable> old_exception(soa.Self(), nullptr);
+    StackHandleScope<3> hs(soa.Self());
+    // TODO: Use nullptr instead of null handles?
+    auto old_throw_this_object(hs.NewHandle<mirror::Object>(nullptr));
+    auto old_throw_method(hs.NewHandle<mirror::ArtMethod>(nullptr));
+    auto old_exception(hs.NewHandle<mirror::Throwable>(nullptr));
     uint32_t old_throw_dex_pc;
     {
       ThrowLocation old_throw_location;
       mirror::Throwable* old_exception_obj = soa.Self()->GetException(&old_throw_location);
-      old_throw_this_object.reset(old_throw_location.GetThis());
-      old_throw_method.reset(old_throw_location.GetMethod());
-      old_exception.reset(old_exception_obj);
+      old_throw_this_object.Assign(old_throw_location.GetThis());
+      old_throw_method.Assign(old_throw_location.GetMethod());
+      old_exception.Assign(old_exception_obj);
       old_throw_dex_pc = old_throw_location.GetDexPc();
       soa.Self()->ClearException();
     }
     ScopedLocalRef<jthrowable> exception(env,
-                                         soa.AddLocalReference<jthrowable>(old_exception.get()));
+                                         soa.AddLocalReference<jthrowable>(old_exception.Get()));
     ScopedLocalRef<jclass> exception_class(env, env->GetObjectClass(exception.get()));
     jmethodID mid = env->GetMethodID(exception_class.get(), "printStackTrace", "()V");
     if (mid == nullptr) {
       LOG(WARNING) << "JNI WARNING: no printStackTrace()V in "
-                   << PrettyTypeOf(old_exception.get());
+                   << PrettyTypeOf(old_exception.Get());
     } else {
       env->CallVoidMethod(exception.get(), mid);
       if (soa.Self()->IsExceptionPending()) {
@@ -686,10 +704,10 @@
         soa.Self()->ClearException();
       }
     }
-    ThrowLocation gc_safe_throw_location(old_throw_this_object.get(), old_throw_method.get(),
+    ThrowLocation gc_safe_throw_location(old_throw_this_object.Get(), old_throw_method.Get(),
                                          old_throw_dex_pc);
 
-    soa.Self()->SetException(gc_safe_throw_location, old_exception.get());
+    soa.Self()->SetException(gc_safe_throw_location, old_exception.Get());
   }
 
   static jthrowable ExceptionOccurred(JNIEnv* env) {
@@ -908,8 +926,8 @@
   static jboolean CallBooleanMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -917,15 +935,15 @@
   }
 
   static jboolean CallBooleanMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args).GetZ();
   }
 
   static jboolean CallBooleanMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid,
                                                args).GetZ();
@@ -934,8 +952,8 @@
   static jbyte CallByteMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -943,15 +961,15 @@
   }
 
   static jbyte CallByteMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args).GetB();
   }
 
   static jbyte CallByteMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid,
                                                args).GetB();
@@ -960,8 +978,8 @@
   static jchar CallCharMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -969,15 +987,15 @@
   }
 
   static jchar CallCharMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args).GetC();
   }
 
   static jchar CallCharMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid,
                                                args).GetC();
@@ -986,8 +1004,8 @@
   static jdouble CallDoubleMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -995,15 +1013,15 @@
   }
 
   static jdouble CallDoubleMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args).GetD();
   }
 
   static jdouble CallDoubleMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid,
                                                args).GetD();
@@ -1012,8 +1030,8 @@
   static jfloat CallFloatMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -1021,15 +1039,15 @@
   }
 
   static jfloat CallFloatMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args).GetF();
   }
 
   static jfloat CallFloatMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid,
                                                args).GetF();
@@ -1038,8 +1056,8 @@
   static jint CallIntMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -1047,15 +1065,15 @@
   }
 
   static jint CallIntMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args).GetI();
   }
 
   static jint CallIntMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid,
                                                args).GetI();
@@ -1064,8 +1082,8 @@
   static jlong CallLongMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -1073,15 +1091,15 @@
   }
 
   static jlong CallLongMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args).GetJ();
   }
 
   static jlong CallLongMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid,
                                                args).GetJ();
@@ -1090,8 +1108,8 @@
   static jshort CallShortMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -1099,15 +1117,15 @@
   }
 
   static jshort CallShortMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args).GetS();
   }
 
   static jshort CallShortMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid,
                                                args).GetS();
@@ -1116,23 +1134,23 @@
   static void CallVoidMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(mid);
     ScopedObjectAccess soa(env);
     InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, ap);
     va_end(ap);
   }
 
   static void CallVoidMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(mid);
     ScopedObjectAccess soa(env);
     InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args);
   }
 
   static void CallVoidMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(mid);
     ScopedObjectAccess soa(env);
     InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args);
   }
@@ -1171,8 +1189,8 @@
                                               ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -1181,16 +1199,16 @@
 
   static jboolean CallNonvirtualBooleanMethodV(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                                va_list args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, obj, mid, args).GetZ();
   }
 
   static jboolean CallNonvirtualBooleanMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                                jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args).GetZ();
   }
@@ -1198,8 +1216,8 @@
   static jbyte CallNonvirtualByteMethod(JNIEnv* env, jobject obj, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -1208,16 +1226,16 @@
 
   static jbyte CallNonvirtualByteMethodV(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                          va_list args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, obj, mid, args).GetB();
   }
 
   static jbyte CallNonvirtualByteMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                          jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args).GetB();
   }
@@ -1225,8 +1243,8 @@
   static jchar CallNonvirtualCharMethod(JNIEnv* env, jobject obj, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -1235,16 +1253,16 @@
 
   static jchar CallNonvirtualCharMethodV(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                          va_list args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, obj, mid, args).GetC();
   }
 
   static jchar CallNonvirtualCharMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                          jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args).GetC();
   }
@@ -1252,8 +1270,8 @@
   static jshort CallNonvirtualShortMethod(JNIEnv* env, jobject obj, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -1262,16 +1280,16 @@
 
   static jshort CallNonvirtualShortMethodV(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                            va_list args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, obj, mid, args).GetS();
   }
 
   static jshort CallNonvirtualShortMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                            jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args).GetS();
   }
@@ -1279,8 +1297,8 @@
   static jint CallNonvirtualIntMethod(JNIEnv* env, jobject obj, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -1289,16 +1307,16 @@
 
   static jint CallNonvirtualIntMethodV(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                        va_list args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, obj, mid, args).GetI();
   }
 
   static jint CallNonvirtualIntMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                        jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args).GetI();
   }
@@ -1306,8 +1324,8 @@
   static jlong CallNonvirtualLongMethod(JNIEnv* env, jobject obj, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -1316,16 +1334,16 @@
 
   static jlong CallNonvirtualLongMethodV(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                          va_list args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, obj, mid, args).GetJ();
   }
 
   static jlong CallNonvirtualLongMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                          jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args).GetJ();
   }
@@ -1333,8 +1351,8 @@
   static jfloat CallNonvirtualFloatMethod(JNIEnv* env, jobject obj, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -1343,16 +1361,16 @@
 
   static jfloat CallNonvirtualFloatMethodV(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                            va_list args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, obj, mid, args).GetF();
   }
 
   static jfloat CallNonvirtualFloatMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                            jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args).GetF();
   }
@@ -1360,8 +1378,8 @@
   static jdouble CallNonvirtualDoubleMethod(JNIEnv* env, jobject obj, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -1370,16 +1388,16 @@
 
   static jdouble CallNonvirtualDoubleMethodV(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                              va_list args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, obj, mid, args).GetD();
   }
 
   static jdouble CallNonvirtualDoubleMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                              jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args).GetD();
   }
@@ -1387,8 +1405,8 @@
   static void CallNonvirtualVoidMethod(JNIEnv* env, jobject obj, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(mid);
     ScopedObjectAccess soa(env);
     InvokeWithVarArgs(soa, obj, mid, ap);
     va_end(ap);
@@ -1396,16 +1414,16 @@
 
   static void CallNonvirtualVoidMethodV(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                         va_list args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(mid);
     ScopedObjectAccess soa(env);
     InvokeWithVarArgs(soa, obj, mid, args);
   }
 
   static void CallNonvirtualVoidMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                         jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(mid);
     ScopedObjectAccess soa(env);
     InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args);
   }
@@ -1444,8 +1462,8 @@
   }
 
   static void SetObjectField(JNIEnv* env, jobject java_object, jfieldID fid, jobject java_value) {
-    CHECK_NON_NULL_ARGUMENT(java_object);
-    CHECK_NON_NULL_ARGUMENT(fid);
+    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);
@@ -1454,7 +1472,7 @@
   }
 
   static void SetStaticObjectField(JNIEnv* env, jclass, jfieldID fid, jobject java_value) {
-    CHECK_NON_NULL_ARGUMENT(fid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(fid);
     ScopedObjectAccess soa(env);
     mirror::Object* v = soa.Decode<mirror::Object*>(java_value);
     mirror::ArtField* f = soa.DecodeField(fid);
@@ -1462,29 +1480,29 @@
   }
 
 #define GET_PRIMITIVE_FIELD(fn, instance) \
-  CHECK_NON_NULL_ARGUMENT(instance); \
-  CHECK_NON_NULL_ARGUMENT(fid); \
+  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); \
   mirror::ArtField* f = soa.DecodeField(fid); \
   return f->Get ##fn (o)
 
 #define GET_STATIC_PRIMITIVE_FIELD(fn) \
-  CHECK_NON_NULL_ARGUMENT(fid); \
+  CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(fid); \
   ScopedObjectAccess soa(env); \
   mirror::ArtField* f = soa.DecodeField(fid); \
   return f->Get ##fn (f->GetDeclaringClass())
 
 #define SET_PRIMITIVE_FIELD(fn, instance, value) \
-  CHECK_NON_NULL_ARGUMENT(instance); \
-  CHECK_NON_NULL_ARGUMENT(fid); \
+  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); \
   mirror::ArtField* f = soa.DecodeField(fid); \
   f->Set ##fn <false>(o, value)
 
 #define SET_STATIC_PRIMITIVE_FIELD(fn, value) \
-  CHECK_NON_NULL_ARGUMENT(fid); \
+  CHECK_NON_NULL_ARGUMENT_RETURN_VOID(fid); \
   ScopedObjectAccess soa(env); \
   mirror::ArtField* f = soa.DecodeField(fid); \
   f->Set ##fn <false>(f->GetDeclaringClass(), value)
@@ -1645,7 +1663,7 @@
   static jboolean CallStaticBooleanMethod(JNIEnv* env, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, nullptr, mid, ap));
     va_end(ap);
@@ -1653,13 +1671,13 @@
   }
 
   static jboolean CallStaticBooleanMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, nullptr, mid, args).GetZ();
   }
 
   static jboolean CallStaticBooleanMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, nullptr, mid, args).GetZ();
   }
@@ -1667,7 +1685,7 @@
   static jbyte CallStaticByteMethod(JNIEnv* env, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, nullptr, mid, ap));
     va_end(ap);
@@ -1675,13 +1693,13 @@
   }
 
   static jbyte CallStaticByteMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, nullptr, mid, args).GetB();
   }
 
   static jbyte CallStaticByteMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, nullptr, mid, args).GetB();
   }
@@ -1689,7 +1707,7 @@
   static jchar CallStaticCharMethod(JNIEnv* env, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, nullptr, mid, ap));
     va_end(ap);
@@ -1697,13 +1715,13 @@
   }
 
   static jchar CallStaticCharMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, nullptr, mid, args).GetC();
   }
 
   static jchar CallStaticCharMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, nullptr, mid, args).GetC();
   }
@@ -1711,7 +1729,7 @@
   static jshort CallStaticShortMethod(JNIEnv* env, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, nullptr, mid, ap));
     va_end(ap);
@@ -1719,13 +1737,13 @@
   }
 
   static jshort CallStaticShortMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, nullptr, mid, args).GetS();
   }
 
   static jshort CallStaticShortMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, nullptr, mid, args).GetS();
   }
@@ -1733,7 +1751,7 @@
   static jint CallStaticIntMethod(JNIEnv* env, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, nullptr, mid, ap));
     va_end(ap);
@@ -1741,13 +1759,13 @@
   }
 
   static jint CallStaticIntMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, nullptr, mid, args).GetI();
   }
 
   static jint CallStaticIntMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, nullptr, mid, args).GetI();
   }
@@ -1755,7 +1773,7 @@
   static jlong CallStaticLongMethod(JNIEnv* env, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, nullptr, mid, ap));
     va_end(ap);
@@ -1763,13 +1781,13 @@
   }
 
   static jlong CallStaticLongMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, nullptr, mid, args).GetJ();
   }
 
   static jlong CallStaticLongMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, nullptr, mid, args).GetJ();
   }
@@ -1777,7 +1795,7 @@
   static jfloat CallStaticFloatMethod(JNIEnv* env, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, nullptr, mid, ap));
     va_end(ap);
@@ -1785,13 +1803,13 @@
   }
 
   static jfloat CallStaticFloatMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, nullptr, mid, args).GetF();
   }
 
   static jfloat CallStaticFloatMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, nullptr, mid, args).GetF();
   }
@@ -1799,7 +1817,7 @@
   static jdouble CallStaticDoubleMethod(JNIEnv* env, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, nullptr, mid, ap));
     va_end(ap);
@@ -1807,13 +1825,13 @@
   }
 
   static jdouble CallStaticDoubleMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, nullptr, mid, args).GetD();
   }
 
   static jdouble CallStaticDoubleMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, nullptr, mid, args).GetD();
   }
@@ -1821,20 +1839,20 @@
   static void CallStaticVoidMethod(JNIEnv* env, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(mid);
     ScopedObjectAccess soa(env);
     InvokeWithVarArgs(soa, nullptr, mid, ap);
     va_end(ap);
   }
 
   static void CallStaticVoidMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(mid);
     ScopedObjectAccess soa(env);
     InvokeWithVarArgs(soa, nullptr, mid, args);
   }
 
   static void CallStaticVoidMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(mid);
     ScopedObjectAccess soa(env);
     InvokeWithJValues(soa, nullptr, mid, args);
   }
@@ -1863,20 +1881,20 @@
   }
 
   static jsize GetStringLength(JNIEnv* env, jstring java_string) {
-    CHECK_NON_NULL_ARGUMENT(java_string);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(java_string);
     ScopedObjectAccess soa(env);
     return soa.Decode<mirror::String*>(java_string)->GetLength();
   }
 
   static jsize GetStringUTFLength(JNIEnv* env, jstring java_string) {
-    CHECK_NON_NULL_ARGUMENT(java_string);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(java_string);
     ScopedObjectAccess soa(env);
     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(java_string);
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(java_string);
     ScopedObjectAccess soa(env);
     mirror::String* s = soa.Decode<mirror::String*>(java_string);
     if (start < 0 || length < 0 || start + length > s->GetLength()) {
@@ -1890,7 +1908,7 @@
 
   static void GetStringUTFRegion(JNIEnv* env, jstring java_string, jsize start, jsize length,
                                  char* buf) {
-    CHECK_NON_NULL_ARGUMENT(java_string);
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(java_string);
     ScopedObjectAccess soa(env);
     mirror::String* s = soa.Decode<mirror::String*>(java_string);
     if (start < 0 || length < 0 || start + length > s->GetLength()) {
@@ -1922,7 +1940,7 @@
   }
 
   static void ReleaseStringChars(JNIEnv* env, jstring java_string, const jchar* chars) {
-    CHECK_NON_NULL_ARGUMENT(java_string);
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(java_string);
     delete[] chars;
     ScopedObjectAccess soa(env);
     UnpinPrimitiveArray(soa, soa.Decode<mirror::String*>(java_string)->GetCharArray());
@@ -1959,7 +1977,7 @@
   }
 
   static jsize GetArrayLength(JNIEnv* env, jarray java_array) {
-    CHECK_NON_NULL_ARGUMENT(java_array);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(java_array);
     ScopedObjectAccess soa(env);
     mirror::Object* obj = soa.Decode<mirror::Object*>(java_array);
     if (UNLIKELY(!obj->IsArrayInstance())) {
@@ -1979,7 +1997,7 @@
 
   static void SetObjectArrayElement(JNIEnv* env, jobjectArray java_array, jsize index,
                                     jobject java_value) {
-    CHECK_NON_NULL_ARGUMENT(java_array);
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(java_array);
     ScopedObjectAccess soa(env);
     mirror::ObjectArray<mirror::Object>* array =
         soa.Decode<mirror::ObjectArray<mirror::Object>*>(java_array);
@@ -1988,38 +2006,31 @@
   }
 
   static jbooleanArray NewBooleanArray(JNIEnv* env, jsize length) {
-    ScopedObjectAccess soa(env);
-    return NewPrimitiveArray<jbooleanArray, mirror::BooleanArray>(soa, length);
+    return NewPrimitiveArray<jbooleanArray, mirror::BooleanArray>(env, length);
   }
 
   static jbyteArray NewByteArray(JNIEnv* env, jsize length) {
-    ScopedObjectAccess soa(env);
-    return NewPrimitiveArray<jbyteArray, mirror::ByteArray>(soa, length);
+    return NewPrimitiveArray<jbyteArray, mirror::ByteArray>(env, length);
   }
 
   static jcharArray NewCharArray(JNIEnv* env, jsize length) {
-    ScopedObjectAccess soa(env);
-    return NewPrimitiveArray<jcharArray, mirror::CharArray>(soa, length);
+    return NewPrimitiveArray<jcharArray, mirror::CharArray>(env, length);
   }
 
   static jdoubleArray NewDoubleArray(JNIEnv* env, jsize length) {
-    ScopedObjectAccess soa(env);
-    return NewPrimitiveArray<jdoubleArray, mirror::DoubleArray>(soa, length);
+    return NewPrimitiveArray<jdoubleArray, mirror::DoubleArray>(env, length);
   }
 
   static jfloatArray NewFloatArray(JNIEnv* env, jsize length) {
-    ScopedObjectAccess soa(env);
-    return NewPrimitiveArray<jfloatArray, mirror::FloatArray>(soa, length);
+    return NewPrimitiveArray<jfloatArray, mirror::FloatArray>(env, length);
   }
 
   static jintArray NewIntArray(JNIEnv* env, jsize length) {
-    ScopedObjectAccess soa(env);
-    return NewPrimitiveArray<jintArray, mirror::IntArray>(soa, length);
+    return NewPrimitiveArray<jintArray, mirror::IntArray>(env, length);
   }
 
   static jlongArray NewLongArray(JNIEnv* env, jsize length) {
-    ScopedObjectAccess soa(env);
-    return NewPrimitiveArray<jlongArray, mirror::LongArray>(soa, length);
+    return NewPrimitiveArray<jlongArray, mirror::LongArray>(env, length);
   }
 
   static jobjectArray NewObjectArray(JNIEnv* env, jsize length, jclass element_jclass,
@@ -2028,6 +2039,7 @@
       JniAbortF("NewObjectArray", "negative array length: %d", length);
       return nullptr;
     }
+    CHECK_NON_NULL_ARGUMENT(element_jclass);
 
     // Compute the array class corresponding to the given element class.
     ScopedObjectAccess soa(env);
@@ -2069,14 +2081,18 @@
   }
 
   static jshortArray NewShortArray(JNIEnv* env, jsize length) {
-    ScopedObjectAccess soa(env);
-    return NewPrimitiveArray<jshortArray, mirror::ShortArray>(soa, length);
+    return NewPrimitiveArray<jshortArray, mirror::ShortArray>(env, length);
   }
 
   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);
+    if (UNLIKELY(!array->GetClass()->IsPrimitiveArray())) {
+      JniAbortF("GetPrimitiveArrayCritical", "expected primitive array, given %s",
+                PrettyDescriptor(array->GetClass()).c_str());
+      return nullptr;
+    }
     gc::Heap* heap = Runtime::Current()->GetHeap();
     if (heap->IsMovableObject(array)) {
       heap->IncrementDisableMovingGC(soa.Self());
@@ -2090,196 +2106,174 @@
     return array->GetRawData(array->GetClass()->GetComponentSize(), 0);
   }
 
-  static void ReleasePrimitiveArrayCritical(JNIEnv* env, jarray array, void* elements, jint mode) {
-    CHECK_NON_NULL_ARGUMENT(array);
-    ReleasePrimitiveArray(env, array, elements, mode);
+  static void ReleasePrimitiveArrayCritical(JNIEnv* env, jarray java_array, void* elements,
+                                            jint mode) {
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(java_array);
+    ScopedObjectAccess soa(env);
+    mirror::Array* array = soa.Decode<mirror::Array*>(java_array);
+    if (UNLIKELY(!array->GetClass()->IsPrimitiveArray())) {
+      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);
   }
 
   static jboolean* GetBooleanArrayElements(JNIEnv* env, jbooleanArray array, jboolean* is_copy) {
-    CHECK_NON_NULL_ARGUMENT(array);
-    ScopedObjectAccess soa(env);
-    return GetPrimitiveArray<jbooleanArray, jboolean*, mirror::BooleanArray>(soa, array, is_copy);
+    return GetPrimitiveArray<jbooleanArray, jboolean, mirror::BooleanArray>(env, array, is_copy);
   }
 
   static jbyte* GetByteArrayElements(JNIEnv* env, jbyteArray array, jboolean* is_copy) {
-    CHECK_NON_NULL_ARGUMENT(array);
-    ScopedObjectAccess soa(env);
-    return GetPrimitiveArray<jbyteArray, jbyte*, mirror::ByteArray>(soa, array, is_copy);
+    return GetPrimitiveArray<jbyteArray, jbyte, mirror::ByteArray>(env, array, is_copy);
   }
 
   static jchar* GetCharArrayElements(JNIEnv* env, jcharArray array, jboolean* is_copy) {
-    CHECK_NON_NULL_ARGUMENT(array);
-    ScopedObjectAccess soa(env);
-    return GetPrimitiveArray<jcharArray, jchar*, mirror::CharArray>(soa, array, is_copy);
+    return GetPrimitiveArray<jcharArray, jchar, mirror::CharArray>(env, array, is_copy);
   }
 
   static jdouble* GetDoubleArrayElements(JNIEnv* env, jdoubleArray array, jboolean* is_copy) {
-    CHECK_NON_NULL_ARGUMENT(array);
-    ScopedObjectAccess soa(env);
-    return GetPrimitiveArray<jdoubleArray, jdouble*, mirror::DoubleArray>(soa, array, is_copy);
+    return GetPrimitiveArray<jdoubleArray, jdouble, mirror::DoubleArray>(env, array, is_copy);
   }
 
   static jfloat* GetFloatArrayElements(JNIEnv* env, jfloatArray array, jboolean* is_copy) {
-    CHECK_NON_NULL_ARGUMENT(array);
-    ScopedObjectAccess soa(env);
-    return GetPrimitiveArray<jfloatArray, jfloat*, mirror::FloatArray>(soa, array, is_copy);
+    return GetPrimitiveArray<jfloatArray, jfloat, mirror::FloatArray>(env, array, is_copy);
   }
 
   static jint* GetIntArrayElements(JNIEnv* env, jintArray array, jboolean* is_copy) {
-    CHECK_NON_NULL_ARGUMENT(array);
-    ScopedObjectAccess soa(env);
-    return GetPrimitiveArray<jintArray, jint*, mirror::IntArray>(soa, array, is_copy);
+    return GetPrimitiveArray<jintArray, jint, mirror::IntArray>(env, array, is_copy);
   }
 
   static jlong* GetLongArrayElements(JNIEnv* env, jlongArray array, jboolean* is_copy) {
-    CHECK_NON_NULL_ARGUMENT(array);
-    ScopedObjectAccess soa(env);
-    return GetPrimitiveArray<jlongArray, jlong*, mirror::LongArray>(soa, array, is_copy);
+    return GetPrimitiveArray<jlongArray, jlong, mirror::LongArray>(env, array, is_copy);
   }
 
   static jshort* GetShortArrayElements(JNIEnv* env, jshortArray array, jboolean* is_copy) {
-    CHECK_NON_NULL_ARGUMENT(array);
-    ScopedObjectAccess soa(env);
-    return GetPrimitiveArray<jshortArray, jshort*, mirror::ShortArray>(soa, array, is_copy);
+    return GetPrimitiveArray<jshortArray, jshort, mirror::ShortArray>(env, array, is_copy);
   }
 
   static void ReleaseBooleanArrayElements(JNIEnv* env, jbooleanArray array, jboolean* elements,
                                           jint mode) {
-    ReleasePrimitiveArray(env, array, elements, mode);
+    ReleasePrimitiveArray<jbooleanArray, jboolean, mirror::BooleanArray>(env, array, elements,
+                                                                         mode);
   }
 
   static void ReleaseByteArrayElements(JNIEnv* env, jbyteArray array, jbyte* elements, jint mode) {
-    ReleasePrimitiveArray(env, array, elements, mode);
+    ReleasePrimitiveArray<jbyteArray, jbyte, mirror::ByteArray>(env, array, elements, mode);
   }
 
   static void ReleaseCharArrayElements(JNIEnv* env, jcharArray array, jchar* elements, jint mode) {
-    ReleasePrimitiveArray(env, array, elements, mode);
+    ReleasePrimitiveArray<jcharArray, jchar, mirror::CharArray>(env, array, elements, mode);
   }
 
   static void ReleaseDoubleArrayElements(JNIEnv* env, jdoubleArray array, jdouble* elements,
                                          jint mode) {
-    ReleasePrimitiveArray(env, array, elements, mode);
+    ReleasePrimitiveArray<jdoubleArray, jdouble, mirror::DoubleArray>(env, array, elements, mode);
   }
 
   static void ReleaseFloatArrayElements(JNIEnv* env, jfloatArray array, jfloat* elements,
                                         jint mode) {
-    ReleasePrimitiveArray(env, array, elements, mode);
+    ReleasePrimitiveArray<jfloatArray, jfloat, mirror::FloatArray>(env, array, elements, mode);
   }
 
   static void ReleaseIntArrayElements(JNIEnv* env, jintArray array, jint* elements, jint mode) {
-    ReleasePrimitiveArray(env, array, elements, mode);
+    ReleasePrimitiveArray<jintArray, jint, mirror::IntArray>(env, array, elements, mode);
   }
 
   static void ReleaseLongArrayElements(JNIEnv* env, jlongArray array, jlong* elements, jint mode) {
-    ReleasePrimitiveArray(env, array, elements, mode);
+    ReleasePrimitiveArray<jlongArray, jlong, mirror::LongArray>(env, array, elements, mode);
   }
 
   static void ReleaseShortArrayElements(JNIEnv* env, jshortArray array, jshort* elements,
                                         jint mode) {
-    ReleasePrimitiveArray(env, array, elements, mode);
+    ReleasePrimitiveArray<jshortArray, jshort, mirror::ShortArray>(env, array, elements, mode);
   }
 
   static void GetBooleanArrayRegion(JNIEnv* env, jbooleanArray array, jsize start, jsize length,
                                     jboolean* buf) {
-    ScopedObjectAccess soa(env);
-    GetPrimitiveArrayRegion<jbooleanArray, jboolean, mirror::BooleanArray>(soa, array, start,
+    GetPrimitiveArrayRegion<jbooleanArray, jboolean, mirror::BooleanArray>(env, array, start,
                                                                            length, buf);
   }
 
   static void GetByteArrayRegion(JNIEnv* env, jbyteArray array, jsize start, jsize length,
                                  jbyte* buf) {
-    ScopedObjectAccess soa(env);
-    GetPrimitiveArrayRegion<jbyteArray, jbyte, mirror::ByteArray>(soa, array, start, length, buf);
+    GetPrimitiveArrayRegion<jbyteArray, jbyte, mirror::ByteArray>(env, array, start, length, buf);
   }
 
   static void GetCharArrayRegion(JNIEnv* env, jcharArray array, jsize start, jsize length,
                                  jchar* buf) {
-    ScopedObjectAccess soa(env);
-    GetPrimitiveArrayRegion<jcharArray, jchar, mirror::CharArray>(soa, array, start, length, buf);
+    GetPrimitiveArrayRegion<jcharArray, jchar, mirror::CharArray>(env, array, start, length, buf);
   }
 
   static void GetDoubleArrayRegion(JNIEnv* env, jdoubleArray array, jsize start, jsize length,
                                    jdouble* buf) {
-    ScopedObjectAccess soa(env);
-    GetPrimitiveArrayRegion<jdoubleArray, jdouble, mirror::DoubleArray>(soa, array, start, length,
+    GetPrimitiveArrayRegion<jdoubleArray, jdouble, mirror::DoubleArray>(env, array, start, length,
                                                                         buf);
   }
 
   static void GetFloatArrayRegion(JNIEnv* env, jfloatArray array, jsize start, jsize length,
                                   jfloat* buf) {
-    ScopedObjectAccess soa(env);
-    GetPrimitiveArrayRegion<jfloatArray, jfloat, mirror::FloatArray>(soa, array, start, length,
+    GetPrimitiveArrayRegion<jfloatArray, jfloat, mirror::FloatArray>(env, array, start, length,
                                                                      buf);
   }
 
   static void GetIntArrayRegion(JNIEnv* env, jintArray array, jsize start, jsize length,
                                 jint* buf) {
-    ScopedObjectAccess soa(env);
-    GetPrimitiveArrayRegion<jintArray, jint, mirror::IntArray>(soa, array, start, length, buf);
+    GetPrimitiveArrayRegion<jintArray, jint, mirror::IntArray>(env, array, start, length, buf);
   }
 
   static void GetLongArrayRegion(JNIEnv* env, jlongArray array, jsize start, jsize length,
                                  jlong* buf) {
-    ScopedObjectAccess soa(env);
-    GetPrimitiveArrayRegion<jlongArray, jlong, mirror::LongArray>(soa, array, start, length, buf);
+    GetPrimitiveArrayRegion<jlongArray, jlong, mirror::LongArray>(env, array, start, length, buf);
   }
 
   static void GetShortArrayRegion(JNIEnv* env, jshortArray array, jsize start, jsize length,
                                   jshort* buf) {
-    ScopedObjectAccess soa(env);
-    GetPrimitiveArrayRegion<jshortArray, jshort, mirror::ShortArray>(soa, array, start, length,
+    GetPrimitiveArrayRegion<jshortArray, jshort, mirror::ShortArray>(env, array, start, length,
                                                                      buf);
   }
 
   static void SetBooleanArrayRegion(JNIEnv* env, jbooleanArray array, jsize start, jsize length,
                                     const jboolean* buf) {
-    ScopedObjectAccess soa(env);
-    SetPrimitiveArrayRegion<jbooleanArray, jboolean, mirror::BooleanArray>(soa, array, start,
+    SetPrimitiveArrayRegion<jbooleanArray, jboolean, mirror::BooleanArray>(env, array, start,
                                                                            length, buf);
   }
 
   static void SetByteArrayRegion(JNIEnv* env, jbyteArray array, jsize start, jsize length,
                                  const jbyte* buf) {
-    ScopedObjectAccess soa(env);
-    SetPrimitiveArrayRegion<jbyteArray, jbyte, mirror::ByteArray>(soa, array, start, length, buf);
+    SetPrimitiveArrayRegion<jbyteArray, jbyte, mirror::ByteArray>(env, array, start, length, buf);
   }
 
   static void SetCharArrayRegion(JNIEnv* env, jcharArray array, jsize start, jsize length,
                                  const jchar* buf) {
-    ScopedObjectAccess soa(env);
-    SetPrimitiveArrayRegion<jcharArray, jchar, mirror::CharArray>(soa, array, start, length, buf);
+    SetPrimitiveArrayRegion<jcharArray, jchar, mirror::CharArray>(env, array, start, length, buf);
   }
 
   static void SetDoubleArrayRegion(JNIEnv* env, jdoubleArray array, jsize start, jsize length,
                                    const jdouble* buf) {
-    ScopedObjectAccess soa(env);
-    SetPrimitiveArrayRegion<jdoubleArray, jdouble, mirror::DoubleArray>(soa, array, start, length,
+    SetPrimitiveArrayRegion<jdoubleArray, jdouble, mirror::DoubleArray>(env, array, start, length,
                                                                         buf);
   }
 
   static void SetFloatArrayRegion(JNIEnv* env, jfloatArray array, jsize start, jsize length,
                                   const jfloat* buf) {
-    ScopedObjectAccess soa(env);
-    SetPrimitiveArrayRegion<jfloatArray, jfloat, mirror::FloatArray>(soa, array, start, length,
+    SetPrimitiveArrayRegion<jfloatArray, jfloat, mirror::FloatArray>(env, array, start, length,
                                                                      buf);
   }
 
   static void SetIntArrayRegion(JNIEnv* env, jintArray array, jsize start, jsize length,
                                 const jint* buf) {
-    ScopedObjectAccess soa(env);
-    SetPrimitiveArrayRegion<jintArray, jint, mirror::IntArray>(soa, array, start, length, buf);
+    SetPrimitiveArrayRegion<jintArray, jint, mirror::IntArray>(env, array, start, length, buf);
   }
 
   static void SetLongArrayRegion(JNIEnv* env, jlongArray array, jsize start, jsize length,
                                  const jlong* buf) {
-    ScopedObjectAccess soa(env);
-    SetPrimitiveArrayRegion<jlongArray, jlong, mirror::LongArray>(soa, array, start, length, buf);
+    SetPrimitiveArrayRegion<jlongArray, jlong, mirror::LongArray>(env, array, start, length, buf);
   }
 
   static void SetShortArrayRegion(JNIEnv* env, jshortArray array, jsize start, jsize length,
                                   const jshort* buf) {
-    ScopedObjectAccess soa(env);
-    SetPrimitiveArrayRegion<jshortArray, jshort, mirror::ShortArray>(soa, array, start, length,
+    SetPrimitiveArrayRegion<jshortArray, jshort, mirror::ShortArray>(env, array, start, length,
                                                                      buf);
   }
 
@@ -2294,7 +2288,7 @@
       JniAbortF("RegisterNatives", "negative method count: %d", method_count);
       return JNI_ERR;  // Not reached.
     }
-    CHECK_NON_NULL_ARGUMENT_FN_NAME("RegisterNatives", java_class);
+    CHECK_NON_NULL_ARGUMENT_FN_NAME("RegisterNatives", java_class, JNI_ERR);
     ScopedObjectAccess soa(env);
     mirror::Class* c = soa.Decode<mirror::Class*>(java_class);
     if (UNLIKELY(method_count == 0)) {
@@ -2302,7 +2296,7 @@
           << PrettyDescriptor(c);
       return JNI_OK;
     }
-    CHECK_NON_NULL_ARGUMENT_FN_NAME("RegisterNatives", methods);
+    CHECK_NON_NULL_ARGUMENT_FN_NAME("RegisterNatives", methods, JNI_ERR);
     for (jint i = 0; i < method_count; ++i) {
       const char* name = methods[i].name;
       const char* sig = methods[i].signature;
@@ -2339,30 +2333,37 @@
   }
 
   static jint UnregisterNatives(JNIEnv* env, jclass java_class) {
-    CHECK_NON_NULL_ARGUMENT(java_class);
+    CHECK_NON_NULL_ARGUMENT_RETURN(java_class, JNI_ERR);
     ScopedObjectAccess soa(env);
     mirror::Class* c = soa.Decode<mirror::Class*>(java_class);
 
     VLOG(jni) << "[Unregistering JNI native methods for " << PrettyClass(c) << "]";
 
+    size_t unregistered_count = 0;
     for (size_t i = 0; i < c->NumDirectMethods(); ++i) {
       mirror::ArtMethod* m = c->GetDirectMethod(i);
       if (m->IsNative()) {
         m->UnregisterNative(soa.Self());
+        unregistered_count++;
       }
     }
     for (size_t i = 0; i < c->NumVirtualMethods(); ++i) {
       mirror::ArtMethod* m = c->GetVirtualMethod(i);
       if (m->IsNative()) {
         m->UnregisterNative(soa.Self());
+        unregistered_count++;
       }
     }
 
+    if (unregistered_count == 0) {
+      LOG(WARNING) << "JNI UnregisterNatives: attempt to unregister native methods of class '"
+          << PrettyDescriptor(c) << "' that contains no native methods";
+    }
     return JNI_OK;
   }
 
   static jint MonitorEnter(JNIEnv* env, jobject java_object) NO_THREAD_SAFETY_ANALYSIS {
-    CHECK_NON_NULL_ARGUMENT(java_object);
+    CHECK_NON_NULL_ARGUMENT_RETURN(java_object, JNI_ERR);
     ScopedObjectAccess soa(env);
     mirror::Object* o = soa.Decode<mirror::Object*>(java_object);
     o = o->MonitorEnter(soa.Self());
@@ -2374,7 +2375,7 @@
   }
 
   static jint MonitorExit(JNIEnv* env, jobject java_object) NO_THREAD_SAFETY_ANALYSIS {
-    CHECK_NON_NULL_ARGUMENT(java_object);
+    CHECK_NON_NULL_ARGUMENT_RETURN(java_object, JNI_ERR);
     ScopedObjectAccess soa(env);
     mirror::Object* o = soa.Decode<mirror::Object*>(java_object);
     o->MonitorExit(soa.Self());
@@ -2386,7 +2387,7 @@
   }
 
   static jint GetJavaVM(JNIEnv* env, JavaVM** vm) {
-    CHECK_NON_NULL_ARGUMENT(vm);
+    CHECK_NON_NULL_ARGUMENT_RETURN(vm, JNI_ERR);
     Runtime* runtime = Runtime::Current();
     if (runtime != nullptr) {
       *vm = runtime->GetJavaVM();
@@ -2426,7 +2427,7 @@
   }
 
   static jobjectRefType GetObjectRefType(JNIEnv* env, jobject java_object) {
-    CHECK_NON_NULL_ARGUMENT(java_object);
+    CHECK_NON_NULL_ARGUMENT_RETURN(java_object, JNIInvalidRefType);
 
     // Do we definitely know what kind of reference this is?
     IndirectRef ref = reinterpret_cast<IndirectRef>(java_object);
@@ -2443,9 +2444,9 @@
       return JNIGlobalRefType;
     case kWeakGlobal:
       return JNIWeakGlobalRefType;
-    case kSirtOrInvalid:
+    case kHandleScopeOrInvalid:
       // Is it in a stack IRT?
-      if (static_cast<JNIEnvExt*>(env)->self->SirtContains(java_object)) {
+      if (static_cast<JNIEnvExt*>(env)->self->HandleScopeContains(java_object)) {
         return JNILocalRefType;
       }
       return JNIInvalidRefType;
@@ -2473,51 +2474,82 @@
   }
 
   template<typename JniT, typename ArtT>
-  static JniT NewPrimitiveArray(const ScopedObjectAccess& soa, jsize length)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  static JniT NewPrimitiveArray(JNIEnv* env, jsize length) {
     if (UNLIKELY(length < 0)) {
       JniAbortF("NewPrimitiveArray", "negative array length: %d", length);
       return nullptr;
     }
+    ScopedObjectAccess soa(env);
     ArtT* result = ArtT::Alloc(soa.Self(), length);
     return soa.AddLocalReference<JniT>(result);
   }
 
-  template <typename ArrayT, typename CArrayT, typename ArtArrayT>
-  static CArrayT GetPrimitiveArray(ScopedObjectAccess& soa, ArrayT java_array,
-                                   jboolean* is_copy)
+  template <typename JArrayT, typename ElementT, typename ArtArrayT>
+  static ArtArrayT* DecodeAndCheckArrayType(ScopedObjectAccess& soa, JArrayT java_array,
+                                           const char* fn_name, const char* operation)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     ArtArrayT* array = soa.Decode<ArtArrayT*>(java_array);
+    if (UNLIKELY(ArtArrayT::GetArrayClass() != array->GetClass())) {
+      JniAbortF(fn_name, "attempt to %s %s primitive array elements with an object of type %s",
+                operation, PrettyDescriptor(ArtArrayT::GetArrayClass()->GetComponentType()).c_str(),
+                PrettyDescriptor(array->GetClass()).c_str());
+      return nullptr;
+    }
+    DCHECK_EQ(sizeof(ElementT), array->GetClass()->GetComponentSize());
+    return array;
+  }
+
+  template <typename ArrayT, typename ElementT, typename ArtArrayT>
+  static ElementT* GetPrimitiveArray(JNIEnv* env, ArrayT java_array, jboolean* is_copy) {
+    CHECK_NON_NULL_ARGUMENT(java_array);
+    ScopedObjectAccess soa(env);
+    ArtArrayT* array = DecodeAndCheckArrayType<ArrayT, ElementT, ArtArrayT>(soa, java_array,
+                                                                            "GetArrayElements",
+                                                                            "get");
+    if (UNLIKELY(array == nullptr)) {
+      return nullptr;
+    }
     PinPrimitiveArray(soa, array);
     // Only make a copy if necessary.
     if (Runtime::Current()->GetHeap()->IsMovableObject(array)) {
       if (is_copy != nullptr) {
         *is_copy = JNI_TRUE;
       }
-      static const size_t component_size = array->GetClass()->GetComponentSize();
+      const size_t component_size = sizeof(ElementT);
       size_t size = array->GetLength() * component_size;
       void* data = new uint64_t[RoundUp(size, 8) / 8];
       memcpy(data, array->GetData(), size);
-      return reinterpret_cast<CArrayT>(data);
+      return reinterpret_cast<ElementT*>(data);
     } else {
       if (is_copy != nullptr) {
         *is_copy = JNI_FALSE;
       }
-      return reinterpret_cast<CArrayT>(array->GetData());
+      return reinterpret_cast<ElementT*>(array->GetData());
     }
   }
 
-  template <typename ArrayT, typename ElementT>
+  template <typename ArrayT, typename ElementT, typename ArtArrayT>
   static void ReleasePrimitiveArray(JNIEnv* env, ArrayT java_array, ElementT* elements, jint mode) {
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(java_array);
     ScopedObjectAccess soa(env);
-    mirror::Array* array = soa.Decode<mirror::Array*>(java_array);
-    size_t component_size = array->GetClass()->GetComponentSize();
+    ArtArrayT* array = DecodeAndCheckArrayType<ArrayT, ElementT, ArtArrayT>(soa, java_array,
+                                                                            "ReleaseArrayElements",
+                                                                            "release");
+    if (array == nullptr) {
+      return;
+    }
+    ReleasePrimitiveArray(soa, array, sizeof(ElementT), elements, mode);
+  }
+
+  static void ReleasePrimitiveArray(ScopedObjectAccess& soa, mirror::Array* array,
+                                    size_t component_size, void* elements, jint mode)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     void* array_data = array->GetRawData(component_size, 0);
     gc::Heap* heap = Runtime::Current()->GetHeap();
-    bool is_copy = array_data != reinterpret_cast<void*>(elements);
+    bool is_copy = array_data != elements;
     size_t bytes = array->GetLength() * component_size;
-    VLOG(heap) << "Release primitive array " << env << " array_data " << array_data
-               << " elements " << reinterpret_cast<void*>(elements);
+    VLOG(heap) << "Release primitive array " << soa.Env() << " array_data " << array_data
+               << " elements " << elements;
     if (is_copy) {
       // Sanity check: If elements is not the same as the java array's data, it better not be a
       // heap address. TODO: This might be slow to check, may be worth keeping track of which
@@ -2543,33 +2575,43 @@
     }
   }
 
-  template <typename JavaArrayT, typename JavaT, typename ArrayT>
-  static void GetPrimitiveArrayRegion(ScopedObjectAccess& soa, JavaArrayT java_array,
-                                      jsize start, jsize length, JavaT* buf)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    CHECK_NON_NULL_ARGUMENT(java_array);
-    ArrayT* array = soa.Decode<ArrayT*>(java_array);
-    if (start < 0 || length < 0 || start + length > array->GetLength()) {
-      ThrowAIOOBE(soa, array, start, length, "src");
-    } else {
-      CHECK_NON_NULL_MEMCPY_ARGUMENT(length, buf);
-      JavaT* data = array->GetData();
-      memcpy(buf, data + start, length * sizeof(JavaT));
+  template <typename JArrayT, typename ElementT, typename ArtArrayT>
+  static void GetPrimitiveArrayRegion(JNIEnv* env, JArrayT java_array,
+                                      jsize start, jsize length, ElementT* buf) {
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(java_array);
+    ScopedObjectAccess soa(env);
+    ArtArrayT* array =
+        DecodeAndCheckArrayType<JArrayT, ElementT, ArtArrayT>(soa, java_array,
+                                                              "GetPrimitiveArrayRegion",
+                                                              "get region of");
+    if (array != nullptr) {
+      if (start < 0 || length < 0 || start + length > array->GetLength()) {
+        ThrowAIOOBE(soa, array, start, length, "src");
+      } else {
+        CHECK_NON_NULL_MEMCPY_ARGUMENT(length, buf);
+        ElementT* data = array->GetData();
+        memcpy(buf, data + start, length * sizeof(ElementT));
+      }
     }
   }
 
-  template <typename JavaArrayT, typename JavaT, typename ArrayT>
-  static void SetPrimitiveArrayRegion(ScopedObjectAccess& soa, JavaArrayT java_array,
-                                      jsize start, jsize length, const JavaT* buf)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    CHECK_NON_NULL_ARGUMENT(java_array);
-    ArrayT* array = soa.Decode<ArrayT*>(java_array);
-    if (start < 0 || length < 0 || start + length > array->GetLength()) {
-      ThrowAIOOBE(soa, array, start, length, "dst");
-    } else {
-      CHECK_NON_NULL_MEMCPY_ARGUMENT(length, buf);
-      JavaT* data = array->GetData();
-      memcpy(data + start, buf, length * sizeof(JavaT));
+  template <typename JArrayT, typename ElementT, typename ArtArrayT>
+  static void SetPrimitiveArrayRegion(JNIEnv* env, JArrayT java_array,
+                                      jsize start, jsize length, const ElementT* buf) {
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(java_array);
+    ScopedObjectAccess soa(env);
+    ArtArrayT* array =
+        DecodeAndCheckArrayType<JArrayT, ElementT, ArtArrayT>(soa, java_array,
+                                                              "SetPrimitiveArrayRegion",
+                                                              "set region of");
+    if (array != nullptr) {
+      if (start < 0 || length < 0 || start + length > array->GetLength()) {
+        ThrowAIOOBE(soa, array, start, length, "dst");
+      } else {
+        CHECK_NON_NULL_MEMCPY_ARGUMENT(length, buf);
+        ElementT* data = array->GetData();
+        memcpy(data + start, buf, length * sizeof(ElementT));
+      }
     }
   }
 };
@@ -3090,7 +3132,7 @@
 }
 
 bool JavaVMExt::LoadNativeLibrary(const std::string& path,
-                                  const SirtRef<mirror::ClassLoader>& class_loader,
+                                  const Handle<mirror::ClassLoader>& class_loader,
                                   std::string* detail) {
   detail->clear();
 
@@ -3106,18 +3148,18 @@
     library = libraries->Get(path);
   }
   if (library != nullptr) {
-    if (library->GetClassLoader() != class_loader.get()) {
+    if (library->GetClassLoader() != class_loader.Get()) {
       // The library will be associated with class_loader. The JNI
       // spec says we can't load the same library into more than one
       // class loader.
       StringAppendF(detail, "Shared library \"%s\" already opened by "
           "ClassLoader %p; can't open in ClassLoader %p",
-          path.c_str(), library->GetClassLoader(), class_loader.get());
+          path.c_str(), library->GetClassLoader(), class_loader.Get());
       LOG(WARNING) << detail;
       return false;
     }
     VLOG(jni) << "[Shared library \"" << path << "\" already loaded in "
-              << "ClassLoader " << class_loader.get() << "]";
+              << "ClassLoader " << class_loader.Get() << "]";
     if (!library->CheckOnLoadResult()) {
       StringAppendF(detail, "JNI_OnLoad failed on a previous attempt "
           "to load \"%s\"", path.c_str());
@@ -3158,18 +3200,18 @@
     MutexLock mu(self, libraries_lock);
     library = libraries->Get(path);
     if (library == nullptr) {  // We won race to get libraries_lock
-      library = new SharedLibrary(path, handle, class_loader.get());
+      library = new SharedLibrary(path, handle, class_loader.Get());
       libraries->Put(path, library);
       created_library = true;
     }
   }
   if (!created_library) {
     LOG(INFO) << "WOW: we lost a race to add shared library: "
-        << "\"" << path << "\" ClassLoader=" << class_loader.get();
+        << "\"" << path << "\" ClassLoader=" << class_loader.Get();
     return library->CheckOnLoadResult();
   }
 
-  VLOG(jni) << "[Added shared library \"" << path << "\" for ClassLoader " << class_loader.get()
+  VLOG(jni) << "[Added shared library \"" << path << "\" for ClassLoader " << class_loader.Get()
       << "]";
 
   bool was_successful = false;
@@ -3184,8 +3226,9 @@
     // the comments in the JNI FindClass function.)
     typedef int (*JNI_OnLoadFn)(JavaVM*, void*);
     JNI_OnLoadFn jni_on_load = reinterpret_cast<JNI_OnLoadFn>(sym);
-    SirtRef<mirror::ClassLoader> old_class_loader(self, self->GetClassLoaderOverride());
-    self->SetClassLoaderOverride(class_loader.get());
+    StackHandleScope<1> hs(self);
+    Handle<mirror::ClassLoader> old_class_loader(hs.NewHandle(self->GetClassLoaderOverride()));
+    self->SetClassLoaderOverride(class_loader.Get());
 
     int version = 0;
     {
@@ -3194,7 +3237,7 @@
       version = (*jni_on_load)(this, nullptr);
     }
 
-    self->SetClassLoaderOverride(old_class_loader.get());
+    self->SetClassLoaderOverride(old_class_loader.Get());
 
     if (version == JNI_ERR) {
       StringAppendF(detail, "JNI_ERR returned from JNI_OnLoad in \"%s\"", path.c_str());
diff --git a/runtime/jni_internal.h b/runtime/jni_internal.h
index cdf3c47..5964947 100644
--- a/runtime/jni_internal.h
+++ b/runtime/jni_internal.h
@@ -46,7 +46,7 @@
 class Libraries;
 class ParsedOptions;
 class ScopedObjectAccess;
-template<class T> class SirtRef;
+template<class T> class Handle;
 class Thread;
 
 void JniAbortF(const char* jni_function_name, const char* fmt, ...)
@@ -67,7 +67,7 @@
    * Returns 'true' on success. On failure, sets 'detail' to a
    * human-readable description of the error.
    */
-  bool LoadNativeLibrary(const std::string& path, const SirtRef<mirror::ClassLoader>& class_loader,
+  bool LoadNativeLibrary(const std::string& path, const Handle<mirror::ClassLoader>& class_loader,
                          std::string* detail)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
diff --git a/runtime/jni_internal_test.cc b/runtime/jni_internal_test.cc
index 778b9e5..83e9b10 100644
--- a/runtime/jni_internal_test.cc
+++ b/runtime/jni_internal_test.cc
@@ -33,35 +33,54 @@
     // Turn on -verbose:jni for the JNI tests.
     // gLogVerbosity.jni = true;
 
-    vm_->AttachCurrentThread(&env_, NULL);
+    vm_->AttachCurrentThread(&env_, nullptr);
 
     ScopedLocalRef<jclass> aioobe(env_,
                                   env_->FindClass("java/lang/ArrayIndexOutOfBoundsException"));
-    CHECK(aioobe.get() != NULL);
+    CHECK(aioobe.get() != nullptr);
     aioobe_ = reinterpret_cast<jclass>(env_->NewGlobalRef(aioobe.get()));
 
     ScopedLocalRef<jclass> ase(env_, env_->FindClass("java/lang/ArrayStoreException"));
-    CHECK(ase.get() != NULL);
+    CHECK(ase.get() != nullptr);
     ase_ = reinterpret_cast<jclass>(env_->NewGlobalRef(ase.get()));
 
     ScopedLocalRef<jclass> sioobe(env_,
                                   env_->FindClass("java/lang/StringIndexOutOfBoundsException"));
-    CHECK(sioobe.get() != NULL);
+    CHECK(sioobe.get() != nullptr);
     sioobe_ = reinterpret_cast<jclass>(env_->NewGlobalRef(sioobe.get()));
   }
 
+  void ExpectException(jclass exception_class) {
+    EXPECT_TRUE(env_->ExceptionCheck());
+    jthrowable exception = env_->ExceptionOccurred();
+    EXPECT_NE(nullptr, exception);
+    env_->ExceptionClear();
+    EXPECT_TRUE(env_->IsInstanceOf(exception, exception_class));
+  }
+
+  void ExpectClassFound(const char* name) {
+    EXPECT_NE(env_->FindClass(name), nullptr) << name;
+    EXPECT_FALSE(env_->ExceptionCheck()) << name;
+  }
+
+  void ExpectClassNotFound(const char* name) {
+    EXPECT_EQ(env_->FindClass(name), nullptr) << name;
+    EXPECT_TRUE(env_->ExceptionCheck()) << name;
+    env_->ExceptionClear();
+  }
+
   void CleanUpJniEnv() {
-    if (aioobe_ != NULL) {
+    if (aioobe_ != nullptr) {
       env_->DeleteGlobalRef(aioobe_);
-      aioobe_ = NULL;
+      aioobe_ = nullptr;
     }
-    if (ase_ != NULL) {
+    if (ase_ != nullptr) {
       env_->DeleteGlobalRef(ase_);
-      ase_ = NULL;
+      ase_ = nullptr;
     }
-    if (sioobe_ != NULL) {
+    if (sioobe_ != nullptr) {
       env_->DeleteGlobalRef(sioobe_);
-      sioobe_ = NULL;
+      sioobe_ = nullptr;
     }
   }
 
@@ -86,9 +105,9 @@
 
 TEST_F(JniInternalTest, AllocObject) {
   jclass c = env_->FindClass("java/lang/String");
-  ASSERT_TRUE(c != NULL);
+  ASSERT_NE(c, nullptr);
   jobject o = env_->AllocObject(c);
-  ASSERT_TRUE(o != NULL);
+  ASSERT_NE(o, nullptr);
 
   // We have an instance of the class we asked for...
   ASSERT_TRUE(env_->IsInstanceOf(o, c));
@@ -96,139 +115,152 @@
   // we didn't call a constructor.
   ASSERT_EQ(0, env_->GetIntField(o, env_->GetFieldID(c, "count", "I")));
   ASSERT_EQ(0, env_->GetIntField(o, env_->GetFieldID(c, "offset", "I")));
-  ASSERT_TRUE(env_->GetObjectField(o, env_->GetFieldID(c, "value", "[C")) == NULL);
+  ASSERT_TRUE(env_->GetObjectField(o, env_->GetFieldID(c, "value", "[C")) == nullptr);
 }
 
 TEST_F(JniInternalTest, GetVersion) {
   ASSERT_EQ(JNI_VERSION_1_6, env_->GetVersion());
 }
 
-#define EXPECT_CLASS_FOUND(NAME) \
-  EXPECT_TRUE(env_->FindClass(NAME) != NULL); \
-  EXPECT_FALSE(env_->ExceptionCheck())
-
-#define EXPECT_CLASS_NOT_FOUND(NAME) \
-  EXPECT_TRUE(env_->FindClass(NAME) == NULL); \
-  EXPECT_TRUE(env_->ExceptionCheck()); \
-  env_->ExceptionClear()
-
 TEST_F(JniInternalTest, FindClass) {
   // Reference types...
-  EXPECT_CLASS_FOUND("java/lang/String");
+  ExpectClassFound("java/lang/String");
   // ...for arrays too, where you must include "L;".
-  EXPECT_CLASS_FOUND("[Ljava/lang/String;");
+  ExpectClassFound("[Ljava/lang/String;");
   // Primitive arrays are okay too, if the primitive type is valid.
-  EXPECT_CLASS_FOUND("[C");
+  ExpectClassFound("[C");
 
   {
-    // We support . as well as / for compatibility, if -Xcheck:jni is off.
     CheckJniAbortCatcher check_jni_abort_catcher;
-    EXPECT_CLASS_FOUND("java.lang.String");
+    env_->FindClass(nullptr);
+    check_jni_abort_catcher.Check("name == null");
+
+    // We support . as well as / for compatibility, if -Xcheck:jni is off.
+    ExpectClassFound("java.lang.String");
     check_jni_abort_catcher.Check("illegal class name 'java.lang.String'");
-    EXPECT_CLASS_NOT_FOUND("Ljava.lang.String;");
+    ExpectClassNotFound("Ljava.lang.String;");
     check_jni_abort_catcher.Check("illegal class name 'Ljava.lang.String;'");
-    EXPECT_CLASS_FOUND("[Ljava.lang.String;");
+    ExpectClassFound("[Ljava.lang.String;");
     check_jni_abort_catcher.Check("illegal class name '[Ljava.lang.String;'");
-    EXPECT_CLASS_NOT_FOUND("[java.lang.String");
+    ExpectClassNotFound("[java.lang.String");
     check_jni_abort_catcher.Check("illegal class name '[java.lang.String'");
 
     // You can't include the "L;" in a JNI class descriptor.
-    EXPECT_CLASS_NOT_FOUND("Ljava/lang/String;");
+    ExpectClassNotFound("Ljava/lang/String;");
     check_jni_abort_catcher.Check("illegal class name 'Ljava/lang/String;'");
 
     // But you must include it for an array of any reference type.
-    EXPECT_CLASS_NOT_FOUND("[java/lang/String");
+    ExpectClassNotFound("[java/lang/String");
     check_jni_abort_catcher.Check("illegal class name '[java/lang/String'");
 
-    EXPECT_CLASS_NOT_FOUND("[K");
+    ExpectClassNotFound("[K");
     check_jni_abort_catcher.Check("illegal class name '[K'");
+
+    // Void arrays aren't allowed.
+    ExpectClassNotFound("[V");
+    check_jni_abort_catcher.Check("illegal class name '[V'");
   }
 
   // But primitive types aren't allowed...
-  EXPECT_CLASS_NOT_FOUND("C");
-  EXPECT_CLASS_NOT_FOUND("K");
+  ExpectClassNotFound("C");
+  ExpectClassNotFound("V");
+  ExpectClassNotFound("K");
 }
 
-#define EXPECT_EXCEPTION(exception_class) \
-  do { \
-    EXPECT_TRUE(env_->ExceptionCheck()); \
-    jthrowable exception = env_->ExceptionOccurred(); \
-    EXPECT_NE(static_cast<jthrowable>(NULL), exception); \
-    env_->ExceptionClear(); \
-    EXPECT_TRUE(env_->IsInstanceOf(exception, exception_class)); \
-  } while (false)
-
 TEST_F(JniInternalTest, GetFieldID) {
   jclass jlnsfe = env_->FindClass("java/lang/NoSuchFieldError");
-  ASSERT_TRUE(jlnsfe != NULL);
+  ASSERT_NE(jlnsfe, nullptr);
   jclass c = env_->FindClass("java/lang/String");
-  ASSERT_TRUE(c != NULL);
+  ASSERT_NE(c, nullptr);
 
   // Wrong type.
   jfieldID fid = env_->GetFieldID(c, "count", "J");
-  EXPECT_EQ(static_cast<jfieldID>(NULL), fid);
-  EXPECT_EXCEPTION(jlnsfe);
+  EXPECT_EQ(nullptr, fid);
+  ExpectException(jlnsfe);
 
   // Wrong type where type doesn't exist.
   fid = env_->GetFieldID(c, "count", "Lrod/jane/freddy;");
-  EXPECT_EQ(static_cast<jfieldID>(NULL), fid);
-  EXPECT_EXCEPTION(jlnsfe);
+  EXPECT_EQ(nullptr, fid);
+  ExpectException(jlnsfe);
 
   // Wrong name.
   fid = env_->GetFieldID(c, "Count", "I");
-  EXPECT_EQ(static_cast<jfieldID>(NULL), fid);
-  EXPECT_EXCEPTION(jlnsfe);
+  EXPECT_EQ(nullptr, fid);
+  ExpectException(jlnsfe);
 
   // Good declared field lookup.
   fid = env_->GetFieldID(c, "count", "I");
-  EXPECT_NE(static_cast<jfieldID>(NULL), fid);
-  EXPECT_TRUE(fid != NULL);
+  EXPECT_NE(nullptr, fid);
   EXPECT_FALSE(env_->ExceptionCheck());
 
   // Good superclass field lookup.
   c = env_->FindClass("java/lang/StringBuilder");
   fid = env_->GetFieldID(c, "count", "I");
-  EXPECT_NE(static_cast<jfieldID>(NULL), fid);
-  EXPECT_TRUE(fid != NULL);
+  EXPECT_NE(nullptr, fid);
+  EXPECT_NE(fid, nullptr);
   EXPECT_FALSE(env_->ExceptionCheck());
 
   // Not instance.
   fid = env_->GetFieldID(c, "CASE_INSENSITIVE_ORDER", "Ljava/util/Comparator;");
-  EXPECT_EQ(static_cast<jfieldID>(NULL), fid);
-  EXPECT_EXCEPTION(jlnsfe);
+  EXPECT_EQ(nullptr, fid);
+  ExpectException(jlnsfe);
+
+  // Bad arguments.
+  CheckJniAbortCatcher check_jni_abort_catcher;
+  fid = env_->GetFieldID(nullptr, "count", "I");
+  EXPECT_EQ(nullptr, fid);
+  check_jni_abort_catcher.Check("java_class == null");
+  fid = env_->GetFieldID(c, nullptr, "I");
+  EXPECT_EQ(nullptr, fid);
+  check_jni_abort_catcher.Check("name == null");
+  fid = env_->GetFieldID(c, "count", nullptr);
+  EXPECT_EQ(nullptr, fid);
+  check_jni_abort_catcher.Check("sig == null");
 }
 
 TEST_F(JniInternalTest, GetStaticFieldID) {
   jclass jlnsfe = env_->FindClass("java/lang/NoSuchFieldError");
-  ASSERT_TRUE(jlnsfe != NULL);
+  ASSERT_NE(jlnsfe, nullptr);
   jclass c = env_->FindClass("java/lang/String");
-  ASSERT_TRUE(c != NULL);
+  ASSERT_NE(c, nullptr);
 
   // Wrong type.
   jfieldID fid = env_->GetStaticFieldID(c, "CASE_INSENSITIVE_ORDER", "J");
-  EXPECT_EQ(static_cast<jfieldID>(NULL), fid);
-  EXPECT_EXCEPTION(jlnsfe);
+  EXPECT_EQ(nullptr, fid);
+  ExpectException(jlnsfe);
 
   // Wrong type where type doesn't exist.
   fid = env_->GetStaticFieldID(c, "CASE_INSENSITIVE_ORDER", "Lrod/jane/freddy;");
-  EXPECT_EQ(static_cast<jfieldID>(NULL), fid);
-  EXPECT_EXCEPTION(jlnsfe);
+  EXPECT_EQ(nullptr, fid);
+  ExpectException(jlnsfe);
 
   // Wrong name.
   fid = env_->GetStaticFieldID(c, "cASE_INSENSITIVE_ORDER", "Ljava/util/Comparator;");
-  EXPECT_EQ(static_cast<jfieldID>(NULL), fid);
-  EXPECT_EXCEPTION(jlnsfe);
+  EXPECT_EQ(nullptr, fid);
+  ExpectException(jlnsfe);
 
   // Good declared field lookup.
   fid = env_->GetStaticFieldID(c, "CASE_INSENSITIVE_ORDER", "Ljava/util/Comparator;");
-  EXPECT_NE(static_cast<jfieldID>(NULL), fid);
-  EXPECT_TRUE(fid != NULL);
+  EXPECT_NE(nullptr, fid);
+  EXPECT_NE(fid, nullptr);
   EXPECT_FALSE(env_->ExceptionCheck());
 
   // Not static.
   fid = env_->GetStaticFieldID(c, "count", "I");
-  EXPECT_EQ(static_cast<jfieldID>(NULL), fid);
-  EXPECT_EXCEPTION(jlnsfe);
+  EXPECT_EQ(nullptr, fid);
+  ExpectException(jlnsfe);
+
+  // Bad arguments.
+  CheckJniAbortCatcher check_jni_abort_catcher;
+  fid = env_->GetStaticFieldID(nullptr, "CASE_INSENSITIVE_ORDER", "Ljava/util/Comparator;");
+  EXPECT_EQ(nullptr, fid);
+  check_jni_abort_catcher.Check("java_class == null");
+  fid = env_->GetStaticFieldID(c, nullptr, "Ljava/util/Comparator;");
+  EXPECT_EQ(nullptr, fid);
+  check_jni_abort_catcher.Check("name == null");
+  fid = env_->GetStaticFieldID(c, "CASE_INSENSITIVE_ORDER", nullptr);
+  EXPECT_EQ(nullptr, fid);
+  check_jni_abort_catcher.Check("sig == null");
 }
 
 TEST_F(JniInternalTest, GetMethodID) {
@@ -242,24 +274,36 @@
   // Check that java.lang.Object.foo() doesn't exist and NoSuchMethodError is
   // a pending exception
   jmethodID method = env_->GetMethodID(jlobject, "foo", "()V");
-  EXPECT_EQ(static_cast<jmethodID>(NULL), method);
-  EXPECT_EXCEPTION(jlnsme);
+  EXPECT_EQ(nullptr, method);
+  ExpectException(jlnsme);
 
   // Check that java.lang.Object.equals() does exist
   method = env_->GetMethodID(jlobject, "equals", "(Ljava/lang/Object;)Z");
-  EXPECT_NE(static_cast<jmethodID>(NULL), method);
+  EXPECT_NE(nullptr, method);
   EXPECT_FALSE(env_->ExceptionCheck());
 
   // Check that GetMethodID for java.lang.String.valueOf(int) fails as the
   // method is static
   method = env_->GetMethodID(jlstring, "valueOf", "(I)Ljava/lang/String;");
-  EXPECT_EQ(static_cast<jmethodID>(NULL), method);
-  EXPECT_EXCEPTION(jlnsme);
+  EXPECT_EQ(nullptr, method);
+  ExpectException(jlnsme);
 
   // Check that GetMethodID for java.lang.NoSuchMethodError.<init>(String) finds the constructor
   method = env_->GetMethodID(jlnsme, "<init>", "(Ljava/lang/String;)V");
-  EXPECT_NE(static_cast<jmethodID>(NULL), method);
+  EXPECT_NE(nullptr, method);
   EXPECT_FALSE(env_->ExceptionCheck());
+
+  // Bad arguments.
+  CheckJniAbortCatcher check_jni_abort_catcher;
+  method = env_->GetMethodID(nullptr, "<init>", "(Ljava/lang/String;)V");
+  EXPECT_EQ(nullptr, method);
+  check_jni_abort_catcher.Check("java_class == null");
+  method = env_->GetMethodID(jlnsme, nullptr, "(Ljava/lang/String;)V");
+  EXPECT_EQ(nullptr, method);
+  check_jni_abort_catcher.Check("name == null");
+  method = env_->GetMethodID(jlnsme, "<init>", nullptr);
+  EXPECT_EQ(nullptr, method);
+  check_jni_abort_catcher.Check("sig == null");
 }
 
 TEST_F(JniInternalTest, GetStaticMethodID) {
@@ -272,93 +316,155 @@
   // Check that java.lang.Object.foo() doesn't exist and NoSuchMethodError is
   // a pending exception
   jmethodID method = env_->GetStaticMethodID(jlobject, "foo", "()V");
-  EXPECT_EQ(static_cast<jmethodID>(NULL), method);
-  EXPECT_EXCEPTION(jlnsme);
+  EXPECT_EQ(nullptr, method);
+  ExpectException(jlnsme);
 
   // Check that GetStaticMethodID for java.lang.Object.equals(Object) fails as
   // the method is not static
   method = env_->GetStaticMethodID(jlobject, "equals", "(Ljava/lang/Object;)Z");
-  EXPECT_EQ(static_cast<jmethodID>(NULL), method);
-  EXPECT_EXCEPTION(jlnsme);
+  EXPECT_EQ(nullptr, method);
+  ExpectException(jlnsme);
 
   // Check that java.lang.String.valueOf(int) does exist
   jclass jlstring = env_->FindClass("java/lang/String");
-  method = env_->GetStaticMethodID(jlstring, "valueOf",
-                                   "(I)Ljava/lang/String;");
-  EXPECT_NE(static_cast<jmethodID>(NULL), method);
+  method = env_->GetStaticMethodID(jlstring, "valueOf", "(I)Ljava/lang/String;");
+  EXPECT_NE(nullptr, method);
   EXPECT_FALSE(env_->ExceptionCheck());
+
+  // Bad arguments.
+  CheckJniAbortCatcher check_jni_abort_catcher;
+  method = env_->GetStaticMethodID(nullptr, "valueOf", "(I)Ljava/lang/String;");
+  EXPECT_EQ(nullptr, method);
+  check_jni_abort_catcher.Check("java_class == null");
+  method = env_->GetStaticMethodID(jlstring, nullptr, "(I)Ljava/lang/String;");
+  EXPECT_EQ(nullptr, method);
+  check_jni_abort_catcher.Check("name == null");
+  method = env_->GetStaticMethodID(jlstring, "valueOf", nullptr);
+  EXPECT_EQ(nullptr, method);
+  check_jni_abort_catcher.Check("sig == null");
 }
 
 TEST_F(JniInternalTest, FromReflectedField_ToReflectedField) {
   jclass jlrField = env_->FindClass("java/lang/reflect/Field");
   jclass c = env_->FindClass("java/lang/String");
-  ASSERT_TRUE(c != NULL);
+  ASSERT_NE(c, nullptr);
   jfieldID fid = env_->GetFieldID(c, "count", "I");
-  ASSERT_TRUE(fid != NULL);
+  ASSERT_NE(fid, nullptr);
   // Turn the fid into a java.lang.reflect.Field...
   jobject field = env_->ToReflectedField(c, fid, JNI_FALSE);
-  ASSERT_TRUE(c != NULL);
+  ASSERT_NE(c, nullptr);
   ASSERT_TRUE(env_->IsInstanceOf(field, jlrField));
   // ...and back again.
   jfieldID fid2 = env_->FromReflectedField(field);
-  ASSERT_TRUE(fid2 != NULL);
+  ASSERT_NE(fid2, nullptr);
   // Make sure we can actually use it.
   jstring s = env_->NewStringUTF("poop");
   ASSERT_EQ(4, env_->GetIntField(s, fid2));
+
+  // Bad arguments.
+  CheckJniAbortCatcher check_jni_abort_catcher;
+  field = env_->ToReflectedField(c, nullptr, JNI_FALSE);
+  EXPECT_EQ(field, nullptr);
+  check_jni_abort_catcher.Check("fid == null");
+  fid2 = env_->FromReflectedField(nullptr);
+  ASSERT_EQ(fid2, nullptr);
+  check_jni_abort_catcher.Check("jlr_field == null");
 }
 
 TEST_F(JniInternalTest, FromReflectedMethod_ToReflectedMethod) {
   jclass jlrMethod = env_->FindClass("java/lang/reflect/Method");
   jclass c = env_->FindClass("java/lang/String");
-  ASSERT_TRUE(c != NULL);
+  ASSERT_NE(c, nullptr);
   jmethodID mid = env_->GetMethodID(c, "length", "()I");
-  ASSERT_TRUE(mid != NULL);
+  ASSERT_NE(mid, nullptr);
   // Turn the mid into a java.lang.reflect.Method...
   jobject method = env_->ToReflectedMethod(c, mid, JNI_FALSE);
-  ASSERT_TRUE(c != NULL);
+  ASSERT_NE(c, nullptr);
   ASSERT_TRUE(env_->IsInstanceOf(method, jlrMethod));
   // ...and back again.
   jmethodID mid2 = env_->FromReflectedMethod(method);
-  ASSERT_TRUE(mid2 != NULL);
+  ASSERT_NE(mid2, nullptr);
   // Make sure we can actually use it.
   jstring s = env_->NewStringUTF("poop");
   ASSERT_EQ(4, env_->CallIntMethod(s, mid2));
+
+  // Bad arguments.
+  CheckJniAbortCatcher check_jni_abort_catcher;
+  method = env_->ToReflectedMethod(c, nullptr, JNI_FALSE);
+  EXPECT_EQ(method, nullptr);
+  check_jni_abort_catcher.Check("mid == null");
+  mid2 = env_->FromReflectedMethod(method);
+  ASSERT_EQ(mid2, nullptr);
+  check_jni_abort_catcher.Check("jlr_method == null");
 }
 
-void BogusMethod() {
-  // You can't pass NULL function pointers to RegisterNatives.
+static void BogusMethod() {
+  // You can't pass nullptr function pointers to RegisterNatives.
 }
 
-TEST_F(JniInternalTest, RegisterNatives) {
+TEST_F(JniInternalTest, RegisterAndUnregisterNatives) {
   jclass jlobject = env_->FindClass("java/lang/Object");
   jclass jlnsme = env_->FindClass("java/lang/NoSuchMethodError");
 
-  // Sanity check that no exceptions are pending
+  // Sanity check that no exceptions are pending.
   ASSERT_FALSE(env_->ExceptionCheck());
 
-  // Check that registering to a non-existent java.lang.Object.foo() causes a
-  // NoSuchMethodError
+  // Check that registering to a non-existent java.lang.Object.foo() causes a NoSuchMethodError.
   {
-    JNINativeMethod methods[] = { { "foo", "()V", NULL } };
-    env_->RegisterNatives(jlobject, methods, 1);
+    JNINativeMethod methods[] = { { "foo", "()V", nullptr } };
+    EXPECT_EQ(env_->RegisterNatives(jlobject, methods, 1), JNI_ERR);
   }
-  EXPECT_EXCEPTION(jlnsme);
+  ExpectException(jlnsme);
 
-  // Check that registering non-native methods causes a NoSuchMethodError
+  // Check that registering non-native methods causes a NoSuchMethodError.
   {
-    JNINativeMethod methods[] = { { "equals", "(Ljava/lang/Object;)Z", NULL } };
-    env_->RegisterNatives(jlobject, methods, 1);
+    JNINativeMethod methods[] = { { "equals", "(Ljava/lang/Object;)Z", nullptr } };
+    EXPECT_EQ(env_->RegisterNatives(jlobject, methods, 1), JNI_ERR);
   }
-  EXPECT_EXCEPTION(jlnsme);
+  ExpectException(jlnsme);
 
-  // Check that registering native methods is successful
+  // Check that registering native methods is successful.
   {
     JNINativeMethod methods[] = { { "notify", "()V", reinterpret_cast<void*>(BogusMethod) } };
-    env_->RegisterNatives(jlobject, methods, 1);
+    EXPECT_EQ(env_->RegisterNatives(jlobject, methods, 1), JNI_OK);
+  }
+  EXPECT_FALSE(env_->ExceptionCheck());
+  EXPECT_EQ(env_->UnregisterNatives(jlobject), JNI_OK);
+
+  // Check that registering no methods isn't a failure.
+  {
+    JNINativeMethod methods[] = { };
+    EXPECT_EQ(env_->RegisterNatives(jlobject, methods, 0), JNI_OK);
+  }
+  EXPECT_FALSE(env_->ExceptionCheck());
+  EXPECT_EQ(env_->UnregisterNatives(jlobject), JNI_OK);
+
+  // Check that registering a -ve number of methods is a failure.
+  CheckJniAbortCatcher check_jni_abort_catcher;
+  for (int i = -10; i < 0; ++i) {
+    JNINativeMethod methods[] = { };
+    EXPECT_EQ(env_->RegisterNatives(jlobject, methods, i), JNI_ERR);
+    check_jni_abort_catcher.Check("negative method count: ");
   }
   EXPECT_FALSE(env_->ExceptionCheck());
 
-  env_->UnregisterNatives(jlobject);
+  // Passing a class of null is a failure.
+  {
+    JNINativeMethod methods[] = { };
+    EXPECT_EQ(env_->RegisterNatives(nullptr, methods, 0), JNI_ERR);
+    check_jni_abort_catcher.Check("java_class == null");
+  }
+
+  // Passing methods as null is a failure.
+  EXPECT_EQ(env_->RegisterNatives(jlobject, nullptr, 1), JNI_ERR);
+  check_jni_abort_catcher.Check("methods == null");
+
+  // Unregisters null is a failure.
+  EXPECT_EQ(env_->UnregisterNatives(nullptr), JNI_ERR);
+  check_jni_abort_catcher.Check("java_class == null");
+
+  // Unregistering a class with no natives is a warning.
+  EXPECT_EQ(env_->UnregisterNatives(jlnsme), JNI_OK);
 }
 
 #define EXPECT_PRIMITIVE_ARRAY(new_fn, \
@@ -368,52 +474,69 @@
                                release_elements_fn, \
                                scalar_type, \
                                expected_class_descriptor) \
+  jsize size = 4; \
+  \
   { \
     CheckJniAbortCatcher jni_abort_catcher; \
     /* Allocate an negative sized array and check it has the right failure type. */ \
-    env_->new_fn(-1); \
+    EXPECT_EQ(env_->new_fn(-1), nullptr); \
     jni_abort_catcher.Check("negative array length: -1"); \
-    env_->new_fn(std::numeric_limits<jint>::min()); \
+    EXPECT_EQ(env_->new_fn(std::numeric_limits<jint>::min()), nullptr); \
     jni_abort_catcher.Check("negative array length: -2147483648"); \
+    /* Pass the array as null. */ \
+    EXPECT_EQ(0, env_->GetArrayLength(nullptr)); \
+    jni_abort_catcher.Check("java_array == null"); \
+    env_->get_region_fn(nullptr, 0, 0, nullptr); \
+    jni_abort_catcher.Check("java_array == null"); \
+    env_->set_region_fn(nullptr, 0, 0, nullptr); \
+    jni_abort_catcher.Check("java_array == null"); \
+    env_->get_elements_fn(nullptr, nullptr); \
+    jni_abort_catcher.Check("java_array == null"); \
+    env_->release_elements_fn(nullptr, nullptr, 0); \
+    jni_abort_catcher.Check("java_array == null"); \
+    /* Pass the elements for region as null. */ \
+    scalar_type ## Array a = env_->new_fn(size); \
+    env_->get_region_fn(a, 0, size, nullptr); \
+    jni_abort_catcher.Check("buf == null"); \
+    env_->set_region_fn(a, 0, size, nullptr); \
+    jni_abort_catcher.Check("buf == null"); \
   } \
-  jsize size = 4; \
-  \
   /* Allocate an array and check it has the right type and length. */ \
   scalar_type ## Array a = env_->new_fn(size); \
-  EXPECT_TRUE(a != NULL); \
+  EXPECT_NE(a, nullptr); \
   EXPECT_TRUE(env_->IsInstanceOf(a, env_->FindClass(expected_class_descriptor))); \
   EXPECT_EQ(size, env_->GetArrayLength(a)); \
   \
   /* GetPrimitiveArrayRegion/SetPrimitiveArrayRegion */ \
   /* AIOOBE for negative start offset. */ \
-  env_->get_region_fn(a, -1, 1, NULL); \
-  EXPECT_EXCEPTION(aioobe_); \
-  env_->set_region_fn(a, -1, 1, NULL); \
-  EXPECT_EXCEPTION(aioobe_); \
+  env_->get_region_fn(a, -1, 1, nullptr); \
+  ExpectException(aioobe_); \
+  env_->set_region_fn(a, -1, 1, nullptr); \
+  ExpectException(aioobe_); \
   \
   /* AIOOBE for negative length. */ \
-  env_->get_region_fn(a, 0, -1, NULL); \
-  EXPECT_EXCEPTION(aioobe_); \
-  env_->set_region_fn(a, 0, -1, NULL); \
-  EXPECT_EXCEPTION(aioobe_); \
+  env_->get_region_fn(a, 0, -1, nullptr); \
+  ExpectException(aioobe_); \
+  env_->set_region_fn(a, 0, -1, nullptr); \
+  ExpectException(aioobe_); \
   \
   /* AIOOBE for buffer overrun. */ \
-  env_->get_region_fn(a, size - 1, size, NULL); \
-  EXPECT_EXCEPTION(aioobe_); \
-  env_->set_region_fn(a, size - 1, size, NULL); \
-  EXPECT_EXCEPTION(aioobe_); \
+  env_->get_region_fn(a, size - 1, size, nullptr); \
+  ExpectException(aioobe_); \
+  env_->set_region_fn(a, size - 1, size, nullptr); \
+  ExpectException(aioobe_); \
   \
-  /* It's okay for the buffer to be NULL as long as the length is 0. */ \
-  env_->get_region_fn(a, 2, 0, NULL); \
+  /* It's okay for the buffer to be nullptr as long as the length is 0. */ \
+  env_->get_region_fn(a, 2, 0, nullptr); \
   /* Even if the offset is invalid... */ \
-  env_->get_region_fn(a, 123, 0, NULL); \
-  EXPECT_EXCEPTION(aioobe_); \
+  env_->get_region_fn(a, 123, 0, nullptr); \
+  ExpectException(aioobe_); \
   \
-  /* It's okay for the buffer to be NULL as long as the length is 0. */ \
-  env_->set_region_fn(a, 2, 0, NULL); \
+  /* It's okay for the buffer to be nullptr as long as the length is 0. */ \
+  env_->set_region_fn(a, 2, 0, nullptr); \
   /* Even if the offset is invalid... */ \
-  env_->set_region_fn(a, 123, 0, NULL); \
-  EXPECT_EXCEPTION(aioobe_); \
+  env_->set_region_fn(a, 123, 0, nullptr); \
+  ExpectException(aioobe_); \
   \
   /* Prepare a couple of buffers. */ \
   UniquePtr<scalar_type[]> src_buf(new scalar_type[size]); \
@@ -437,12 +560,12 @@
   EXPECT_EQ(memcmp(&src_buf[0], &dst_buf[0], size * sizeof(scalar_type)), 0) \
     << "full copy not equal"; \
   /* GetPrimitiveArrayCritical */ \
-  void* v = env_->GetPrimitiveArrayCritical(a, NULL); \
+  void* v = env_->GetPrimitiveArrayCritical(a, nullptr); \
   EXPECT_EQ(memcmp(&src_buf[0], v, size * sizeof(scalar_type)), 0) \
     << "GetPrimitiveArrayCritical not equal"; \
   env_->ReleasePrimitiveArrayCritical(a, v, 0); \
   /* GetXArrayElements */ \
-  scalar_type* xs = env_->get_elements_fn(a, NULL); \
+  scalar_type* xs = env_->get_elements_fn(a, nullptr); \
   EXPECT_EQ(memcmp(&src_buf[0], xs, size * sizeof(scalar_type)), 0) \
     << # get_elements_fn " not equal"; \
   env_->release_elements_fn(a, xs, 0); \
@@ -480,31 +603,206 @@
                          GetShortArrayElements, ReleaseShortArrayElements, jshort, "[S");
 }
 
+TEST_F(JniInternalTest, GetPrimitiveArrayElementsOfWrongType) {
+  CheckJniAbortCatcher jni_abort_catcher;
+  jbooleanArray array = env_->NewBooleanArray(10);
+  jboolean is_copy;
+  EXPECT_EQ(env_->GetByteArrayElements(reinterpret_cast<jbyteArray>(array), &is_copy), nullptr);
+  jni_abort_catcher.Check(
+      "attempt to get byte primitive array elements with an object of type boolean[]");
+  EXPECT_EQ(env_->GetShortArrayElements(reinterpret_cast<jshortArray>(array), &is_copy), nullptr);
+  jni_abort_catcher.Check(
+      "attempt to get short primitive array elements with an object of type boolean[]");
+  EXPECT_EQ(env_->GetCharArrayElements(reinterpret_cast<jcharArray>(array), &is_copy), nullptr);
+  jni_abort_catcher.Check(
+      "attempt to get char primitive array elements with an object of type boolean[]");
+  EXPECT_EQ(env_->GetIntArrayElements(reinterpret_cast<jintArray>(array), &is_copy), nullptr);
+  jni_abort_catcher.Check(
+      "attempt to get int primitive array elements with an object of type boolean[]");
+  EXPECT_EQ(env_->GetLongArrayElements(reinterpret_cast<jlongArray>(array), &is_copy), nullptr);
+  jni_abort_catcher.Check(
+      "attempt to get long primitive array elements with an object of type boolean[]");
+  EXPECT_EQ(env_->GetFloatArrayElements(reinterpret_cast<jfloatArray>(array), &is_copy), nullptr);
+  jni_abort_catcher.Check(
+      "attempt to get float primitive array elements with an object of type boolean[]");
+  EXPECT_EQ(env_->GetDoubleArrayElements(reinterpret_cast<jdoubleArray>(array), &is_copy), nullptr);
+  jni_abort_catcher.Check(
+      "attempt to get double primitive array elements with an object of type boolean[]");
+  jbyteArray array2 = env_->NewByteArray(10);
+  EXPECT_EQ(env_->GetBooleanArrayElements(reinterpret_cast<jbooleanArray>(array2), &is_copy), nullptr);
+  jni_abort_catcher.Check(
+      "attempt to get boolean primitive array elements with an object of type byte[]");
+  jobject object = env_->NewStringUTF("Test String");
+  EXPECT_EQ(env_->GetBooleanArrayElements(reinterpret_cast<jbooleanArray>(object), &is_copy), nullptr);
+  jni_abort_catcher.Check(
+      "attempt to get boolean primitive array elements with an object of type java.lang.String");
+}
+
+TEST_F(JniInternalTest, ReleasePrimitiveArrayElementsOfWrongType) {
+  CheckJniAbortCatcher jni_abort_catcher;
+  jbooleanArray array = env_->NewBooleanArray(10);
+  ASSERT_TRUE(array != nullptr);
+  jboolean is_copy;
+  jboolean* elements = env_->GetBooleanArrayElements(array, &is_copy);
+  ASSERT_TRUE(elements != nullptr);
+  env_->ReleaseByteArrayElements(reinterpret_cast<jbyteArray>(array),
+                                 reinterpret_cast<jbyte*>(elements), 0);
+  jni_abort_catcher.Check(
+      "attempt to release byte primitive array elements with an object of type boolean[]");
+  env_->ReleaseShortArrayElements(reinterpret_cast<jshortArray>(array),
+                                  reinterpret_cast<jshort*>(elements), 0);
+  jni_abort_catcher.Check(
+      "attempt to release short primitive array elements with an object of type boolean[]");
+  env_->ReleaseCharArrayElements(reinterpret_cast<jcharArray>(array),
+                                 reinterpret_cast<jchar*>(elements), 0);
+  jni_abort_catcher.Check(
+      "attempt to release char primitive array elements with an object of type boolean[]");
+  env_->ReleaseIntArrayElements(reinterpret_cast<jintArray>(array),
+                                reinterpret_cast<jint*>(elements), 0);
+  jni_abort_catcher.Check(
+      "attempt to release int primitive array elements with an object of type boolean[]");
+  env_->ReleaseLongArrayElements(reinterpret_cast<jlongArray>(array),
+                                 reinterpret_cast<jlong*>(elements), 0);
+  jni_abort_catcher.Check(
+      "attempt to release long primitive array elements with an object of type boolean[]");
+  env_->ReleaseFloatArrayElements(reinterpret_cast<jfloatArray>(array),
+                                  reinterpret_cast<jfloat*>(elements), 0);
+  jni_abort_catcher.Check(
+      "attempt to release float primitive array elements with an object of type boolean[]");
+  env_->ReleaseDoubleArrayElements(reinterpret_cast<jdoubleArray>(array),
+                                  reinterpret_cast<jdouble*>(elements), 0);
+  jni_abort_catcher.Check(
+      "attempt to release double primitive array elements with an object of type boolean[]");
+  jbyteArray array2 = env_->NewByteArray(10);
+  env_->ReleaseBooleanArrayElements(reinterpret_cast<jbooleanArray>(array2), elements, 0);
+  jni_abort_catcher.Check(
+      "attempt to release boolean primitive array elements with an object of type byte[]");
+  jobject object = env_->NewStringUTF("Test String");
+  env_->ReleaseBooleanArrayElements(reinterpret_cast<jbooleanArray>(object), elements, 0);
+  jni_abort_catcher.Check(
+      "attempt to release boolean primitive array elements with an object of type java.lang.String");
+}
+TEST_F(JniInternalTest, GetReleasePrimitiveArrayCriticalOfWrongType) {
+  CheckJniAbortCatcher jni_abort_catcher;
+  jobject object = env_->NewStringUTF("Test String");
+  jboolean is_copy;
+  void* elements = env_->GetPrimitiveArrayCritical(reinterpret_cast<jarray>(object), &is_copy);
+  jni_abort_catcher.Check("expected primitive array, given java.lang.String");
+  env_->ReleasePrimitiveArrayCritical(reinterpret_cast<jarray>(object), elements, 0);
+  jni_abort_catcher.Check("expected primitive array, given java.lang.String");
+}
+
+TEST_F(JniInternalTest, GetPrimitiveArrayRegionElementsOfWrongType) {
+  CheckJniAbortCatcher jni_abort_catcher;
+  constexpr size_t kLength = 10;
+  jbooleanArray array = env_->NewBooleanArray(kLength);
+  ASSERT_TRUE(array != nullptr);
+  jboolean elements[kLength];
+  env_->GetByteArrayRegion(reinterpret_cast<jbyteArray>(array), 0, kLength,
+                           reinterpret_cast<jbyte*>(elements));
+  jni_abort_catcher.Check(
+      "attempt to get region of byte primitive array elements with an object of type boolean[]");
+  env_->GetShortArrayRegion(reinterpret_cast<jshortArray>(array), 0, kLength,
+                            reinterpret_cast<jshort*>(elements));
+  jni_abort_catcher.Check(
+      "attempt to get region of short primitive array elements with an object of type boolean[]");
+  env_->GetCharArrayRegion(reinterpret_cast<jcharArray>(array), 0, kLength,
+                           reinterpret_cast<jchar*>(elements));
+  jni_abort_catcher.Check(
+      "attempt to get region of char primitive array elements with an object of type boolean[]");
+  env_->GetIntArrayRegion(reinterpret_cast<jintArray>(array), 0, kLength,
+                          reinterpret_cast<jint*>(elements));
+  jni_abort_catcher.Check(
+      "attempt to get region of int primitive array elements with an object of type boolean[]");
+  env_->GetLongArrayRegion(reinterpret_cast<jlongArray>(array), 0, kLength,
+                           reinterpret_cast<jlong*>(elements));
+  jni_abort_catcher.Check(
+      "attempt to get region of long primitive array elements with an object of type boolean[]");
+  env_->GetFloatArrayRegion(reinterpret_cast<jfloatArray>(array), 0, kLength,
+                            reinterpret_cast<jfloat*>(elements));
+  jni_abort_catcher.Check(
+      "attempt to get region of float primitive array elements with an object of type boolean[]");
+  env_->GetDoubleArrayRegion(reinterpret_cast<jdoubleArray>(array), 0, kLength,
+                           reinterpret_cast<jdouble*>(elements));
+  jni_abort_catcher.Check(
+      "attempt to get region of double primitive array elements with an object of type boolean[]");
+  jbyteArray array2 = env_->NewByteArray(10);
+  env_->GetBooleanArrayRegion(reinterpret_cast<jbooleanArray>(array2), 0, kLength,
+                              reinterpret_cast<jboolean*>(elements));
+  jni_abort_catcher.Check(
+      "attempt to get region of boolean primitive array elements with an object of type byte[]");
+  jobject object = env_->NewStringUTF("Test String");
+  env_->GetBooleanArrayRegion(reinterpret_cast<jbooleanArray>(object), 0, kLength,
+                              reinterpret_cast<jboolean*>(elements));
+  jni_abort_catcher.Check(
+      "attempt to get region of boolean primitive array elements with an object of type java.lang.String");
+}
+
+TEST_F(JniInternalTest, SetPrimitiveArrayRegionElementsOfWrongType) {
+  CheckJniAbortCatcher jni_abort_catcher;
+  constexpr size_t kLength = 10;
+  jbooleanArray array = env_->NewBooleanArray(kLength);
+  ASSERT_TRUE(array != nullptr);
+  jboolean elements[kLength];
+  env_->SetByteArrayRegion(reinterpret_cast<jbyteArray>(array), 0, kLength,
+                           reinterpret_cast<jbyte*>(elements));
+  jni_abort_catcher.Check(
+      "attempt to set region of byte primitive array elements with an object of type boolean[]");
+  env_->SetShortArrayRegion(reinterpret_cast<jshortArray>(array), 0, kLength,
+                            reinterpret_cast<jshort*>(elements));
+  jni_abort_catcher.Check(
+      "attempt to set region of short primitive array elements with an object of type boolean[]");
+  env_->SetCharArrayRegion(reinterpret_cast<jcharArray>(array), 0, kLength,
+                           reinterpret_cast<jchar*>(elements));
+  jni_abort_catcher.Check(
+      "attempt to set region of char primitive array elements with an object of type boolean[]");
+  env_->SetIntArrayRegion(reinterpret_cast<jintArray>(array), 0, kLength,
+                          reinterpret_cast<jint*>(elements));
+  jni_abort_catcher.Check(
+      "attempt to set region of int primitive array elements with an object of type boolean[]");
+  env_->SetLongArrayRegion(reinterpret_cast<jlongArray>(array), 0, kLength,
+                           reinterpret_cast<jlong*>(elements));
+  jni_abort_catcher.Check(
+      "attempt to set region of long primitive array elements with an object of type boolean[]");
+  env_->SetFloatArrayRegion(reinterpret_cast<jfloatArray>(array), 0, kLength,
+                            reinterpret_cast<jfloat*>(elements));
+  jni_abort_catcher.Check(
+      "attempt to set region of float primitive array elements with an object of type boolean[]");
+  env_->SetDoubleArrayRegion(reinterpret_cast<jdoubleArray>(array), 0, kLength,
+                           reinterpret_cast<jdouble*>(elements));
+  jni_abort_catcher.Check(
+      "attempt to set region of double primitive array elements with an object of type boolean[]");
+  jbyteArray array2 = env_->NewByteArray(10);
+  env_->SetBooleanArrayRegion(reinterpret_cast<jbooleanArray>(array2), 0, kLength,
+                              reinterpret_cast<jboolean*>(elements));
+  jni_abort_catcher.Check(
+      "attempt to set region of boolean primitive array elements with an object of type byte[]");
+  jobject object = env_->NewStringUTF("Test String");
+  env_->SetBooleanArrayRegion(reinterpret_cast<jbooleanArray>(object), 0, kLength,
+                              reinterpret_cast<jboolean*>(elements));
+  jni_abort_catcher.Check(
+      "attempt to set region of boolean primitive array elements with an object of type java.lang.String");
+}
+
 TEST_F(JniInternalTest, NewObjectArray) {
   jclass element_class = env_->FindClass("java/lang/String");
-  ASSERT_TRUE(element_class != nullptr);
+  ASSERT_NE(element_class, nullptr);
   jclass array_class = env_->FindClass("[Ljava/lang/String;");
-  ASSERT_TRUE(array_class != nullptr);
+  ASSERT_NE(array_class, nullptr);
 
   jobjectArray a = env_->NewObjectArray(0, element_class, nullptr);
-  EXPECT_TRUE(a != nullptr);
+  EXPECT_NE(a, nullptr);
   EXPECT_TRUE(env_->IsInstanceOf(a, array_class));
   EXPECT_EQ(0, env_->GetArrayLength(a));
 
   a = env_->NewObjectArray(1, element_class, nullptr);
-  EXPECT_TRUE(a != nullptr);
+  EXPECT_NE(a, nullptr);
   EXPECT_TRUE(env_->IsInstanceOf(a, array_class));
   EXPECT_EQ(1, env_->GetArrayLength(a));
   EXPECT_TRUE(env_->IsSameObject(env_->GetObjectArrayElement(a, 0), nullptr));
-}
 
-TEST_F(JniInternalTest, NewObjectArrayWithNegativeLength) {
-  jclass element_class = env_->FindClass("java/lang/String");
-  ASSERT_TRUE(element_class != nullptr);
-  jclass array_class = env_->FindClass("[Ljava/lang/String;");
-  ASSERT_TRUE(array_class != nullptr);
+  // Negative array length checks.
   CheckJniAbortCatcher jni_abort_catcher;
-
   env_->NewObjectArray(-1, element_class, nullptr);
   jni_abort_catcher.Check("negative array length: -1");
 
@@ -521,6 +819,8 @@
 
   CheckJniAbortCatcher jni_abort_catcher;
   for (size_t i = 0; i < strlen(primitive_descriptors); ++i) {
+    env_->NewObjectArray(0, nullptr, nullptr);
+    jni_abort_catcher.Check("element_jclass == null");
     jclass primitive_class = GetPrimitiveClass(primitive_descriptors[i]);
     env_->NewObjectArray(1, primitive_class, nullptr);
     std::string error_msg(StringPrintf("not an object type: %s", primitive_names[i]));
@@ -530,13 +830,13 @@
 
 TEST_F(JniInternalTest, NewObjectArrayWithInitialValue) {
   jclass element_class = env_->FindClass("java/lang/String");
-  ASSERT_TRUE(element_class != nullptr);
+  ASSERT_NE(element_class, nullptr);
   jclass array_class = env_->FindClass("[Ljava/lang/String;");
-  ASSERT_TRUE(array_class != nullptr);
+  ASSERT_NE(array_class, nullptr);
 
   jstring s = env_->NewStringUTF("poop");
   jobjectArray a = env_->NewObjectArray(2, element_class, s);
-  EXPECT_TRUE(a != nullptr);
+  EXPECT_NE(a, nullptr);
   EXPECT_TRUE(env_->IsInstanceOf(a, array_class));
   EXPECT_EQ(2, env_->GetArrayLength(a));
   EXPECT_TRUE(env_->IsSameObject(env_->GetObjectArrayElement(a, 0), s));
@@ -555,9 +855,9 @@
 
 TEST_F(JniInternalTest, GetObjectClass) {
   jclass string_class = env_->FindClass("java/lang/String");
-  ASSERT_TRUE(string_class != NULL);
+  ASSERT_NE(string_class, nullptr);
   jclass class_class = env_->FindClass("java/lang/Class");
-  ASSERT_TRUE(class_class != NULL);
+  ASSERT_NE(class_class, nullptr);
 
   jstring s = env_->NewStringUTF("poop");
   jclass c = env_->GetObjectClass(s);
@@ -565,33 +865,50 @@
 
   jclass c2 = env_->GetObjectClass(c);
   ASSERT_TRUE(env_->IsSameObject(class_class, env_->GetObjectClass(c2)));
+
+  // Null as object should fail.
+  CheckJniAbortCatcher jni_abort_catcher;
+  EXPECT_EQ(env_->GetObjectClass(nullptr), nullptr);
+  jni_abort_catcher.Check("java_object == null");
 }
 
 TEST_F(JniInternalTest, GetSuperclass) {
   jclass object_class = env_->FindClass("java/lang/Object");
-  ASSERT_TRUE(object_class != NULL);
+  ASSERT_NE(object_class, nullptr);
   jclass string_class = env_->FindClass("java/lang/String");
-  ASSERT_TRUE(string_class != NULL);
+  ASSERT_NE(string_class, nullptr);
   jclass runnable_interface = env_->FindClass("java/lang/Runnable");
-  ASSERT_TRUE(runnable_interface != NULL);
+  ASSERT_NE(runnable_interface, nullptr);
   ASSERT_TRUE(env_->IsSameObject(object_class, env_->GetSuperclass(string_class)));
-  ASSERT_TRUE(env_->GetSuperclass(object_class) == NULL);
+  ASSERT_EQ(env_->GetSuperclass(object_class), nullptr);
   ASSERT_TRUE(env_->IsSameObject(object_class, env_->GetSuperclass(runnable_interface)));
+
+  // Null as class should fail.
+  CheckJniAbortCatcher jni_abort_catcher;
+  EXPECT_EQ(env_->GetSuperclass(nullptr), nullptr);
+  jni_abort_catcher.Check("java_class == null");
 }
 
 TEST_F(JniInternalTest, IsAssignableFrom) {
   jclass object_class = env_->FindClass("java/lang/Object");
-  ASSERT_TRUE(object_class != NULL);
+  ASSERT_NE(object_class, nullptr);
   jclass string_class = env_->FindClass("java/lang/String");
-  ASSERT_TRUE(string_class != NULL);
+  ASSERT_NE(string_class, nullptr);
 
   ASSERT_TRUE(env_->IsAssignableFrom(object_class, string_class));
   ASSERT_FALSE(env_->IsAssignableFrom(string_class, object_class));
+
+  // Null as either class should fail.
+  CheckJniAbortCatcher jni_abort_catcher;
+  EXPECT_EQ(env_->IsAssignableFrom(nullptr, string_class), JNI_FALSE);
+  jni_abort_catcher.Check("java_class1 == null");
+  EXPECT_EQ(env_->IsAssignableFrom(object_class, nullptr), JNI_FALSE);
+  jni_abort_catcher.Check("java_class2 == null");
 }
 
 TEST_F(JniInternalTest, GetObjectRefType) {
   jclass local = env_->FindClass("java/lang/Object");
-  ASSERT_TRUE(local != NULL);
+  ASSERT_TRUE(local != nullptr);
   EXPECT_EQ(JNILocalRefType, env_->GetObjectRefType(local));
 
   jobject global = env_->NewGlobalRef(local);
@@ -604,33 +921,38 @@
   EXPECT_EQ(JNIInvalidRefType, env_->GetObjectRefType(invalid));
 
   // TODO: invoke a native method and test that its arguments are considered local references.
+
+  // Null as object should fail.
+  CheckJniAbortCatcher jni_abort_catcher;
+  EXPECT_EQ(JNIInvalidRefType, env_->GetObjectRefType(nullptr));
+  jni_abort_catcher.Check("java_object == null");
 }
 
 TEST_F(JniInternalTest, StaleWeakGlobal) {
   jclass java_lang_Class = env_->FindClass("java/lang/Class");
-  ASSERT_TRUE(java_lang_Class != NULL);
-  jobjectArray local_ref = env_->NewObjectArray(1, java_lang_Class, NULL);
-  ASSERT_TRUE(local_ref != NULL);
+  ASSERT_NE(java_lang_Class, nullptr);
+  jobjectArray local_ref = env_->NewObjectArray(1, java_lang_Class, nullptr);
+  ASSERT_NE(local_ref, nullptr);
   jweak weak_global = env_->NewWeakGlobalRef(local_ref);
-  ASSERT_TRUE(weak_global != NULL);
+  ASSERT_NE(weak_global, nullptr);
   env_->DeleteLocalRef(local_ref);
   Runtime::Current()->GetHeap()->CollectGarbage(false);  // GC should clear the weak global.
   jobject new_global_ref = env_->NewGlobalRef(weak_global);
-  EXPECT_TRUE(new_global_ref == NULL);
+  EXPECT_EQ(new_global_ref, nullptr);
   jobject new_local_ref = env_->NewLocalRef(weak_global);
-  EXPECT_TRUE(new_local_ref == NULL);
+  EXPECT_EQ(new_local_ref, nullptr);
 }
 
 TEST_F(JniInternalTest, NewStringUTF) {
-  EXPECT_TRUE(env_->NewStringUTF(NULL) == NULL);
+  EXPECT_EQ(env_->NewStringUTF(nullptr), nullptr);
   jstring s;
 
   s = env_->NewStringUTF("");
-  EXPECT_TRUE(s != NULL);
+  EXPECT_NE(s, nullptr);
   EXPECT_EQ(0, env_->GetStringLength(s));
   EXPECT_EQ(0, env_->GetStringUTFLength(s));
   s = env_->NewStringUTF("hello");
-  EXPECT_TRUE(s != NULL);
+  EXPECT_NE(s, nullptr);
   EXPECT_EQ(5, env_->GetStringLength(s));
   EXPECT_EQ(5, env_->GetStringUTFLength(s));
 
@@ -641,11 +963,11 @@
   jchar chars[] = { 'h', 'i' };
   jstring s;
   s = env_->NewString(chars, 0);
-  EXPECT_TRUE(s != NULL);
+  EXPECT_NE(s, nullptr);
   EXPECT_EQ(0, env_->GetStringLength(s));
   EXPECT_EQ(0, env_->GetStringUTFLength(s));
   s = env_->NewString(chars, 2);
-  EXPECT_TRUE(s != NULL);
+  EXPECT_NE(s, nullptr);
   EXPECT_EQ(2, env_->GetStringLength(s));
   EXPECT_EQ(2, env_->GetStringUTFLength(s));
 
@@ -654,7 +976,7 @@
 
 TEST_F(JniInternalTest, NewStringNullCharsZeroLength) {
   jstring s = env_->NewString(nullptr, 0);
-  EXPECT_TRUE(s != nullptr);
+  EXPECT_NE(s, nullptr);
   EXPECT_EQ(0, env_->GetStringLength(s));
 }
 
@@ -678,16 +1000,16 @@
 
 TEST_F(JniInternalTest, GetStringRegion_GetStringUTFRegion) {
   jstring s = env_->NewStringUTF("hello");
-  ASSERT_TRUE(s != NULL);
+  ASSERT_TRUE(s != nullptr);
 
-  env_->GetStringRegion(s, -1, 0, NULL);
-  EXPECT_EXCEPTION(sioobe_);
-  env_->GetStringRegion(s, 0, -1, NULL);
-  EXPECT_EXCEPTION(sioobe_);
-  env_->GetStringRegion(s, 0, 10, NULL);
-  EXPECT_EXCEPTION(sioobe_);
-  env_->GetStringRegion(s, 10, 1, NULL);
-  EXPECT_EXCEPTION(sioobe_);
+  env_->GetStringRegion(s, -1, 0, nullptr);
+  ExpectException(sioobe_);
+  env_->GetStringRegion(s, 0, -1, nullptr);
+  ExpectException(sioobe_);
+  env_->GetStringRegion(s, 0, 10, nullptr);
+  ExpectException(sioobe_);
+  env_->GetStringRegion(s, 10, 1, nullptr);
+  ExpectException(sioobe_);
 
   jchar chars[4] = { 'x', 'x', 'x', 'x' };
   env_->GetStringRegion(s, 1, 2, &chars[1]);
@@ -696,20 +1018,20 @@
   EXPECT_EQ('l', chars[2]);
   EXPECT_EQ('x', chars[3]);
 
-  // It's okay for the buffer to be NULL as long as the length is 0.
-  env_->GetStringRegion(s, 2, 0, NULL);
+  // It's okay for the buffer to be nullptr as long as the length is 0.
+  env_->GetStringRegion(s, 2, 0, nullptr);
   // Even if the offset is invalid...
-  env_->GetStringRegion(s, 123, 0, NULL);
-  EXPECT_EXCEPTION(sioobe_);
+  env_->GetStringRegion(s, 123, 0, nullptr);
+  ExpectException(sioobe_);
 
-  env_->GetStringUTFRegion(s, -1, 0, NULL);
-  EXPECT_EXCEPTION(sioobe_);
-  env_->GetStringUTFRegion(s, 0, -1, NULL);
-  EXPECT_EXCEPTION(sioobe_);
-  env_->GetStringUTFRegion(s, 0, 10, NULL);
-  EXPECT_EXCEPTION(sioobe_);
-  env_->GetStringUTFRegion(s, 10, 1, NULL);
-  EXPECT_EXCEPTION(sioobe_);
+  env_->GetStringUTFRegion(s, -1, 0, nullptr);
+  ExpectException(sioobe_);
+  env_->GetStringUTFRegion(s, 0, -1, nullptr);
+  ExpectException(sioobe_);
+  env_->GetStringUTFRegion(s, 0, 10, nullptr);
+  ExpectException(sioobe_);
+  env_->GetStringUTFRegion(s, 10, 1, nullptr);
+  ExpectException(sioobe_);
 
   char bytes[4] = { 'x', 'x', 'x', 'x' };
   env_->GetStringUTFRegion(s, 1, 2, &bytes[1]);
@@ -718,25 +1040,25 @@
   EXPECT_EQ('l', bytes[2]);
   EXPECT_EQ('x', bytes[3]);
 
-  // It's okay for the buffer to be NULL as long as the length is 0.
-  env_->GetStringUTFRegion(s, 2, 0, NULL);
+  // It's okay for the buffer to be nullptr as long as the length is 0.
+  env_->GetStringUTFRegion(s, 2, 0, nullptr);
   // Even if the offset is invalid...
-  env_->GetStringUTFRegion(s, 123, 0, NULL);
-  EXPECT_EXCEPTION(sioobe_);
+  env_->GetStringUTFRegion(s, 123, 0, nullptr);
+  ExpectException(sioobe_);
 }
 
 TEST_F(JniInternalTest, GetStringUTFChars_ReleaseStringUTFChars) {
-  // Passing in a NULL jstring is ignored normally, but caught by -Xcheck:jni.
+  // Passing in a nullptr jstring is ignored normally, but caught by -Xcheck:jni.
   {
     CheckJniAbortCatcher check_jni_abort_catcher;
-    EXPECT_TRUE(env_->GetStringUTFChars(NULL, NULL) == NULL);
+    EXPECT_EQ(env_->GetStringUTFChars(nullptr, nullptr), nullptr);
     check_jni_abort_catcher.Check("GetStringUTFChars received null jstring");
   }
 
   jstring s = env_->NewStringUTF("hello");
-  ASSERT_TRUE(s != NULL);
+  ASSERT_TRUE(s != nullptr);
 
-  const char* utf = env_->GetStringUTFChars(s, NULL);
+  const char* utf = env_->GetStringUTFChars(s, nullptr);
   EXPECT_STREQ("hello", utf);
   env_->ReleaseStringUTFChars(s, utf);
 
@@ -749,10 +1071,10 @@
 
 TEST_F(JniInternalTest, GetStringChars_ReleaseStringChars) {
   jstring s = env_->NewStringUTF("hello");
-  ASSERT_TRUE(s != NULL);
+  ASSERT_TRUE(s != nullptr);
 
   jchar expected[] = { 'h', 'e', 'l', 'l', 'o' };
-  const jchar* chars = env_->GetStringChars(s, NULL);
+  const jchar* chars = env_->GetStringChars(s, nullptr);
   EXPECT_EQ(expected[0], chars[0]);
   EXPECT_EQ(expected[1], chars[1]);
   EXPECT_EQ(expected[2], chars[2]);
@@ -773,10 +1095,10 @@
 
 TEST_F(JniInternalTest, GetStringCritical_ReleaseStringCritical) {
   jstring s = env_->NewStringUTF("hello");
-  ASSERT_TRUE(s != NULL);
+  ASSERT_TRUE(s != nullptr);
 
   jchar expected[] = { 'h', 'e', 'l', 'l', 'o' };
-  const jchar* chars = env_->GetStringCritical(s, NULL);
+  const jchar* chars = env_->GetStringCritical(s, nullptr);
   EXPECT_EQ(expected[0], chars[0]);
   EXPECT_EQ(expected[1], chars[1]);
   EXPECT_EQ(expected[2], chars[2]);
@@ -798,45 +1120,72 @@
 
 TEST_F(JniInternalTest, GetObjectArrayElement_SetObjectArrayElement) {
   jclass java_lang_Class = env_->FindClass("java/lang/Class");
-  ASSERT_TRUE(java_lang_Class != NULL);
+  ASSERT_TRUE(java_lang_Class != nullptr);
 
-  jobjectArray array = env_->NewObjectArray(1, java_lang_Class, NULL);
-  EXPECT_TRUE(array != NULL);
-  EXPECT_TRUE(env_->GetObjectArrayElement(array, 0) == NULL);
+  jobjectArray array = env_->NewObjectArray(1, java_lang_Class, nullptr);
+  EXPECT_NE(array, nullptr);
+  EXPECT_EQ(env_->GetObjectArrayElement(array, 0), nullptr);
   env_->SetObjectArrayElement(array, 0, java_lang_Class);
   EXPECT_TRUE(env_->IsSameObject(env_->GetObjectArrayElement(array, 0), java_lang_Class));
 
   // ArrayIndexOutOfBounds for negative index.
   env_->SetObjectArrayElement(array, -1, java_lang_Class);
-  EXPECT_EXCEPTION(aioobe_);
+  ExpectException(aioobe_);
 
   // ArrayIndexOutOfBounds for too-large index.
   env_->SetObjectArrayElement(array, 1, java_lang_Class);
-  EXPECT_EXCEPTION(aioobe_);
+  ExpectException(aioobe_);
 
   // ArrayStoreException thrown for bad types.
   env_->SetObjectArrayElement(array, 0, env_->NewStringUTF("not a jclass!"));
-  EXPECT_EXCEPTION(ase_);
+  ExpectException(ase_);
+
+  // Null as array should fail.
+  CheckJniAbortCatcher jni_abort_catcher;
+  EXPECT_EQ(nullptr, env_->GetObjectArrayElement(nullptr, 0));
+  jni_abort_catcher.Check("java_array == null");
+  env_->SetObjectArrayElement(nullptr, 0, nullptr);
+  jni_abort_catcher.Check("java_array == null");
 }
 
 #define EXPECT_STATIC_PRIMITIVE_FIELD(type, field_name, sig, value1, value2) \
   do { \
     jfieldID fid = env_->GetStaticFieldID(c, field_name, sig); \
-    EXPECT_TRUE(fid != NULL); \
+    EXPECT_NE(fid, nullptr); \
     env_->SetStatic ## type ## Field(c, fid, value1); \
-    EXPECT_TRUE(value1 == env_->GetStatic ## type ## Field(c, fid)); \
+    EXPECT_EQ(value1, env_->GetStatic ## type ## Field(c, fid)); \
     env_->SetStatic ## type ## Field(c, fid, value2); \
-    EXPECT_TRUE(value2 == env_->GetStatic ## type ## Field(c, fid)); \
+    EXPECT_EQ(value2, env_->GetStatic ## type ## Field(c, fid)); \
+    \
+    CheckJniAbortCatcher jni_abort_catcher; \
+    env_->GetStatic ## type ## Field(nullptr, fid); \
+    jni_abort_catcher.Check("received null jclass"); \
+    env_->SetStatic ## type ## Field(nullptr, fid, value1); \
+    jni_abort_catcher.Check("received null jclass"); \
+    env_->GetStatic ## type ## Field(c, nullptr); \
+    jni_abort_catcher.Check("fid == null"); \
+    env_->SetStatic ## type ## Field(c, nullptr, value1); \
+    jni_abort_catcher.Check("fid == null"); \
   } while (false)
 
 #define EXPECT_PRIMITIVE_FIELD(instance, type, field_name, sig, value1, value2) \
   do { \
     jfieldID fid = env_->GetFieldID(c, field_name, sig); \
-    EXPECT_TRUE(fid != NULL); \
+    EXPECT_NE(fid, nullptr); \
     env_->Set ## type ## Field(instance, fid, value1); \
-    EXPECT_TRUE(value1 == env_->Get ## type ## Field(instance, fid)); \
+    EXPECT_EQ(value1, env_->Get ## type ## Field(instance, fid)); \
     env_->Set ## type ## Field(instance, fid, value2); \
-    EXPECT_TRUE(value2 == env_->Get ## type ## Field(instance, fid)); \
+    EXPECT_EQ(value2, env_->Get ## type ## Field(instance, fid)); \
+    \
+    CheckJniAbortCatcher jni_abort_catcher; \
+    env_->Get ## type ## Field(nullptr, fid); \
+    jni_abort_catcher.Check("obj == null"); \
+    env_->Set ## type ## Field(nullptr, fid, value1); \
+    jni_abort_catcher.Check("obj == null"); \
+    env_->Get ## type ## Field(instance, nullptr); \
+    jni_abort_catcher.Check("fid == null"); \
+    env_->Set ## type ## Field(instance, nullptr, value1); \
+    jni_abort_catcher.Check("fid == null"); \
   } while (false)
 
 
@@ -845,14 +1194,14 @@
   Thread::Current()->TransitionFromSuspendedToRunnable();
   LoadDex("AllFields");
   bool started = runtime_->Start();
-  CHECK(started);
+  ASSERT_TRUE(started);
 
   jclass c = env_->FindClass("AllFields");
-  ASSERT_TRUE(c != NULL);
+  ASSERT_NE(c, nullptr);
   jobject o = env_->AllocObject(c);
-  ASSERT_TRUE(o != NULL);
+  ASSERT_NE(o, nullptr);
 
-  EXPECT_STATIC_PRIMITIVE_FIELD(Boolean, "sZ", "Z", true, false);
+  EXPECT_STATIC_PRIMITIVE_FIELD(Boolean, "sZ", "Z", JNI_TRUE, JNI_FALSE);
   EXPECT_STATIC_PRIMITIVE_FIELD(Byte, "sB", "B", 1, 2);
   EXPECT_STATIC_PRIMITIVE_FIELD(Char, "sC", "C", 'a', 'b');
   EXPECT_STATIC_PRIMITIVE_FIELD(Double, "sD", "D", 1.0, 2.0);
@@ -861,7 +1210,7 @@
   EXPECT_STATIC_PRIMITIVE_FIELD(Long, "sJ", "J", 1, 2);
   EXPECT_STATIC_PRIMITIVE_FIELD(Short, "sS", "S", 1, 2);
 
-  EXPECT_PRIMITIVE_FIELD(o, Boolean, "iZ", "Z", true, false);
+  EXPECT_PRIMITIVE_FIELD(o, Boolean, "iZ", "Z", JNI_TRUE, JNI_FALSE);
   EXPECT_PRIMITIVE_FIELD(o, Byte, "iB", "B", 1, 2);
   EXPECT_PRIMITIVE_FIELD(o, Char, "iC", "C", 'a', 'b');
   EXPECT_PRIMITIVE_FIELD(o, Double, "iD", "D", 1.0, 2.0);
@@ -878,19 +1227,19 @@
   runtime_->Start();
 
   jclass c = env_->FindClass("AllFields");
-  ASSERT_TRUE(c != NULL);
+  ASSERT_NE(c, nullptr);
   jobject o = env_->AllocObject(c);
-  ASSERT_TRUE(o != NULL);
+  ASSERT_NE(o, nullptr);
 
   jstring s1 = env_->NewStringUTF("hello");
-  ASSERT_TRUE(s1 != NULL);
+  ASSERT_NE(s1, nullptr);
   jstring s2 = env_->NewStringUTF("world");
-  ASSERT_TRUE(s2 != NULL);
+  ASSERT_NE(s2, nullptr);
 
   jfieldID s_fid = env_->GetStaticFieldID(c, "sObject", "Ljava/lang/Object;");
-  ASSERT_TRUE(s_fid != NULL);
+  ASSERT_NE(s_fid, nullptr);
   jfieldID i_fid = env_->GetFieldID(c, "iObject", "Ljava/lang/Object;");
-  ASSERT_TRUE(i_fid != NULL);
+  ASSERT_NE(i_fid, nullptr);
 
   env_->SetStaticObjectField(c, s_fid, s1);
   ASSERT_TRUE(env_->IsSameObject(s1, env_->GetStaticObjectField(c, s_fid)));
@@ -903,27 +1252,27 @@
   ASSERT_TRUE(env_->IsSameObject(s2, env_->GetObjectField(o, i_fid)));
 }
 
-TEST_F(JniInternalTest, NewLocalRef_NULL) {
-  EXPECT_TRUE(env_->NewLocalRef(NULL) == NULL);
+TEST_F(JniInternalTest, NewLocalRef_nullptr) {
+  EXPECT_EQ(env_->NewLocalRef(nullptr), nullptr);
 }
 
 TEST_F(JniInternalTest, NewLocalRef) {
   jstring s = env_->NewStringUTF("");
-  ASSERT_TRUE(s != NULL);
+  ASSERT_NE(s, nullptr);
   jobject o = env_->NewLocalRef(s);
-  EXPECT_TRUE(o != NULL);
-  EXPECT_TRUE(o != s);
+  EXPECT_NE(o, nullptr);
+  EXPECT_NE(o, s);
 
   EXPECT_EQ(JNILocalRefType, env_->GetObjectRefType(o));
 }
 
-TEST_F(JniInternalTest, DeleteLocalRef_NULL) {
-  env_->DeleteLocalRef(NULL);
+TEST_F(JniInternalTest, DeleteLocalRef_nullptr) {
+  env_->DeleteLocalRef(nullptr);
 }
 
 TEST_F(JniInternalTest, DeleteLocalRef) {
   jstring s = env_->NewStringUTF("");
-  ASSERT_TRUE(s != NULL);
+  ASSERT_NE(s, nullptr);
   env_->DeleteLocalRef(s);
 
   // Currently, deleting an already-deleted reference is just a CheckJNI warning.
@@ -937,9 +1286,9 @@
   }
 
   s = env_->NewStringUTF("");
-  ASSERT_TRUE(s != NULL);
+  ASSERT_NE(s, nullptr);
   jobject o = env_->NewLocalRef(s);
-  ASSERT_TRUE(o != NULL);
+  ASSERT_NE(o, nullptr);
 
   env_->DeleteLocalRef(s);
   env_->DeleteLocalRef(o);
@@ -951,7 +1300,7 @@
   // Android historically treated it, and it's how the RI treats it. It's also the more useful
   // interpretation!
   ASSERT_EQ(JNI_OK, env_->PushLocalFrame(0));
-  env_->PopLocalFrame(NULL);
+  env_->PopLocalFrame(nullptr);
 
   // Negative capacities are not allowed.
   ASSERT_EQ(JNI_ERR, env_->PushLocalFrame(-1));
@@ -962,7 +1311,7 @@
 
 TEST_F(JniInternalTest, PushLocalFrame_PopLocalFrame) {
   jobject original = env_->NewStringUTF("");
-  ASSERT_TRUE(original != NULL);
+  ASSERT_NE(original, nullptr);
 
   jobject outer;
   jobject inner1, inner2;
@@ -988,7 +1337,7 @@
     // gets a new local reference...
     EXPECT_EQ(JNIInvalidRefType, env_->GetObjectRefType(inner2));
 
-    env_->PopLocalFrame(NULL);
+    env_->PopLocalFrame(nullptr);
   }
   EXPECT_EQ(JNILocalRefType, env_->GetObjectRefType(original));
   EXPECT_EQ(JNIInvalidRefType, env_->GetObjectRefType(outer));
@@ -996,30 +1345,30 @@
   EXPECT_EQ(JNIInvalidRefType, env_->GetObjectRefType(inner2));
 }
 
-TEST_F(JniInternalTest, NewGlobalRef_NULL) {
-  EXPECT_TRUE(env_->NewGlobalRef(NULL) == NULL);
+TEST_F(JniInternalTest, NewGlobalRef_nullptr) {
+  EXPECT_EQ(env_->NewGlobalRef(nullptr), nullptr);
 }
 
 TEST_F(JniInternalTest, NewGlobalRef) {
   jstring s = env_->NewStringUTF("");
-  ASSERT_TRUE(s != NULL);
+  ASSERT_NE(s, nullptr);
   jobject o = env_->NewGlobalRef(s);
-  EXPECT_TRUE(o != NULL);
-  EXPECT_TRUE(o != s);
+  EXPECT_NE(o, nullptr);
+  EXPECT_NE(o, s);
 
-  // TODO: check that o is a global reference.
+  EXPECT_EQ(env_->GetObjectRefType(o), JNIGlobalRefType);
 }
 
-TEST_F(JniInternalTest, DeleteGlobalRef_NULL) {
-  env_->DeleteGlobalRef(NULL);
+TEST_F(JniInternalTest, DeleteGlobalRef_nullptr) {
+  env_->DeleteGlobalRef(nullptr);
 }
 
 TEST_F(JniInternalTest, DeleteGlobalRef) {
   jstring s = env_->NewStringUTF("");
-  ASSERT_TRUE(s != NULL);
+  ASSERT_NE(s, nullptr);
 
   jobject o = env_->NewGlobalRef(s);
-  ASSERT_TRUE(o != NULL);
+  ASSERT_NE(o, nullptr);
   env_->DeleteGlobalRef(o);
 
   // Currently, deleting an already-deleted reference is just a CheckJNI warning.
@@ -1033,38 +1382,38 @@
   }
 
   jobject o1 = env_->NewGlobalRef(s);
-  ASSERT_TRUE(o1 != NULL);
+  ASSERT_NE(o1, nullptr);
   jobject o2 = env_->NewGlobalRef(s);
-  ASSERT_TRUE(o2 != NULL);
+  ASSERT_NE(o2, nullptr);
 
   env_->DeleteGlobalRef(o1);
   env_->DeleteGlobalRef(o2);
 }
 
-TEST_F(JniInternalTest, NewWeakGlobalRef_NULL) {
-  EXPECT_TRUE(env_->NewWeakGlobalRef(NULL) == NULL);
+TEST_F(JniInternalTest, NewWeakGlobalRef_nullptr) {
+  EXPECT_EQ(env_->NewWeakGlobalRef(nullptr),   nullptr);
 }
 
 TEST_F(JniInternalTest, NewWeakGlobalRef) {
   jstring s = env_->NewStringUTF("");
-  ASSERT_TRUE(s != NULL);
+  ASSERT_NE(s, nullptr);
   jobject o = env_->NewWeakGlobalRef(s);
-  EXPECT_TRUE(o != NULL);
-  EXPECT_TRUE(o != s);
+  EXPECT_NE(o, nullptr);
+  EXPECT_NE(o, s);
 
-  // TODO: check that o is a weak global reference.
+  EXPECT_EQ(env_->GetObjectRefType(o), JNIWeakGlobalRefType);
 }
 
-TEST_F(JniInternalTest, DeleteWeakGlobalRef_NULL) {
-  env_->DeleteWeakGlobalRef(NULL);
+TEST_F(JniInternalTest, DeleteWeakGlobalRef_nullptr) {
+  env_->DeleteWeakGlobalRef(nullptr);
 }
 
 TEST_F(JniInternalTest, DeleteWeakGlobalRef) {
   jstring s = env_->NewStringUTF("");
-  ASSERT_TRUE(s != NULL);
+  ASSERT_NE(s, nullptr);
 
   jobject o = env_->NewWeakGlobalRef(s);
-  ASSERT_TRUE(o != NULL);
+  ASSERT_NE(o, nullptr);
   env_->DeleteWeakGlobalRef(o);
 
   // Currently, deleting an already-deleted reference is just a CheckJNI warning.
@@ -1078,21 +1427,21 @@
   }
 
   jobject o1 = env_->NewWeakGlobalRef(s);
-  ASSERT_TRUE(o1 != NULL);
+  ASSERT_NE(o1, nullptr);
   jobject o2 = env_->NewWeakGlobalRef(s);
-  ASSERT_TRUE(o2 != NULL);
+  ASSERT_NE(o2, nullptr);
 
   env_->DeleteWeakGlobalRef(o1);
   env_->DeleteWeakGlobalRef(o2);
 }
 
 TEST_F(JniInternalTest, Throw) {
-  EXPECT_EQ(JNI_ERR, env_->Throw(NULL));
+  EXPECT_EQ(JNI_ERR, env_->Throw(nullptr));
 
   jclass exception_class = env_->FindClass("java/lang/RuntimeException");
-  ASSERT_TRUE(exception_class != NULL);
+  ASSERT_TRUE(exception_class != nullptr);
   jthrowable exception = reinterpret_cast<jthrowable>(env_->AllocObject(exception_class));
-  ASSERT_TRUE(exception != NULL);
+  ASSERT_TRUE(exception != nullptr);
 
   EXPECT_EQ(JNI_OK, env_->Throw(exception));
   EXPECT_TRUE(env_->ExceptionCheck());
@@ -1102,10 +1451,10 @@
 }
 
 TEST_F(JniInternalTest, ThrowNew) {
-  EXPECT_EQ(JNI_ERR, env_->Throw(NULL));
+  EXPECT_EQ(JNI_ERR, env_->Throw(nullptr));
 
   jclass exception_class = env_->FindClass("java/lang/RuntimeException");
-  ASSERT_TRUE(exception_class != NULL);
+  ASSERT_TRUE(exception_class != nullptr);
 
   jthrowable thrown_exception;
 
@@ -1115,7 +1464,7 @@
   env_->ExceptionClear();
   EXPECT_TRUE(env_->IsInstanceOf(thrown_exception, exception_class));
 
-  EXPECT_EQ(JNI_OK, env_->ThrowNew(exception_class, NULL));
+  EXPECT_EQ(JNI_OK, env_->ThrowNew(exception_class, nullptr));
   EXPECT_TRUE(env_->ExceptionCheck());
   thrown_exception = env_->ExceptionOccurred();
   env_->ExceptionClear();
@@ -1141,26 +1490,26 @@
   ASSERT_TRUE(started);
 
   jclass buffer_class = env_->FindClass("java/nio/Buffer");
-  ASSERT_TRUE(buffer_class != NULL);
+  ASSERT_NE(buffer_class, nullptr);
 
   char bytes[1024];
   jobject buffer = env_->NewDirectByteBuffer(bytes, sizeof(bytes));
-  ASSERT_TRUE(buffer != NULL);
+  ASSERT_NE(buffer, nullptr);
   ASSERT_TRUE(env_->IsInstanceOf(buffer, buffer_class));
-  ASSERT_TRUE(env_->GetDirectBufferAddress(buffer) == bytes);
-  ASSERT_TRUE(env_->GetDirectBufferCapacity(buffer) == sizeof(bytes));
+  ASSERT_EQ(env_->GetDirectBufferAddress(buffer), bytes);
+  ASSERT_EQ(env_->GetDirectBufferCapacity(buffer), static_cast<jlong>(sizeof(bytes)));
 }
 
 TEST_F(JniInternalTest, MonitorEnterExit) {
-  // Create an object to torture
+  // Create an object to torture.
   jclass object_class = env_->FindClass("java/lang/Object");
-  ASSERT_TRUE(object_class != NULL);
+  ASSERT_NE(object_class, nullptr);
   jobject object = env_->AllocObject(object_class);
-  ASSERT_TRUE(object != NULL);
+  ASSERT_NE(object, nullptr);
 
   // Expected class of exceptions
   jclass imse_class = env_->FindClass("java/lang/IllegalMonitorStateException");
-  ASSERT_TRUE(imse_class != NULL);
+  ASSERT_NE(imse_class, nullptr);
 
   jthrowable thrown_exception;
 
@@ -1197,13 +1546,13 @@
   env_->ExceptionClear();
   EXPECT_TRUE(env_->IsInstanceOf(thrown_exception, imse_class));
 
-  // It's an error to call MonitorEnter or MonitorExit on NULL.
+  // It's an error to call MonitorEnter or MonitorExit on nullptr.
   {
     CheckJniAbortCatcher check_jni_abort_catcher;
-    env_->MonitorEnter(NULL);
+    env_->MonitorEnter(nullptr);
     check_jni_abort_catcher.Check("in call to MonitorEnter");
 
-    env_->MonitorExit(NULL);
+    env_->MonitorExit(nullptr);
     check_jni_abort_catcher.Check("in call to MonitorExit");
   }
 }
@@ -1215,7 +1564,7 @@
 
   jint err = vm_->DetachCurrentThread();
   EXPECT_EQ(JNI_ERR, err);
-  vm_->AttachCurrentThread(&env_, NULL);  // need attached thread for CommonRuntimeTest::TearDown
+  vm_->AttachCurrentThread(&env_, nullptr);  // need attached thread for CommonRuntimeTest::TearDown
 }
 
 }  // namespace art
diff --git a/runtime/mirror/array.cc b/runtime/mirror/array.cc
index 139e2d0..552652c 100644
--- a/runtime/mirror/array.cc
+++ b/runtime/mirror/array.cc
@@ -26,7 +26,7 @@
 #include "object_array.h"
 #include "object_array-inl.h"
 #include "object_utils.h"
-#include "sirt_ref.h"
+#include "handle_scope-inl.h"
 #include "thread.h"
 #include "utils.h"
 
@@ -42,22 +42,25 @@
 // Recursively create an array with multiple dimensions.  Elements may be
 // Objects or primitive types.
 static Array* RecursiveCreateMultiArray(Thread* self,
-                                        const SirtRef<Class>& array_class, int current_dimension,
-                                        const SirtRef<mirror::IntArray>& dimensions)
+                                        const Handle<Class>& array_class, int current_dimension,
+                                        const Handle<mirror::IntArray>& dimensions)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   int32_t array_length = dimensions->Get(current_dimension);
-  SirtRef<Array> new_array(self, Array::Alloc<true>(self, array_class.get(), array_length,
-                                                    array_class->GetComponentSize(),
-                                                    Runtime::Current()->GetHeap()->GetCurrentAllocator()));
-  if (UNLIKELY(new_array.get() == nullptr)) {
+  StackHandleScope<1> hs(self);
+  Handle<Array> new_array(
+      hs.NewHandle(
+          Array::Alloc<true>(self, array_class.Get(), array_length, array_class->GetComponentSize(),
+                             Runtime::Current()->GetHeap()->GetCurrentAllocator())));
+  if (UNLIKELY(new_array.Get() == nullptr)) {
     CHECK(self->IsExceptionPending());
     return nullptr;
   }
   if (current_dimension + 1 < dimensions->GetLength()) {
     // Create a new sub-array in every element of the array.
     for (int32_t i = 0; i < array_length; i++) {
-      SirtRef<mirror::Class> sirt_component_type(self, array_class->GetComponentType());
-      Array* sub_array = RecursiveCreateMultiArray(self, sirt_component_type,
+      StackHandleScope<1> hs(self);
+      Handle<mirror::Class> h_component_type(hs.NewHandle(array_class->GetComponentType()));
+      Array* sub_array = RecursiveCreateMultiArray(self, h_component_type,
                                                    current_dimension + 1, dimensions);
       if (UNLIKELY(sub_array == nullptr)) {
         CHECK(self->IsExceptionPending());
@@ -67,11 +70,11 @@
       new_array->AsObjectArray<Array>()->Set<false, false>(i, sub_array);
     }
   }
-  return new_array.get();
+  return new_array.Get();
 }
 
-Array* Array::CreateMultiArray(Thread* self, const SirtRef<Class>& element_class,
-                               const SirtRef<IntArray>& dimensions) {
+Array* Array::CreateMultiArray(Thread* self, const Handle<Class>& element_class,
+                               const Handle<IntArray>& dimensions) {
   // Verify dimensions.
   //
   // The caller is responsible for verifying that "dimArray" is non-null
@@ -90,15 +93,16 @@
 
   // Find/generate the array class.
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  SirtRef<mirror::Class> array_class(self,
-                                     class_linker->FindArrayClass(self, element_class.get()));
-  if (UNLIKELY(array_class.get() == nullptr)) {
+  StackHandleScope<1> hs(self);
+  Handle<mirror::Class> array_class(
+      hs.NewHandle(class_linker->FindArrayClass(self, element_class.Get())));
+  if (UNLIKELY(array_class.Get() == nullptr)) {
     CHECK(self->IsExceptionPending());
     return nullptr;
   }
   for (int32_t i = 1; i < dimensions->GetLength(); ++i) {
-    array_class.reset(class_linker->FindArrayClass(self, array_class.get()));
-    if (UNLIKELY(array_class.get() == nullptr)) {
+    array_class.Assign(class_linker->FindArrayClass(self, array_class.Get()));
+    if (UNLIKELY(array_class.Get() == nullptr)) {
       CHECK(self->IsExceptionPending());
       return nullptr;
     }
diff --git a/runtime/mirror/array.h b/runtime/mirror/array.h
index eead4eb..1b8106e 100644
--- a/runtime/mirror/array.h
+++ b/runtime/mirror/array.h
@@ -23,7 +23,7 @@
 
 namespace art {
 
-template<class T> class SirtRef;
+template<class T> class Handle;
 
 namespace mirror {
 
@@ -38,8 +38,8 @@
                       bool fill_usable = false)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  static Array* CreateMultiArray(Thread* self, const SirtRef<Class>& element_class,
-                                 const SirtRef<IntArray>& dimensions)
+  static Array* CreateMultiArray(Thread* self, const Handle<Class>& element_class,
+                                 const Handle<IntArray>& dimensions)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
@@ -155,14 +155,19 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   static void SetArrayClass(Class* array_class) {
-    CHECK(array_class_ == NULL);
-    CHECK(array_class != NULL);
+    CHECK(array_class_ == nullptr);
+    CHECK(array_class != nullptr);
     array_class_ = array_class;
   }
 
+  static Class* GetArrayClass() {
+    DCHECK(array_class_ != nullptr);
+    return array_class_;
+  }
+
   static void ResetArrayClass() {
-    CHECK(array_class_ != NULL);
-    array_class_ = NULL;
+    CHECK(array_class_ != nullptr);
+    array_class_ = nullptr;
   }
 
   static void VisitRoots(RootCallback* callback, void* arg)
diff --git a/runtime/mirror/art_field.cc b/runtime/mirror/art_field.cc
index 8eb30f9..86c5c3f 100644
--- a/runtime/mirror/art_field.cc
+++ b/runtime/mirror/art_field.cc
@@ -29,7 +29,7 @@
 namespace art {
 namespace mirror {
 
-// TODO: get global references for these
+// TODO: Get global references for these
 Class* ArtField::java_lang_reflect_ArtField_ = NULL;
 
 ArtField* ArtField::FromReflectedField(const ScopedObjectAccess& soa, jobject jlr_field) {
diff --git a/runtime/mirror/art_method-inl.h b/runtime/mirror/art_method-inl.h
index fb9a09a..c3e2d22 100644
--- a/runtime/mirror/art_method-inl.h
+++ b/runtime/mirror/art_method-inl.h
@@ -23,7 +23,8 @@
 #include "entrypoints/entrypoint_utils.h"
 #include "object_array.h"
 #include "oat.h"
-#include "runtime.h"
+#include "quick/quick_method_frame_info.h"
+#include "runtime-inl.h"
 
 namespace art {
 namespace mirror {
@@ -81,7 +82,7 @@
   if (code == nullptr) {
     return 0u;
   }
-  return reinterpret_cast<const OatMethodHeader*>(code)[-1].code_size_;
+  return reinterpret_cast<const OatQuickMethodHeader*>(code)[-1].code_size_;
 }
 
 inline bool ArtMethod::CheckIncompatibleClassChange(InvokeType type) {
@@ -201,6 +202,40 @@
       OFFSET_OF_OBJECT_MEMBER(ArtMethod, entry_point_from_jni_), native_method);
 }
 
+inline QuickMethodFrameInfo ArtMethod::GetQuickFrameInfo() {
+  if (UNLIKELY(IsPortableCompiled())) {
+    // Portable compiled dex bytecode or jni stub.
+    return QuickMethodFrameInfo(kStackAlignment, 0u, 0u);
+  }
+  Runtime* runtime = Runtime::Current();
+  if (UNLIKELY(IsAbstract()) || UNLIKELY(IsProxyMethod())) {
+    return runtime->GetCalleeSaveMethodFrameInfo(Runtime::kRefsAndArgs);
+  }
+  if (UNLIKELY(IsRuntimeMethod())) {
+    return runtime->GetRuntimeMethodFrameInfo(this);
+  }
+
+  const void* entry_point = runtime->GetInstrumentation()->GetQuickCodeFor(this);
+  // On failure, instead of nullptr we get the quick-generic-jni-trampoline for native method
+  // indicating the generic JNI, or the quick-to-interpreter-bridge (but not the trampoline)
+  // for non-native methods. And we really shouldn't see a failure for non-native methods here.
+  DCHECK(entry_point != GetQuickToInterpreterBridgeTrampoline(runtime->GetClassLinker()));
+  CHECK(entry_point != GetQuickToInterpreterBridge());
+
+  if (UNLIKELY(entry_point == GetQuickGenericJniTrampoline())) {
+    // Generic JNI frame.
+    DCHECK(IsNative());
+    uint32_t handle_refs = MethodHelper(this).GetNumberOfReferenceArgsWithoutReceiver() + 1;
+    size_t scope_size = HandleScope::GetAlignedHandleScopeSize(handle_refs);
+    QuickMethodFrameInfo callee_info = runtime->GetCalleeSaveMethodFrameInfo(Runtime::kRefsAndArgs);
+    return QuickMethodFrameInfo(callee_info.FrameSizeInBytes() + scope_size,
+                                callee_info.CoreSpillMask(), callee_info.FpSpillMask());
+  }
+
+  const void* code_pointer = EntryPointToCodePointer(entry_point);
+  return reinterpret_cast<const OatQuickMethodHeader*>(code_pointer)[-1].frame_info_;
+}
+
 }  // namespace mirror
 }  // namespace art
 
diff --git a/runtime/mirror/art_method.cc b/runtime/mirror/art_method.cc
index 4275f25..495ae2d 100644
--- a/runtime/mirror/art_method.cc
+++ b/runtime/mirror/art_method.cc
@@ -230,14 +230,15 @@
   return 0;
 }
 
-uint32_t ArtMethod::FindCatchBlock(SirtRef<Class>& exception_type, uint32_t dex_pc,
-                                   bool* has_no_move_exception) {
+uint32_t ArtMethod::FindCatchBlock(Handle<Class>& exception_type, uint32_t dex_pc,
+                                   bool* has_no_move_exception, bool* exc_changed) {
   MethodHelper mh(this);
   const DexFile::CodeItem* code_item = mh.GetCodeItem();
   // Set aside the exception while we resolve its type.
   Thread* self = Thread::Current();
   ThrowLocation throw_location;
-  SirtRef<mirror::Throwable> exception(self, self->GetException(&throw_location));
+  StackHandleScope<1> hs(self);
+  Handle<mirror::Throwable> exception(hs.NewHandle(self->GetException(&throw_location)));
   self->ClearException();
   // Default to handler not found.
   uint32_t found_dex_pc = DexFile::kDexNoIndex;
@@ -251,11 +252,18 @@
     }
     // Does this catch exception type apply?
     Class* iter_exception_type = mh.GetClassFromTypeIdx(iter_type_idx);
-    if (exception_type.get() == nullptr) {
-      self->ClearException();
+    if (iter_exception_type == nullptr) {
+      // Now have a NoClassDefFoundError as exception.
+      // Note: this is not RI behavior. RI would have failed when loading the class.
+      *exc_changed = true;
+
+      // TODO: Add old exception as suppressed.
       LOG(WARNING) << "Unresolved exception class when finding catch block: "
         << mh.GetTypeDescriptorFromTypeIdx(iter_type_idx);
-    } else if (iter_exception_type->IsAssignableFrom(exception_type.get())) {
+
+      // Return immediately.
+      return DexFile::kDexNoIndex;
+    } else if (iter_exception_type->IsAssignableFrom(exception_type.Get())) {
       found_dex_pc = it.GetHandlerAddress();
       break;
     }
@@ -266,8 +274,8 @@
     *has_no_move_exception = (first_catch_instr->Opcode() != Instruction::MOVE_EXCEPTION);
   }
   // Put the exception back.
-  if (exception.get() != nullptr) {
-    self->SetException(throw_location, exception.get());
+  if (exception.Get() != nullptr) {
+    self->SetException(throw_location, exception.Get());
   }
   return found_dex_pc;
 }
@@ -389,7 +397,7 @@
   if (code == nullptr) {
     return nullptr;
   }
-  uint32_t offset = reinterpret_cast<const OatMethodHeader*>(code)[-1].mapping_table_offset_;
+  uint32_t offset = reinterpret_cast<const OatQuickMethodHeader*>(code)[-1].mapping_table_offset_;
   if (UNLIKELY(offset == 0u)) {
     return nullptr;
   }
@@ -401,7 +409,7 @@
   if (code == nullptr) {
     return nullptr;
   }
-  uint32_t offset = reinterpret_cast<const OatMethodHeader*>(code)[-1].vmap_table_offset_;
+  uint32_t offset = reinterpret_cast<const OatQuickMethodHeader*>(code)[-1].vmap_table_offset_;
   if (UNLIKELY(offset == 0u)) {
     return nullptr;
   }
diff --git a/runtime/mirror/art_method.h b/runtime/mirror/art_method.h
index 71f0210..3950a98 100644
--- a/runtime/mirror/art_method.h
+++ b/runtime/mirror/art_method.h
@@ -23,6 +23,7 @@
 #include "modifiers.h"
 #include "object.h"
 #include "object_callbacks.h"
+#include "quick/quick_method_frame_info.h"
 
 namespace art {
 
@@ -318,25 +319,20 @@
 
   template <bool kCheckFrameSize = true>
   uint32_t GetFrameSizeInBytes() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    uint32_t result = GetField32(OFFSET_OF_OBJECT_MEMBER(ArtMethod, quick_frame_size_in_bytes_));
+    uint32_t result = GetQuickFrameInfo().FrameSizeInBytes();
     if (kCheckFrameSize) {
       DCHECK_LE(static_cast<size_t>(kStackAlignment), result);
     }
     return result;
   }
 
-  void SetFrameSizeInBytes(size_t new_frame_size_in_bytes)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    // Not called within a transaction.
-    SetField32<false>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, quick_frame_size_in_bytes_),
-                      new_frame_size_in_bytes);
-  }
+  QuickMethodFrameInfo GetQuickFrameInfo() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   size_t GetReturnPcOffsetInBytes() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     return GetFrameSizeInBytes() - kPointerSize;
   }
 
-  size_t GetSirtOffsetInBytes() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  size_t GetHandleScopeOffsetInBytes() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     return kPointerSize;
   }
 
@@ -362,26 +358,6 @@
     return OFFSET_OF_OBJECT_MEMBER(ArtMethod, method_index_);
   }
 
-  uint32_t GetCoreSpillMask() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return GetField32(OFFSET_OF_OBJECT_MEMBER(ArtMethod, quick_core_spill_mask_));
-  }
-
-  void SetCoreSpillMask(uint32_t core_spill_mask) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    // Computed during compilation.
-    // Not called within a transaction.
-    SetField32<false>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, quick_core_spill_mask_), core_spill_mask);
-  }
-
-  uint32_t GetFpSpillMask() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return GetField32(OFFSET_OF_OBJECT_MEMBER(ArtMethod, quick_fp_spill_mask_));
-  }
-
-  void SetFpSpillMask(uint32_t fp_spill_mask) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    // Computed during compilation.
-    // Not called within a transaction.
-    SetField32<false>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, quick_fp_spill_mask_), fp_spill_mask);
-  }
-
   // Is this a CalleSaveMethod or ResolutionMethod and therefore doesn't adhere to normal
   // conventions for a method of managed code. Returns false for Proxy methods.
   bool IsRuntimeMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -405,8 +381,11 @@
   // Find the catch block for the given exception type and dex_pc. When a catch block is found,
   // indicates whether the found catch block is responsible for clearing the exception or whether
   // a move-exception instruction is present.
-  uint32_t FindCatchBlock(SirtRef<Class>& exception_type, uint32_t dex_pc,
-                          bool* has_no_move_exception)
+  // In the process of finding a catch block we might trigger resolution errors. This is flagged
+  // by exc_changed, which indicates that a different exception is now stored in the thread and
+  // should be reloaded.
+  uint32_t FindCatchBlock(Handle<Class>& exception_type, uint32_t dex_pc,
+                          bool* has_no_move_exception, bool* exc_changed)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   static void SetClass(Class* java_lang_reflect_ArtMethod);
@@ -474,20 +453,6 @@
   // ifTable.
   uint32_t method_index_;
 
-  // --- Quick compiler meta-data. ---
-  // TODO: merge and place in native heap, such as done with the code size.
-
-  // Bit map of spilled machine registers.
-  uint32_t quick_core_spill_mask_;
-
-  // Bit map of spilled floating point machine registers.
-  uint32_t quick_fp_spill_mask_;
-
-  // Fixed frame size for this method when executed.
-  uint32_t quick_frame_size_in_bytes_;
-
-  // --- End of quick compiler meta-data. ---
-
   static Class* java_lang_reflect_ArtMethod_;
 
  private:
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index ff63782..15b69f3 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -28,7 +28,7 @@
 #include "object_array-inl.h"
 #include "object_utils.h"
 #include "runtime.h"
-#include "sirt_ref.h"
+#include "handle_scope-inl.h"
 #include "thread.h"
 #include "throwable.h"
 #include "utils.h"
@@ -77,20 +77,13 @@
         << "Attempt to set as erroneous an already erroneous class " << PrettyClass(this);
 
     // Stash current exception.
-    SirtRef<mirror::Object> old_throw_this_object(self, NULL);
-    SirtRef<mirror::ArtMethod> old_throw_method(self, NULL);
-    SirtRef<mirror::Throwable> old_exception(self, NULL);
-    uint32_t old_throw_dex_pc;
-    {
-      ThrowLocation old_throw_location;
-      mirror::Throwable* old_exception_obj = self->GetException(&old_throw_location);
-      old_throw_this_object.reset(old_throw_location.GetThis());
-      old_throw_method.reset(old_throw_location.GetMethod());
-      old_exception.reset(old_exception_obj);
-      old_throw_dex_pc = old_throw_location.GetDexPc();
-      self->ClearException();
-    }
-    CHECK(old_exception.get() != NULL);
+    StackHandleScope<3> hs(self);
+    ThrowLocation old_throw_location;
+    Handle<mirror::Throwable> old_exception(hs.NewHandle(self->GetException(&old_throw_location)));
+    CHECK(old_exception.Get() != nullptr);
+    Handle<mirror::Object> old_throw_this_object(hs.NewHandle(old_throw_location.GetThis()));
+    Handle<mirror::ArtMethod> old_throw_method(hs.NewHandle(old_throw_location.GetMethod()));
+    uint32_t old_throw_dex_pc = old_throw_location.GetDexPc();
 
     // clear exception to call FindSystemClass
     self->ClearException();
@@ -107,10 +100,10 @@
     }
 
     // Restore exception.
-    ThrowLocation gc_safe_throw_location(old_throw_this_object.get(), old_throw_method.get(),
+    ThrowLocation gc_safe_throw_location(old_throw_this_object.Get(), old_throw_method.Get(),
                                          old_throw_dex_pc);
 
-    self->SetException(gc_safe_throw_location, old_exception.get());
+    self->SetException(gc_safe_throw_location, old_exception.Get());
   }
   CHECK(sizeof(Status) == sizeof(uint32_t)) << PrettyClass(this);
   if (Runtime::Current()->IsActiveTransaction()) {
@@ -149,7 +142,8 @@
     return name;
   }
   Thread* self = Thread::Current();
-  SirtRef<mirror::Class> sirt_c(self, this);
+  StackHandleScope<1> hs(self);
+  Handle<mirror::Class> handle_c(hs.NewHandle(this));
   std::string descriptor(ClassHelper(this).GetDescriptor());
   if ((descriptor[0] != 'L') && (descriptor[0] != '[')) {
     // The descriptor indicates that this is the class for
@@ -179,7 +173,7 @@
     std::replace(descriptor.begin(), descriptor.end(), '/', '.');
     name = String::AllocFromModifiedUtf8(self, descriptor.c_str());
   }
-  sirt_c->SetName(name);
+  handle_c->SetName(name);
   return name;
 }
 
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 1f393db..92b999e 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -429,7 +429,7 @@
            ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
   bool IsVariableSize() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     // Classes and arrays vary in size, and so the object_size_ field cannot
-    // be used to get their instance size
+    // be used to Get their instance size
     return IsClassClass<kVerifyFlags, kReadBarrierOption>() ||
         IsArrayClass<kVerifyFlags, kReadBarrierOption>();
   }
diff --git a/runtime/mirror/dex_cache_test.cc b/runtime/mirror/dex_cache_test.cc
index fef1f9b..3d28dc6 100644
--- a/runtime/mirror/dex_cache_test.cc
+++ b/runtime/mirror/dex_cache_test.cc
@@ -23,7 +23,7 @@
 #include "gc/heap.h"
 #include "mirror/object_array-inl.h"
 #include "mirror/object-inl.h"
-#include "sirt_ref.h"
+#include "handle_scope-inl.h"
 
 namespace art {
 namespace mirror {
@@ -32,9 +32,10 @@
 
 TEST_F(DexCacheTest, Open) {
   ScopedObjectAccess soa(Thread::Current());
-  SirtRef<DexCache> dex_cache(soa.Self(), class_linker_->AllocDexCache(soa.Self(),
-                                                                       *java_lang_dex_file_));
-  ASSERT_TRUE(dex_cache.get() != NULL);
+  StackHandleScope<1> hs(soa.Self());
+  Handle<DexCache> dex_cache(
+      hs.NewHandle(class_linker_->AllocDexCache(soa.Self(), *java_lang_dex_file_)));
+  ASSERT_TRUE(dex_cache.Get() != NULL);
 
   EXPECT_EQ(java_lang_dex_file_->NumStringIds(), dex_cache->NumStrings());
   EXPECT_EQ(java_lang_dex_file_->NumTypeIds(),   dex_cache->NumResolvedTypes());
diff --git a/runtime/mirror/object.cc b/runtime/mirror/object.cc
index 2f775bc..04905a5 100644
--- a/runtime/mirror/object.cc
+++ b/runtime/mirror/object.cc
@@ -32,7 +32,7 @@
 #include "object_array-inl.h"
 #include "object_utils.h"
 #include "runtime.h"
-#include "sirt_ref.h"
+#include "handle_scope-inl.h"
 #include "throwable.h"
 #include "well_known_classes.h"
 
@@ -100,19 +100,19 @@
 // An allocation pre-fence visitor that copies the object.
 class CopyObjectVisitor {
  public:
-  explicit CopyObjectVisitor(Thread* self, SirtRef<Object>* orig, size_t num_bytes)
+  explicit CopyObjectVisitor(Thread* self, Handle<Object>* orig, size_t num_bytes)
       : self_(self), orig_(orig), num_bytes_(num_bytes) {
   }
 
   void operator()(Object* obj, size_t usable_size) const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     UNUSED(usable_size);
-    CopyObject(self_, obj, orig_->get(), num_bytes_);
+    CopyObject(self_, obj, orig_->Get(), num_bytes_);
   }
 
  private:
   Thread* const self_;
-  SirtRef<Object>* const orig_;
+  Handle<Object>* const orig_;
   const size_t num_bytes_;
   DISALLOW_COPY_AND_ASSIGN(CopyObjectVisitor);
 };
@@ -123,7 +123,8 @@
   // be wrong.
   gc::Heap* heap = Runtime::Current()->GetHeap();
   size_t num_bytes = SizeOf();
-  SirtRef<Object> this_object(self, this);
+  StackHandleScope<1> hs(self);
+  Handle<Object> this_object(hs.NewHandle(this));
   Object* copy;
   CopyObjectVisitor visitor(self, &this_object, num_bytes);
   if (heap->IsMovableObject(this)) {
@@ -163,10 +164,11 @@
       case LockWord::kThinLocked: {
         // Inflate the thin lock to a monitor and stick the hash code inside of the monitor.
         Thread* self = Thread::Current();
-        SirtRef<mirror::Object> sirt_this(self, current_this);
-        Monitor::InflateThinLocked(self, sirt_this, lw, GenerateIdentityHashCode());
+        StackHandleScope<1> hs(self);
+        Handle<mirror::Object> h_this(hs.NewHandle(current_this));
+        Monitor::InflateThinLocked(self, h_this, lw, GenerateIdentityHashCode());
         // A GC may have occurred when we switched to kBlocked.
-        current_this = sirt_this.get();
+        current_this = h_this.Get();
         break;
       }
       case LockWord::kFatLocked: {
diff --git a/runtime/mirror/object_array-inl.h b/runtime/mirror/object_array-inl.h
index 203a6b2..942a271 100644
--- a/runtime/mirror/object_array-inl.h
+++ b/runtime/mirror/object_array-inl.h
@@ -23,7 +23,7 @@
 #include "mirror/art_field.h"
 #include "mirror/class.h"
 #include "runtime.h"
-#include "sirt_ref.h"
+#include "handle_scope-inl.h"
 #include "thread.h"
 #include <string>
 
@@ -118,7 +118,7 @@
                                               int32_t src_pos, int32_t count) {
   if (kIsDebugBuild) {
     for (int i = 0; i < count; ++i) {
-      // The Get will perform the VerifyObject.
+      // The get will perform the VerifyObject.
       src->GetWithoutChecks(src_pos + i);
     }
   }
@@ -150,7 +150,7 @@
   Runtime::Current()->GetHeap()->WriteBarrierArray(this, dst_pos, count);
   if (kIsDebugBuild) {
     for (int i = 0; i < count; ++i) {
-      // The Get will perform the VerifyObject.
+      // The get will perform the VerifyObject.
       GetWithoutChecks(dst_pos + i);
     }
   }
@@ -161,7 +161,7 @@
                                              int32_t src_pos, int32_t count) {
   if (kIsDebugBuild) {
     for (int i = 0; i < count; ++i) {
-      // The Get will perform the VerifyObject.
+      // The get will perform the VerifyObject.
       src->GetWithoutChecks(src_pos + i);
     }
   }
@@ -182,7 +182,7 @@
   Runtime::Current()->GetHeap()->WriteBarrierArray(this, dst_pos, count);
   if (kIsDebugBuild) {
     for (int i = 0; i < count; ++i) {
-      // The Get will perform the VerifyObject.
+      // The get will perform the VerifyObject.
       GetWithoutChecks(dst_pos + i);
     }
   }
@@ -244,13 +244,14 @@
 inline ObjectArray<T>* ObjectArray<T>::CopyOf(Thread* self, int32_t new_length) {
   DCHECK_GE(new_length, 0);
   // We may get copied by a compacting GC.
-  SirtRef<ObjectArray<T> > sirt_this(self, this);
+  StackHandleScope<1> hs(self);
+  Handle<ObjectArray<T> > h_this(hs.NewHandle(this));
   gc::Heap* heap = Runtime::Current()->GetHeap();
   gc::AllocatorType allocator_type = heap->IsMovableObject(this) ? heap->GetCurrentAllocator() :
       heap->GetCurrentNonMovingAllocator();
   ObjectArray<T>* new_array = Alloc(self, GetClass(), new_length, allocator_type);
   if (LIKELY(new_array != nullptr)) {
-    new_array->AssignableMemcpy(0, sirt_this.get(), 0, std::min(sirt_this->GetLength(), new_length));
+    new_array->AssignableMemcpy(0, h_this.Get(), 0, std::min(h_this->GetLength(), new_length));
   }
   return new_array;
 }
diff --git a/runtime/mirror/object_test.cc b/runtime/mirror/object_test.cc
index c494f13..537fe85 100644
--- a/runtime/mirror/object_test.cc
+++ b/runtime/mirror/object_test.cc
@@ -34,7 +34,7 @@
 #include "art_method-inl.h"
 #include "object-inl.h"
 #include "object_array-inl.h"
-#include "sirt_ref.h"
+#include "handle_scope-inl.h"
 #include "string-inl.h"
 #include "UniquePtr.h"
 
@@ -56,7 +56,9 @@
     }
 
     Thread* self = Thread::Current();
-    SirtRef<String> string(self, String::AllocFromModifiedUtf8(self, expected_utf16_length, utf8_in));
+    StackHandleScope<1> hs(self);
+    Handle<String> string(
+        hs.NewHandle(String::AllocFromModifiedUtf8(self, expected_utf16_length, utf8_in)));
     ASSERT_EQ(expected_utf16_length, string->GetLength());
     ASSERT_TRUE(string->GetCharArray() != NULL);
     ASSERT_TRUE(string->GetCharArray()->GetData() != NULL);
@@ -102,8 +104,9 @@
 
 TEST_F(ObjectTest, Clone) {
   ScopedObjectAccess soa(Thread::Current());
-  SirtRef<ObjectArray<Object> > a1(soa.Self(),
-                                   class_linker_->AllocObjectArray<Object>(soa.Self(), 256));
+  StackHandleScope<1> hs(soa.Self());
+  Handle<ObjectArray<Object>> a1(
+      hs.NewHandle(class_linker_->AllocObjectArray<Object>(soa.Self(), 256)));
   size_t s1 = a1->SizeOf();
   Object* clone = a1->Clone(soa.Self());
   EXPECT_EQ(s1, clone->SizeOf());
@@ -112,17 +115,18 @@
 
 TEST_F(ObjectTest, AllocObjectArray) {
   ScopedObjectAccess soa(Thread::Current());
-  SirtRef<ObjectArray<Object> > oa(soa.Self(),
-                                   class_linker_->AllocObjectArray<Object>(soa.Self(), 2));
+  StackHandleScope<1> hs(soa.Self());
+  Handle<ObjectArray<Object> > oa(
+      hs.NewHandle(class_linker_->AllocObjectArray<Object>(soa.Self(), 2)));
   EXPECT_EQ(2, oa->GetLength());
   EXPECT_TRUE(oa->Get(0) == NULL);
   EXPECT_TRUE(oa->Get(1) == NULL);
-  oa->Set<false>(0, oa.get());
-  EXPECT_TRUE(oa->Get(0) == oa.get());
+  oa->Set<false>(0, oa.Get());
+  EXPECT_TRUE(oa->Get(0) == oa.Get());
   EXPECT_TRUE(oa->Get(1) == NULL);
-  oa->Set<false>(1, oa.get());
-  EXPECT_TRUE(oa->Get(0) == oa.get());
-  EXPECT_TRUE(oa->Get(1) == oa.get());
+  oa->Set<false>(1, oa.Get());
+  EXPECT_TRUE(oa->Get(0) == oa.Get());
+  EXPECT_TRUE(oa->Get(1) == oa.Get());
 
   Class* aioobe = class_linker_->FindSystemClass(soa.Self(),
                                                  "Ljava/lang/ArrayIndexOutOfBoundsException;");
@@ -149,20 +153,22 @@
 TEST_F(ObjectTest, AllocArray) {
   ScopedObjectAccess soa(Thread::Current());
   Class* c = class_linker_->FindSystemClass(soa.Self(), "[I");
-  SirtRef<Array> a(soa.Self(), Array::Alloc<true>(soa.Self(), c, 1, c->GetComponentSize(),
-                                                  Runtime::Current()->GetHeap()->GetCurrentAllocator()));
+  StackHandleScope<1> hs(soa.Self());
+  Handle<Array> a(
+      hs.NewHandle(Array::Alloc<true>(soa.Self(), c, 1, c->GetComponentSize(),
+                                      Runtime::Current()->GetHeap()->GetCurrentAllocator())));
   EXPECT_TRUE(c == a->GetClass());
   EXPECT_EQ(1, a->GetLength());
 
   c = class_linker_->FindSystemClass(soa.Self(), "[Ljava/lang/Object;");
-  a.reset(Array::Alloc<true>(soa.Self(), c, 1, c->GetComponentSize(),
-                             Runtime::Current()->GetHeap()->GetCurrentAllocator()));
+  a.Assign(Array::Alloc<true>(soa.Self(), c, 1, c->GetComponentSize(),
+                              Runtime::Current()->GetHeap()->GetCurrentAllocator()));
   EXPECT_TRUE(c == a->GetClass());
   EXPECT_EQ(1, a->GetLength());
 
   c = class_linker_->FindSystemClass(soa.Self(), "[[Ljava/lang/Object;");
-  a.reset(Array::Alloc<true>(soa.Self(), c, 1, c->GetComponentSize(),
-                             Runtime::Current()->GetHeap()->GetCurrentAllocator()));
+  a.Assign(Array::Alloc<true>(soa.Self(), c, 1, c->GetComponentSize(),
+                              Runtime::Current()->GetHeap()->GetCurrentAllocator()));
   EXPECT_TRUE(c == a->GetClass());
   EXPECT_EQ(1, a->GetLength());
 }
@@ -170,28 +176,27 @@
 TEST_F(ObjectTest, AllocArray_FillUsable) {
   ScopedObjectAccess soa(Thread::Current());
   Class* c = class_linker_->FindSystemClass(soa.Self(), "[B");
-  SirtRef<Array> a(soa.Self(), Array::Alloc<true>(soa.Self(), c, 1, c->GetComponentSize(),
-                                                  Runtime::Current()->GetHeap()->GetCurrentAllocator(),
-                                                  true));
+  StackHandleScope<1> hs(soa.Self());
+  Handle<Array> a(
+      hs.NewHandle(Array::Alloc<true>(soa.Self(), c, 1, c->GetComponentSize(),
+                                      Runtime::Current()->GetHeap()->GetCurrentAllocator(), true)));
   EXPECT_TRUE(c == a->GetClass());
   EXPECT_LE(1, a->GetLength());
 
   c = class_linker_->FindSystemClass(soa.Self(), "[I");
-  a.reset(Array::Alloc<true>(soa.Self(), c, 2, c->GetComponentSize(),
-                             Runtime::Current()->GetHeap()->GetCurrentAllocator(),
-                             true));
+  a.Assign(Array::Alloc<true>(soa.Self(), c, 2, c->GetComponentSize(),
+                              Runtime::Current()->GetHeap()->GetCurrentAllocator(), true));
   EXPECT_TRUE(c == a->GetClass());
   EXPECT_LE(2, a->GetLength());
 
   c = class_linker_->FindSystemClass(soa.Self(), "[Ljava/lang/Object;");
-  a.reset(Array::Alloc<true>(soa.Self(), c, 2, c->GetComponentSize(),
-                             Runtime::Current()->GetHeap()->GetCurrentAllocator(),
-                             true));
+  a.Assign(Array::Alloc<true>(soa.Self(), c, 2, c->GetComponentSize(),
+                              Runtime::Current()->GetHeap()->GetCurrentAllocator(), true));
   EXPECT_TRUE(c == a->GetClass());
   EXPECT_LE(2, a->GetLength());
 
   c = class_linker_->FindSystemClass(soa.Self(), "[[Ljava/lang/Object;");
-  a.reset(Array::Alloc<true>(soa.Self(), c, 2, c->GetComponentSize(),
+  a.Assign(Array::Alloc<true>(soa.Self(), c, 2, c->GetComponentSize(),
                              Runtime::Current()->GetHeap()->GetCurrentAllocator(), true));
   EXPECT_TRUE(c == a->GetClass());
   EXPECT_LE(2, a->GetLength());
@@ -273,8 +278,9 @@
 TEST_F(ObjectTest, CreateMultiArray) {
   ScopedObjectAccess soa(Thread::Current());
 
-  SirtRef<Class> c(soa.Self(), class_linker_->FindSystemClass(soa.Self(), "I"));
-  SirtRef<IntArray> dims(soa.Self(), IntArray::Alloc(soa.Self(), 1));
+  StackHandleScope<2> hs(soa.Self());
+  Handle<Class> c(hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "I")));
+  Handle<IntArray> dims(hs.NewHandle(IntArray::Alloc(soa.Self(), 1)));
   dims->Set<false>(0, 1);
   Array* multi = Array::CreateMultiArray(soa.Self(), c, dims);
   EXPECT_TRUE(multi->GetClass() == class_linker_->FindSystemClass(soa.Self(), "[I"));
@@ -287,7 +293,7 @@
             "java.lang.NegativeArraySizeException");
   soa.Self()->ClearException();
 
-  dims.reset(IntArray::Alloc(soa.Self(), 2));
+  dims.Assign(IntArray::Alloc(soa.Self(), 2));
   for (int i = 1; i < 20; ++i) {
     for (int j = 0; j < 20; ++j) {
       dims->Set<false>(0, i);
@@ -311,7 +317,8 @@
   const DexFile* dex_file = Runtime::Current()->GetCompileTimeClassPath(class_loader)[0];
   CHECK(dex_file != NULL);
 
-  SirtRef<mirror::ClassLoader> loader(soa.Self(), soa.Decode<ClassLoader*>(class_loader));
+  StackHandleScope<2> hs(soa.Self());
+  Handle<mirror::ClassLoader> loader(hs.NewHandle(soa.Decode<ClassLoader*>(class_loader)));
   Class* klass = class_linker_->FindClass(soa.Self(), "LStaticsFromCode;", loader);
   ArtMethod* clinit = klass->FindClassInitializer();
   const DexFile::StringId* klass_string_id = dex_file->FindStringId("LStaticsFromCode;");
@@ -339,9 +346,9 @@
   Object* s0 = field->GetObj(klass);
   EXPECT_TRUE(s0 != NULL);
 
-  SirtRef<CharArray> char_array(soa.Self(), CharArray::Alloc(soa.Self(), 0));
-  field->SetObj<false>(field->GetDeclaringClass(), char_array.get());
-  EXPECT_EQ(char_array.get(), field->GetObj(klass));
+  Handle<CharArray> char_array(hs.NewHandle(CharArray::Alloc(soa.Self(), 0)));
+  field->SetObj<false>(field->GetDeclaringClass(), char_array.Get());
+  EXPECT_EQ(char_array.Get(), field->GetObj(klass));
 
   field->SetObj<false>(field->GetDeclaringClass(), NULL);
   EXPECT_EQ(NULL, field->GetObj(klass));
@@ -375,7 +382,8 @@
 
 TEST_F(ObjectTest, StringEqualsUtf8) {
   ScopedObjectAccess soa(Thread::Current());
-  SirtRef<String> string(soa.Self(), String::AllocFromModifiedUtf8(soa.Self(), "android"));
+  StackHandleScope<2> hs(soa.Self());
+  Handle<String> string(hs.NewHandle(String::AllocFromModifiedUtf8(soa.Self(), "android")));
   EXPECT_TRUE(string->Equals("android"));
   EXPECT_FALSE(string->Equals("Android"));
   EXPECT_FALSE(string->Equals("ANDROID"));
@@ -383,46 +391,49 @@
   EXPECT_FALSE(string->Equals("and"));
   EXPECT_FALSE(string->Equals("androids"));
 
-  SirtRef<String> empty(soa.Self(), String::AllocFromModifiedUtf8(soa.Self(), ""));
+  Handle<String> empty(hs.NewHandle(String::AllocFromModifiedUtf8(soa.Self(), "")));
   EXPECT_TRUE(empty->Equals(""));
   EXPECT_FALSE(empty->Equals("a"));
 }
 
 TEST_F(ObjectTest, StringEquals) {
   ScopedObjectAccess soa(Thread::Current());
-  SirtRef<String> string(soa.Self(), String::AllocFromModifiedUtf8(soa.Self(), "android"));
-  SirtRef<String> string_2(soa.Self(), String::AllocFromModifiedUtf8(soa.Self(), "android"));
-  EXPECT_TRUE(string->Equals(string_2.get()));
+  StackHandleScope<3> hs(soa.Self());
+  Handle<String> string(hs.NewHandle(String::AllocFromModifiedUtf8(soa.Self(), "android")));
+  Handle<String> string_2(hs.NewHandle(String::AllocFromModifiedUtf8(soa.Self(), "android")));
+  EXPECT_TRUE(string->Equals(string_2.Get()));
   EXPECT_FALSE(string->Equals("Android"));
   EXPECT_FALSE(string->Equals("ANDROID"));
   EXPECT_FALSE(string->Equals(""));
   EXPECT_FALSE(string->Equals("and"));
   EXPECT_FALSE(string->Equals("androids"));
 
-  SirtRef<String> empty(soa.Self(), String::AllocFromModifiedUtf8(soa.Self(), ""));
+  Handle<String> empty(hs.NewHandle(String::AllocFromModifiedUtf8(soa.Self(), "")));
   EXPECT_TRUE(empty->Equals(""));
   EXPECT_FALSE(empty->Equals("a"));
 }
 
 TEST_F(ObjectTest, StringCompareTo) {
   ScopedObjectAccess soa(Thread::Current());
-  SirtRef<String> string(soa.Self(), String::AllocFromModifiedUtf8(soa.Self(), "android"));
-  SirtRef<String> string_2(soa.Self(), String::AllocFromModifiedUtf8(soa.Self(), "android"));
-  SirtRef<String> string_3(soa.Self(), String::AllocFromModifiedUtf8(soa.Self(), "Android"));
-  SirtRef<String> string_4(soa.Self(), String::AllocFromModifiedUtf8(soa.Self(), "and"));
-  SirtRef<String> string_5(soa.Self(), String::AllocFromModifiedUtf8(soa.Self(), ""));
-  EXPECT_EQ(0, string->CompareTo(string_2.get()));
-  EXPECT_LT(0, string->CompareTo(string_3.get()));
-  EXPECT_GT(0, string_3->CompareTo(string.get()));
-  EXPECT_LT(0, string->CompareTo(string_4.get()));
-  EXPECT_GT(0, string_4->CompareTo(string.get()));
-  EXPECT_LT(0, string->CompareTo(string_5.get()));
-  EXPECT_GT(0, string_5->CompareTo(string.get()));
+  StackHandleScope<5> hs(soa.Self());
+  Handle<String> string(hs.NewHandle(String::AllocFromModifiedUtf8(soa.Self(), "android")));
+  Handle<String> string_2(hs.NewHandle(String::AllocFromModifiedUtf8(soa.Self(), "android")));
+  Handle<String> string_3(hs.NewHandle(String::AllocFromModifiedUtf8(soa.Self(), "Android")));
+  Handle<String> string_4(hs.NewHandle(String::AllocFromModifiedUtf8(soa.Self(), "and")));
+  Handle<String> string_5(hs.NewHandle(String::AllocFromModifiedUtf8(soa.Self(), "")));
+  EXPECT_EQ(0, string->CompareTo(string_2.Get()));
+  EXPECT_LT(0, string->CompareTo(string_3.Get()));
+  EXPECT_GT(0, string_3->CompareTo(string.Get()));
+  EXPECT_LT(0, string->CompareTo(string_4.Get()));
+  EXPECT_GT(0, string_4->CompareTo(string.Get()));
+  EXPECT_LT(0, string->CompareTo(string_5.Get()));
+  EXPECT_GT(0, string_5->CompareTo(string.Get()));
 }
 
 TEST_F(ObjectTest, StringLength) {
   ScopedObjectAccess soa(Thread::Current());
-  SirtRef<String> string(soa.Self(), String::AllocFromModifiedUtf8(soa.Self(), "android"));
+  StackHandleScope<1> hs(soa.Self());
+  Handle<String> string(hs.NewHandle(String::AllocFromModifiedUtf8(soa.Self(), "android")));
   EXPECT_EQ(string->GetLength(), 7);
   EXPECT_EQ(string->GetUtfLength(), 7);
 
@@ -440,8 +451,9 @@
 
   jobject jclass_loader_1 = LoadDex("ProtoCompare");
   jobject jclass_loader_2 = LoadDex("ProtoCompare2");
-  SirtRef<ClassLoader> class_loader_1(soa.Self(), soa.Decode<ClassLoader*>(jclass_loader_1));
-  SirtRef<ClassLoader> class_loader_2(soa.Self(), soa.Decode<ClassLoader*>(jclass_loader_2));
+  StackHandleScope<2> 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)));
 
   Class* klass1 = linker->FindClass(soa.Self(), "LProtoCompare;", class_loader_1);
   ASSERT_TRUE(klass1 != NULL);
@@ -497,9 +509,10 @@
 
 TEST_F(ObjectTest, StringHashCode) {
   ScopedObjectAccess soa(Thread::Current());
-  SirtRef<String> empty(soa.Self(), String::AllocFromModifiedUtf8(soa.Self(), ""));
-  SirtRef<String> A(soa.Self(), String::AllocFromModifiedUtf8(soa.Self(), "A"));
-  SirtRef<String> ABC(soa.Self(), String::AllocFromModifiedUtf8(soa.Self(), "ABC"));
+  StackHandleScope<3> hs(soa.Self());
+  Handle<String> empty(hs.NewHandle(String::AllocFromModifiedUtf8(soa.Self(), "")));
+  Handle<String> A(hs.NewHandle(String::AllocFromModifiedUtf8(soa.Self(), "A")));
+  Handle<String> ABC(hs.NewHandle(String::AllocFromModifiedUtf8(soa.Self(), "ABC")));
 
   EXPECT_EQ(0, empty->GetHashCode());
   EXPECT_EQ(65, A->GetHashCode());
@@ -509,17 +522,18 @@
 TEST_F(ObjectTest, InstanceOf) {
   ScopedObjectAccess soa(Thread::Current());
   jobject jclass_loader = LoadDex("XandY");
-  SirtRef<ClassLoader> class_loader(soa.Self(), soa.Decode<ClassLoader*>(jclass_loader));
+  StackHandleScope<3> hs(soa.Self());
+  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 != NULL);
   ASSERT_TRUE(Y != NULL);
 
-  SirtRef<Object> x(soa.Self(), X->AllocObject(soa.Self()));
-  SirtRef<Object> y(soa.Self(), Y->AllocObject(soa.Self()));
-  ASSERT_TRUE(x.get() != NULL);
-  ASSERT_TRUE(y.get() != NULL);
+  Handle<Object> x(hs.NewHandle(X->AllocObject(soa.Self())));
+  Handle<Object> y(hs.NewHandle(Y->AllocObject(soa.Self())));
+  ASSERT_TRUE(x.Get() != NULL);
+  ASSERT_TRUE(y.Get() != NULL);
 
   EXPECT_TRUE(x->InstanceOf(X));
   EXPECT_FALSE(x->InstanceOf(Y));
@@ -543,7 +557,8 @@
 TEST_F(ObjectTest, IsAssignableFrom) {
   ScopedObjectAccess soa(Thread::Current());
   jobject jclass_loader = LoadDex("XandY");
-  SirtRef<ClassLoader> class_loader(soa.Self(), soa.Decode<ClassLoader*>(jclass_loader));
+  StackHandleScope<1> hs(soa.Self());
+  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);
 
@@ -580,7 +595,8 @@
 TEST_F(ObjectTest, IsAssignableFromArray) {
   ScopedObjectAccess soa(Thread::Current());
   jobject jclass_loader = LoadDex("XandY");
-  SirtRef<ClassLoader> class_loader(soa.Self(), soa.Decode<ClassLoader*>(jclass_loader));
+  StackHandleScope<1> hs(soa.Self());
+  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 != NULL);
@@ -632,8 +648,9 @@
 
 TEST_F(ObjectTest, FindInstanceField) {
   ScopedObjectAccess soa(Thread::Current());
-  SirtRef<String> s(soa.Self(), String::AllocFromModifiedUtf8(soa.Self(), "ABC"));
-  ASSERT_TRUE(s.get() != NULL);
+  StackHandleScope<1> hs(soa.Self());
+  Handle<String> s(hs.NewHandle(String::AllocFromModifiedUtf8(soa.Self(), "ABC")));
+  ASSERT_TRUE(s.Get() != NULL);
   Class* c = s->GetClass();
   ASSERT_TRUE(c != NULL);
 
@@ -665,8 +682,9 @@
 
 TEST_F(ObjectTest, FindStaticField) {
   ScopedObjectAccess soa(Thread::Current());
-  SirtRef<String> s(soa.Self(), String::AllocFromModifiedUtf8(soa.Self(), "ABC"));
-  ASSERT_TRUE(s.get() != NULL);
+  StackHandleScope<1> hs(soa.Self());
+  Handle<String> s(hs.NewHandle(String::AllocFromModifiedUtf8(soa.Self(), "ABC")));
+  ASSERT_TRUE(s.Get() != NULL);
   Class* c = s->GetClass();
   ASSERT_TRUE(c != NULL);
 
diff --git a/runtime/mirror/stack_trace_element.cc b/runtime/mirror/stack_trace_element.cc
index f220039..d8591cc 100644
--- a/runtime/mirror/stack_trace_element.cc
+++ b/runtime/mirror/stack_trace_element.cc
@@ -20,7 +20,7 @@
 #include "class-inl.h"
 #include "gc/accounting/card_table-inl.h"
 #include "object-inl.h"
-#include "sirt_ref-inl.h"
+#include "handle_scope-inl.h"
 #include "string.h"
 
 namespace art {
@@ -40,9 +40,9 @@
 }
 
 StackTraceElement* StackTraceElement::Alloc(Thread* self,
-                                            SirtRef<String>& declaring_class,
-                                            SirtRef<String>& method_name,
-                                            SirtRef<String>& file_name,
+                                            Handle<String>& declaring_class,
+                                            Handle<String>& method_name,
+                                            Handle<String>& file_name,
                                             int32_t line_number) {
   StackTraceElement* trace =
       down_cast<StackTraceElement*>(GetStackTraceElement()->AllocObject(self));
@@ -57,14 +57,14 @@
 }
 
 template<bool kTransactionActive>
-void StackTraceElement::Init(SirtRef<String>& declaring_class, SirtRef<String>& method_name,
-                             SirtRef<String>& file_name, int32_t line_number) {
+void StackTraceElement::Init(Handle<String>& declaring_class, Handle<String>& method_name,
+                             Handle<String>& file_name, int32_t line_number) {
   SetFieldObject<kTransactionActive>(OFFSET_OF_OBJECT_MEMBER(StackTraceElement, declaring_class_),
-                                     declaring_class.get());
+                                     declaring_class.Get());
   SetFieldObject<kTransactionActive>(OFFSET_OF_OBJECT_MEMBER(StackTraceElement, method_name_),
-                                     method_name.get());
+                                     method_name.Get());
   SetFieldObject<kTransactionActive>(OFFSET_OF_OBJECT_MEMBER(StackTraceElement, file_name_),
-                                     file_name.get());
+                                     file_name.Get());
   SetField32<kTransactionActive>(OFFSET_OF_OBJECT_MEMBER(StackTraceElement, line_number_),
                                  line_number);
 }
diff --git a/runtime/mirror/stack_trace_element.h b/runtime/mirror/stack_trace_element.h
index c324d96..22d9b71 100644
--- a/runtime/mirror/stack_trace_element.h
+++ b/runtime/mirror/stack_trace_element.h
@@ -22,7 +22,7 @@
 
 namespace art {
 
-template<class T> class SirtRef;
+template<class T> class Handle;
 struct StackTraceElementOffsets;
 
 namespace mirror {
@@ -47,9 +47,9 @@
   }
 
   static StackTraceElement* Alloc(Thread* self,
-                                  SirtRef<String>& declaring_class,
-                                  SirtRef<String>& method_name,
-                                  SirtRef<String>& file_name,
+                                  Handle<String>& declaring_class,
+                                  Handle<String>& method_name,
+                                  Handle<String>& file_name,
                                   int32_t line_number)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -70,8 +70,8 @@
   int32_t line_number_;
 
   template<bool kTransactionActive>
-  void Init(SirtRef<String>& declaring_class, SirtRef<String>& method_name,
-            SirtRef<String>& file_name, int32_t line_number)
+  void Init(Handle<String>& declaring_class, Handle<String>& method_name,
+            Handle<String>& file_name, int32_t line_number)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   static Class* java_lang_StackTraceElement_;
diff --git a/runtime/mirror/string.cc b/runtime/mirror/string.cc
index 6a0c225..ee719b4 100644
--- a/runtime/mirror/string.cc
+++ b/runtime/mirror/string.cc
@@ -22,7 +22,7 @@
 #include "intern_table.h"
 #include "object-inl.h"
 #include "runtime.h"
-#include "sirt_ref.h"
+#include "handle_scope-inl.h"
 #include "thread.h"
 #include "utf-inl.h"
 
@@ -123,18 +123,19 @@
 }
 
 String* String::Alloc(Thread* self, int32_t utf16_length) {
-  SirtRef<CharArray> array(self, CharArray::Alloc(self, utf16_length));
-  if (UNLIKELY(array.get() == nullptr)) {
+  StackHandleScope<1> hs(self);
+  Handle<CharArray> array(hs.NewHandle(CharArray::Alloc(self, utf16_length)));
+  if (UNLIKELY(array.Get() == nullptr)) {
     return nullptr;
   }
   return Alloc(self, array);
 }
 
-String* String::Alloc(Thread* self, const SirtRef<CharArray>& array) {
+String* String::Alloc(Thread* self, const Handle<CharArray>& array) {
   // Hold reference in case AllocObject causes GC.
   String* string = down_cast<String*>(GetJavaLangString()->AllocObject(self));
   if (LIKELY(string != nullptr)) {
-    string->SetArray(array.get());
+    string->SetArray(array.Get());
     string->SetCount(array->GetLength());
   }
   return string;
diff --git a/runtime/mirror/string.h b/runtime/mirror/string.h
index f97308e..169b671 100644
--- a/runtime/mirror/string.h
+++ b/runtime/mirror/string.h
@@ -24,7 +24,7 @@
 
 namespace art {
 
-template<class T> class SirtRef;
+template<class T> class Handle;
 struct StringClassOffsets;
 struct StringOffsets;
 class StringPiece;
@@ -137,7 +137,7 @@
   static String* Alloc(Thread* self, int32_t utf16_length)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  static String* Alloc(Thread* self, const SirtRef<CharArray>& array)
+  static String* Alloc(Thread* self, const Handle<CharArray>& array)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void SetArray(CharArray* new_array) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/monitor.cc b/runtime/monitor.cc
index 38b77d1..64edba8 100644
--- a/runtime/monitor.cc
+++ b/runtime/monitor.cc
@@ -632,31 +632,32 @@
   }
 }
 
-void Monitor::InflateThinLocked(Thread* self, SirtRef<mirror::Object>& obj, LockWord lock_word,
+void Monitor::InflateThinLocked(Thread* self, Handle<mirror::Object>& obj, LockWord lock_word,
                                 uint32_t hash_code) {
   DCHECK_EQ(lock_word.GetState(), LockWord::kThinLocked);
   uint32_t owner_thread_id = lock_word.ThinLockOwner();
   if (owner_thread_id == self->GetThreadId()) {
     // We own the monitor, we can easily inflate it.
-    Inflate(self, self, obj.get(), hash_code);
+    Inflate(self, self, obj.Get(), hash_code);
   } else {
     ThreadList* thread_list = Runtime::Current()->GetThreadList();
     // Suspend the owner, inflate. First change to blocked and give up mutator_lock_.
-    ScopedThreadStateChange tsc(self, kBlocked);
-    self->SetMonitorEnterObject(obj.get());
-    if (lock_word == obj->GetLockWord(true)) {  // If lock word hasn't changed.
-      bool timed_out;
-      Thread* owner = thread_list->SuspendThreadByThreadId(owner_thread_id, false, &timed_out);
-      if (owner != nullptr) {
-        // We succeeded in suspending the thread, check the lock's status didn't change.
-        lock_word = obj->GetLockWord(true);
-        if (lock_word.GetState() == LockWord::kThinLocked &&
-            lock_word.ThinLockOwner() == owner_thread_id) {
-          // Go ahead and inflate the lock.
-          Inflate(self, owner, obj.get(), hash_code);
-        }
-        thread_list->Resume(owner, false);
+    self->SetMonitorEnterObject(obj.Get());
+    bool timed_out;
+    Thread* owner;
+    {
+      ScopedThreadStateChange tsc(self, kBlocked);
+      owner = thread_list->SuspendThreadByThreadId(owner_thread_id, false, &timed_out);
+    }
+    if (owner != nullptr) {
+      // We succeeded in suspending the thread, check the lock's status didn't change.
+      lock_word = obj->GetLockWord(true);
+      if (lock_word.GetState() == LockWord::kThinLocked &&
+          lock_word.ThinLockOwner() == owner_thread_id) {
+        // Go ahead and inflate the lock.
+        Inflate(self, owner, obj.Get(), hash_code);
       }
+      thread_list->Resume(owner, false);
     }
     self->SetMonitorEnterObject(nullptr);
   }
@@ -680,15 +681,16 @@
   obj = FakeLock(obj);
   uint32_t thread_id = self->GetThreadId();
   size_t contention_count = 0;
-  SirtRef<mirror::Object> sirt_obj(self, obj);
+  StackHandleScope<1> hs(self);
+  Handle<mirror::Object> h_obj(hs.NewHandle(obj));
   while (true) {
-    LockWord lock_word = sirt_obj->GetLockWord(true);
+    LockWord lock_word = h_obj->GetLockWord(true);
     switch (lock_word.GetState()) {
       case LockWord::kUnlocked: {
         LockWord thin_locked(LockWord::FromThinLockId(thread_id, 0));
-        if (sirt_obj->CasLockWord(lock_word, thin_locked)) {
+        if (h_obj->CasLockWord(lock_word, thin_locked)) {
           QuasiAtomic::MembarLoadLoad();
-          return sirt_obj.get();  // Success!
+          return h_obj.Get();  // Success!
         }
         continue;  // Go again.
       }
@@ -699,11 +701,11 @@
           uint32_t new_count = lock_word.ThinLockCount() + 1;
           if (LIKELY(new_count <= LockWord::kThinLockMaxCount)) {
             LockWord thin_locked(LockWord::FromThinLockId(thread_id, new_count));
-            sirt_obj->SetLockWord(thin_locked, true);
-            return sirt_obj.get();  // Success!
+            h_obj->SetLockWord(thin_locked, true);
+            return h_obj.Get();  // Success!
           } else {
             // We'd overflow the recursion count, so inflate the monitor.
-            InflateThinLocked(self, sirt_obj, lock_word, 0);
+            InflateThinLocked(self, h_obj, lock_word, 0);
           }
         } else {
           // Contention.
@@ -713,7 +715,7 @@
             NanoSleep(1000);  // Sleep for 1us and re-attempt.
           } else {
             contention_count = 0;
-            InflateThinLocked(self, sirt_obj, lock_word, 0);
+            InflateThinLocked(self, h_obj, lock_word, 0);
           }
         }
         continue;  // Start from the beginning.
@@ -721,15 +723,15 @@
       case LockWord::kFatLocked: {
         Monitor* mon = lock_word.FatLockMonitor();
         mon->Lock(self);
-        return sirt_obj.get();  // Success!
+        return h_obj.Get();  // Success!
       }
       case LockWord::kHashCode:
         // Inflate with the existing hashcode.
-        Inflate(self, nullptr, sirt_obj.get(), lock_word.GetHashCode());
+        Inflate(self, nullptr, h_obj.Get(), lock_word.GetHashCode());
         continue;  // Start from the beginning.
       default: {
         LOG(FATAL) << "Invalid monitor state " << lock_word.GetState();
-        return sirt_obj.get();
+        return h_obj.Get();
       }
     }
   }
@@ -740,12 +742,13 @@
   DCHECK(obj != NULL);
   obj = FakeUnlock(obj);
   LockWord lock_word = obj->GetLockWord(true);
-  SirtRef<mirror::Object> sirt_obj(self, obj);
+  StackHandleScope<1> hs(self);
+  Handle<mirror::Object> h_obj(hs.NewHandle(obj));
   switch (lock_word.GetState()) {
     case LockWord::kHashCode:
       // Fall-through.
     case LockWord::kUnlocked:
-      FailedUnlock(sirt_obj.get(), self, nullptr, nullptr);
+      FailedUnlock(h_obj.Get(), self, nullptr, nullptr);
       return false;  // Failure.
     case LockWord::kThinLocked: {
       uint32_t thread_id = self->GetThreadId();
@@ -754,16 +757,16 @@
         // TODO: there's a race here with the owner dying while we unlock.
         Thread* owner =
             Runtime::Current()->GetThreadList()->FindThreadByThreadId(lock_word.ThinLockOwner());
-        FailedUnlock(sirt_obj.get(), self, owner, nullptr);
+        FailedUnlock(h_obj.Get(), self, owner, nullptr);
         return false;  // Failure.
       } else {
         // We own the lock, decrease the recursion count.
         if (lock_word.ThinLockCount() != 0) {
           uint32_t new_count = lock_word.ThinLockCount() - 1;
           LockWord thin_locked(LockWord::FromThinLockId(thread_id, new_count));
-          sirt_obj->SetLockWord(thin_locked, true);
+          h_obj->SetLockWord(thin_locked, true);
         } else {
-          sirt_obj->SetLockWord(LockWord(), true);
+          h_obj->SetLockWord(LockWord(), true);
         }
         return true;  // Success!
       }
@@ -946,7 +949,7 @@
   // TODO: use the JNI implementation's table of explicit MonitorEnter calls and dump those too.
   if (m->IsNative()) {
     if (m->IsSynchronized()) {
-      mirror::Object* jni_this = stack_visitor->GetCurrentSirt()->GetReference(0);
+      mirror::Object* jni_this = stack_visitor->GetCurrentHandleScope()->GetReference(0);
       callback(jni_this, callback_context);
     }
     return;
diff --git a/runtime/monitor.h b/runtime/monitor.h
index 15620d5..bc5d2e4 100644
--- a/runtime/monitor.h
+++ b/runtime/monitor.h
@@ -32,7 +32,7 @@
 namespace art {
 
 class LockWord;
-template<class T> class SirtRef;
+template<class T> class Handle;
 class Thread;
 class StackVisitor;
 typedef uint32_t MonitorId;
@@ -114,7 +114,7 @@
     return monitor_id_;
   }
 
-  static void InflateThinLocked(Thread* self, SirtRef<mirror::Object>& obj, LockWord lock_word,
+  static void InflateThinLocked(Thread* self, Handle<mirror::Object>& obj, LockWord lock_word,
                                 uint32_t hash_code) NO_THREAD_SAFETY_ANALYSIS;
 
   static bool Deflate(Thread* self, mirror::Object* obj)
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index ed1ee7a..52abaab 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -186,7 +186,9 @@
   ScopedObjectAccess soa(env);
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   class_linker->RegisterDexFile(*dex_file);
-  SirtRef<mirror::ClassLoader> class_loader(soa.Self(), soa.Decode<mirror::ClassLoader*>(javaLoader));
+  StackHandleScope<1> hs(soa.Self());
+  Handle<mirror::ClassLoader> class_loader(
+      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(javaLoader)));
   mirror::Class* result = class_linker->DefineClass(descriptor.c_str(), class_loader, *dex_file,
                                                     *dex_class_def);
   VLOG(class_linker) << "DexFile_defineClassNative returning " << result;
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index 76c5866..8d183da 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -66,10 +66,6 @@
     ThrowNullPointerException(NULL, "element class == null");
     return nullptr;
   }
-  if (UNLIKELY(element_class->IsPrimitiveVoid())) {
-    ThrowIllegalArgumentException(NULL, "Can't allocate an array of void");
-    return nullptr;
-  }
   Runtime* runtime = Runtime::Current();
   mirror::Class* array_class = runtime->GetClassLinker()->FindArrayClass(soa.Self(), element_class);
   if (UNLIKELY(array_class == nullptr)) {
@@ -93,10 +89,6 @@
     ThrowNullPointerException(NULL, "element class == null");
     return nullptr;
   }
-  if (UNLIKELY(element_class->IsPrimitiveVoid())) {
-    ThrowIllegalArgumentException(NULL, "Can't allocate an array of void");
-    return nullptr;
-  }
   Runtime* runtime = Runtime::Current();
   mirror::Class* array_class = runtime->GetClassLinker()->FindArrayClass(soa.Self(), element_class);
   if (UNLIKELY(array_class == nullptr)) {
@@ -214,7 +206,7 @@
 }
 
 // Based on ClassLinker::ResolveString.
-static void PreloadDexCachesResolveString(SirtRef<mirror::DexCache>& dex_cache, uint32_t string_idx,
+static void PreloadDexCachesResolveString(Handle<mirror::DexCache>& dex_cache, uint32_t string_idx,
                                           StringTable& strings)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   mirror::String* string = dex_cache->GetResolvedString(string_idx);
@@ -260,7 +252,7 @@
 }
 
 // Based on ClassLinker::ResolveField.
-static void PreloadDexCachesResolveField(SirtRef<mirror::DexCache>& dex_cache,
+static void PreloadDexCachesResolveField(Handle<mirror::DexCache>& dex_cache,
                                          uint32_t field_idx,
                                          bool is_static)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -275,9 +267,9 @@
     return;
   }
   if (is_static) {
-    field = klass->FindStaticField(dex_cache.get(), field_idx);
+    field = klass->FindStaticField(dex_cache.Get(), field_idx);
   } else {
-    field = klass->FindInstanceField(dex_cache.get(), field_idx);
+    field = klass->FindInstanceField(dex_cache.Get(), field_idx);
   }
   if (field == NULL) {
     return;
@@ -287,7 +279,7 @@
 }
 
 // Based on ClassLinker::ResolveMethod.
-static void PreloadDexCachesResolveMethod(SirtRef<mirror::DexCache>& dex_cache,
+static void PreloadDexCachesResolveMethod(Handle<mirror::DexCache>& dex_cache,
                                           uint32_t method_idx,
                                           InvokeType invoke_type)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -304,14 +296,14 @@
   switch (invoke_type) {
     case kDirect:
     case kStatic:
-      method = klass->FindDirectMethod(dex_cache.get(), method_idx);
+      method = klass->FindDirectMethod(dex_cache.Get(), method_idx);
       break;
     case kInterface:
-      method = klass->FindInterfaceMethod(dex_cache.get(), method_idx);
+      method = klass->FindInterfaceMethod(dex_cache.Get(), method_idx);
       break;
     case kSuper:
     case kVirtual:
-      method = klass->FindVirtualMethod(dex_cache.get(), method_idx);
+      method = klass->FindVirtualMethod(dex_cache.Get(), method_idx);
       break;
     default:
       LOG(FATAL) << "Unreachable - invocation type: " << invoke_type;
@@ -434,7 +426,8 @@
   for (size_t i = 0; i< boot_class_path.size(); i++) {
     const DexFile* dex_file = boot_class_path[i];
     CHECK(dex_file != NULL);
-    SirtRef<mirror::DexCache> dex_cache(self, linker->FindDexCache(*dex_file));
+    StackHandleScope<1> hs(self);
+    Handle<mirror::DexCache> dex_cache(hs.NewHandle(linker->FindDexCache(*dex_file)));
 
     if (kPreloadDexCachesStrings) {
       for (size_t i = 0; i < dex_cache->NumStrings(); i++) {
@@ -444,7 +437,7 @@
 
     if (kPreloadDexCachesTypes) {
       for (size_t i = 0; i < dex_cache->NumResolvedTypes(); i++) {
-        PreloadDexCachesResolveType(dex_cache.get(), i);
+        PreloadDexCachesResolveType(dex_cache.Get(), i);
       }
     }
 
diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc
index f541633..7490e6a 100644
--- a/runtime/native/dalvik_system_ZygoteHooks.cc
+++ b/runtime/native/dalvik_system_ZygoteHooks.cc
@@ -58,12 +58,12 @@
     Runtime* runtime = Runtime::Current();
     JavaVMExt* vm = runtime->GetJavaVM();
     if (!vm->check_jni) {
-      VLOG(jni) << "Late-enabling -Xcheck:jni";
+      LOG(INFO) << "Late-enabling -Xcheck:jni";
       vm->SetCheckJniEnabled(true);
       // There's only one thread running at this point, so only one JNIEnv to fix up.
       Thread::Current()->GetJniEnv()->SetCheckJniEnabled(true);
     } else {
-      VLOG(jni) << "Not late-enabling -Xcheck:jni (already on)";
+      LOG(INFO) << "Not late-enabling -Xcheck:jni (already on)";
     }
     debug_flags &= ~DEBUG_ENABLE_CHECKJNI;
   }
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
index 6daf9a9..b6cf7d8 100644
--- a/runtime/native/java_lang_Class.cc
+++ b/runtime/native/java_lang_Class.cc
@@ -62,12 +62,12 @@
   }
 
   std::string descriptor(DotToDescriptor(name.c_str()));
-  SirtRef<mirror::ClassLoader> class_loader(soa.Self(),
-                                            soa.Decode<mirror::ClassLoader*>(javaLoader));
+  StackHandleScope<2> hs(soa.Self());
+  Handle<mirror::ClassLoader> class_loader(hs.NewHandle(soa.Decode<mirror::ClassLoader*>(javaLoader)));
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  SirtRef<mirror::Class> c(soa.Self(), class_linker->FindClass(soa.Self(), descriptor.c_str(),
-                                                               class_loader));
-  if (c.get() == nullptr) {
+  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,
@@ -79,7 +79,7 @@
   if (initialize) {
     class_linker->EnsureInitialized(c, true, true);
   }
-  return soa.AddLocalReference<jclass>(c.get());
+  return soa.AddLocalReference<jclass>(c.Get());
 }
 
 static jstring Class_getNameNative(JNIEnv* env, jobject javaThis) {
diff --git a/runtime/native/java_lang_Runtime.cc b/runtime/native/java_lang_Runtime.cc
index 636be5d..496a1b2 100644
--- a/runtime/native/java_lang_Runtime.cc
+++ b/runtime/native/java_lang_Runtime.cc
@@ -19,12 +19,13 @@
 #include <unistd.h>
 
 #include "gc/heap.h"
+#include "handle_scope-inl.h"
 #include "jni_internal.h"
 #include "mirror/class_loader.h"
 #include "runtime.h"
 #include "scoped_thread_state_change.h"
 #include "ScopedUtfChars.h"
-#include "sirt_ref-inl.h"
+#include "verify_object-inl.h"
 
 namespace art {
 
@@ -65,8 +66,9 @@
   std::string detail;
   {
     ScopedObjectAccess soa(env);
-    SirtRef<mirror::ClassLoader> classLoader(soa.Self(),
-                                             soa.Decode<mirror::ClassLoader*>(javaLoader));
+    StackHandleScope<1> hs(soa.Self());
+    Handle<mirror::ClassLoader> classLoader(
+        hs.NewHandle(soa.Decode<mirror::ClassLoader*>(javaLoader)));
     JavaVMExt* vm = Runtime::Current()->GetJavaVM();
     bool success = vm->LoadNativeLibrary(filename.c_str(), classLoader, &detail);
     if (success) {
diff --git a/runtime/native/java_lang_reflect_Array.cc b/runtime/native/java_lang_reflect_Array.cc
index a991818..7c6f2f3 100644
--- a/runtime/native/java_lang_reflect_Array.cc
+++ b/runtime/native/java_lang_reflect_Array.cc
@@ -22,21 +22,22 @@
 #include "mirror/object-inl.h"
 #include "object_utils.h"
 #include "scoped_fast_native_object_access.h"
-#include "sirt_ref.h"
+#include "handle_scope-inl.h"
 
 namespace art {
 
 static jobject Array_createMultiArray(JNIEnv* env, jclass, jclass javaElementClass, jobject javaDimArray) {
   ScopedFastNativeObjectAccess soa(env);
   DCHECK(javaElementClass != NULL);
-  SirtRef<mirror::Class> element_class(soa.Self(), soa.Decode<mirror::Class*>(javaElementClass));
+  StackHandleScope<2> hs(soa.Self());
+  Handle<mirror::Class> element_class(hs.NewHandle(soa.Decode<mirror::Class*>(javaElementClass)));
   DCHECK(element_class->IsClass());
   DCHECK(javaDimArray != NULL);
   mirror::Object* dimensions_obj = soa.Decode<mirror::Object*>(javaDimArray);
   DCHECK(dimensions_obj->IsArrayInstance());
   DCHECK_STREQ(ClassHelper(dimensions_obj->GetClass()).GetDescriptor(), "[I");
-  SirtRef<mirror::IntArray> dimensions_array(soa.Self(),
-                                             down_cast<mirror::IntArray*>(dimensions_obj));
+  Handle<mirror::IntArray> dimensions_array(
+      hs.NewHandle(down_cast<mirror::IntArray*>(dimensions_obj)));
   mirror::Array* new_array = mirror::Array::CreateMultiArray(soa.Self(), element_class,
                                                              dimensions_array);
   return soa.AddLocalReference<jobject>(new_array);
diff --git a/runtime/native/java_lang_reflect_Constructor.cc b/runtime/native/java_lang_reflect_Constructor.cc
index 2445b53..1981bfd 100644
--- a/runtime/native/java_lang_reflect_Constructor.cc
+++ b/runtime/native/java_lang_reflect_Constructor.cc
@@ -38,13 +38,14 @@
                                        jboolean accessible) {
   ScopedFastNativeObjectAccess soa(env);
   mirror::ArtMethod* m = mirror::ArtMethod::FromReflectedMethod(soa, javaMethod);
-  SirtRef<mirror::Class> c(soa.Self(), m->GetDeclaringClass());
+  StackHandleScope<1> hs(soa.Self());
+  Handle<mirror::Class> c(hs.NewHandle(m->GetDeclaringClass()));
   if (UNLIKELY(c->IsAbstract())) {
     ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow();
     soa.Self()->ThrowNewExceptionF(throw_location, "Ljava/lang/InstantiationException;",
                                    "Can't instantiate %s %s",
                                    c->IsInterface() ? "interface" : "abstract class",
-                                   PrettyDescriptor(c.get()).c_str());
+                                   PrettyDescriptor(c.Get()).c_str());
     return nullptr;
   }
 
diff --git a/runtime/native/java_lang_reflect_Field.cc b/runtime/native/java_lang_reflect_Field.cc
index ce622d9..0d54772 100644
--- a/runtime/native/java_lang_reflect_Field.cc
+++ b/runtime/native/java_lang_reflect_Field.cc
@@ -94,13 +94,14 @@
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   soa.Self()->AssertThreadSuspensionIsAllowable();
   if (f->IsStatic()) {
-    SirtRef<mirror::Class> sirt_klass(soa.Self(), f->GetDeclaringClass());
-    if (UNLIKELY(!Runtime::Current()->GetClassLinker()->EnsureInitialized(sirt_klass, true, true))) {
+    StackHandleScope<1> hs(soa.Self());
+    Handle<mirror::Class> h_klass(hs.NewHandle(f->GetDeclaringClass()));
+    if (UNLIKELY(!Runtime::Current()->GetClassLinker()->EnsureInitialized(h_klass, true, true))) {
       DCHECK(soa.Self()->IsExceptionPending());
       *class_or_rcvr = nullptr;
       return false;
     }
-    *class_or_rcvr = sirt_klass.get();
+    *class_or_rcvr = h_klass.Get();
     return true;
   }
 
@@ -271,7 +272,8 @@
     const char* field_type_desciptor = fh.GetTypeDescriptor();
     field_prim_type = Primitive::GetType(field_type_desciptor[0]);
     if (field_prim_type == Primitive::kPrimNot) {
-      SirtRef<mirror::Object> sirt_obj(soa.Self(), o);
+      StackHandleScope<1> hs(soa.Self());
+      HandleWrapper<mirror::Object> h(hs.NewHandleWrapper(&o));
       // May cause resolution.
       CHECK(!kMovingFields) << "Resolution may trigger thread suspension";
       field_type = fh.GetType(true);
diff --git a/runtime/oat.cc b/runtime/oat.cc
index a1f4fd0..cb9334a 100644
--- a/runtime/oat.cc
+++ b/runtime/oat.cc
@@ -22,7 +22,7 @@
 namespace art {
 
 const uint8_t OatHeader::kOatMagic[] = { 'o', 'a', 't', '\n' };
-const uint8_t OatHeader::kOatVersion[] = { '0', '2', '7', '\0' };
+const uint8_t OatHeader::kOatVersion[] = { '0', '2', '8', '\0' };
 
 OatHeader::OatHeader() {
   memset(this, 0, sizeof(*this));
@@ -345,40 +345,34 @@
 
 OatMethodOffsets::OatMethodOffsets()
   : code_offset_(0),
-    frame_size_in_bytes_(0),
-    core_spill_mask_(0),
-    fp_spill_mask_(0),
     gc_map_offset_(0)
 {}
 
 OatMethodOffsets::OatMethodOffsets(uint32_t code_offset,
-                                   uint32_t frame_size_in_bytes,
-                                   uint32_t core_spill_mask,
-                                   uint32_t fp_spill_mask,
                                    uint32_t gc_map_offset
                                    )
   : code_offset_(code_offset),
-    frame_size_in_bytes_(frame_size_in_bytes),
-    core_spill_mask_(core_spill_mask),
-    fp_spill_mask_(fp_spill_mask),
     gc_map_offset_(gc_map_offset)
 {}
 
 OatMethodOffsets::~OatMethodOffsets() {}
 
-OatMethodHeader::OatMethodHeader()
+OatQuickMethodHeader::OatQuickMethodHeader()
   : mapping_table_offset_(0),
     vmap_table_offset_(0),
+    frame_info_(0, 0, 0),
     code_size_(0)
 {}
 
-OatMethodHeader::OatMethodHeader(uint32_t vmap_table_offset, uint32_t mapping_table_offset,
-                                 uint32_t code_size)
+OatQuickMethodHeader::OatQuickMethodHeader(
+    uint32_t mapping_table_offset, uint32_t vmap_table_offset, uint32_t frame_size_in_bytes,
+    uint32_t core_spill_mask, uint32_t fp_spill_mask, uint32_t code_size)
   : mapping_table_offset_(mapping_table_offset),
     vmap_table_offset_(vmap_table_offset),
+    frame_info_(frame_size_in_bytes, core_spill_mask, fp_spill_mask),
     code_size_(code_size)
 {}
 
-OatMethodHeader::~OatMethodHeader() {}
+OatQuickMethodHeader::~OatQuickMethodHeader() {}
 
 }  // namespace art
diff --git a/runtime/oat.h b/runtime/oat.h
index e9dfae9..7be768c 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -22,6 +22,7 @@
 #include "base/macros.h"
 #include "dex_file.h"
 #include "instruction_set.h"
+#include "quick/quick_method_frame_info.h"
 
 namespace art {
 
@@ -137,34 +138,31 @@
   OatMethodOffsets();
 
   OatMethodOffsets(uint32_t code_offset,
-                   uint32_t frame_size_in_bytes,
-                   uint32_t core_spill_mask,
-                   uint32_t fp_spill_mask,
                    uint32_t gc_map_offset);
 
   ~OatMethodOffsets();
 
   uint32_t code_offset_;
-  uint32_t frame_size_in_bytes_;
-  uint32_t core_spill_mask_;
-  uint32_t fp_spill_mask_;
   uint32_t gc_map_offset_;
 };
 
-// OatMethodHeader precedes the raw code chunk generated by the Quick compiler.
-class PACKED(4) OatMethodHeader {
+// OatQuickMethodHeader precedes the raw code chunk generated by the Quick compiler.
+class PACKED(4) OatQuickMethodHeader {
  public:
-  OatMethodHeader();
+  OatQuickMethodHeader();
 
-  explicit OatMethodHeader(uint32_t mapping_table_offset, uint32_t vmap_table_offset,
-                           uint32_t code_size);
+  explicit OatQuickMethodHeader(uint32_t mapping_table_offset, uint32_t vmap_table_offset,
+                                uint32_t frame_size_in_bytes, uint32_t core_spill_mask,
+                                uint32_t fp_spill_mask, uint32_t code_size);
 
-  ~OatMethodHeader();
+  ~OatQuickMethodHeader();
 
   // The offset in bytes from the start of the mapping table to the end of the header.
   uint32_t mapping_table_offset_;
   // The offset in bytes from the start of the vmap table to the end of the header.
   uint32_t vmap_table_offset_;
+  // The stack frame information.
+  QuickMethodFrameInfo frame_info_;
   // The code size in bytes.
   uint32_t code_size_;
 };
diff --git a/runtime/oat_file-inl.h b/runtime/oat_file-inl.h
index 00ae797..97ca6b2 100644
--- a/runtime/oat_file-inl.h
+++ b/runtime/oat_file-inl.h
@@ -21,6 +21,30 @@
 
 namespace art {
 
+inline size_t OatFile::OatMethod::GetFrameSizeInBytes() const {
+  const void* code = mirror::ArtMethod::EntryPointToCodePointer(GetQuickCode());
+  if (code == nullptr) {
+    return 0u;
+  }
+  return reinterpret_cast<const OatQuickMethodHeader*>(code)[-1].frame_info_.FrameSizeInBytes();
+}
+
+inline uint32_t OatFile::OatMethod::GetCoreSpillMask() const {
+  const void* code = mirror::ArtMethod::EntryPointToCodePointer(GetQuickCode());
+  if (code == nullptr) {
+    return 0u;
+  }
+  return reinterpret_cast<const OatQuickMethodHeader*>(code)[-1].frame_info_.CoreSpillMask();
+}
+
+inline uint32_t OatFile::OatMethod::GetFpSpillMask() const {
+  const void* code = mirror::ArtMethod::EntryPointToCodePointer(GetQuickCode());
+  if (code == nullptr) {
+    return 0u;
+  }
+  return reinterpret_cast<const OatQuickMethodHeader*>(code)[-1].frame_info_.FpSpillMask();
+}
+
 inline uint32_t OatFile::OatMethod::GetMappingTableOffset() const {
   const uint8_t* mapping_table = GetMappingTable();
   return static_cast<uint32_t>(mapping_table != nullptr ? mapping_table - begin_ : 0u);
@@ -36,7 +60,7 @@
   if (code == nullptr) {
     return nullptr;
   }
-  uint32_t offset = reinterpret_cast<const OatMethodHeader*>(code)[-1].mapping_table_offset_;
+  uint32_t offset = reinterpret_cast<const OatQuickMethodHeader*>(code)[-1].mapping_table_offset_;
   if (UNLIKELY(offset == 0u)) {
     return nullptr;
   }
@@ -48,7 +72,7 @@
   if (code == nullptr) {
     return nullptr;
   }
-  uint32_t offset = reinterpret_cast<const OatMethodHeader*>(code)[-1].vmap_table_offset_;
+  uint32_t offset = reinterpret_cast<const OatQuickMethodHeader*>(code)[-1].vmap_table_offset_;
   if (UNLIKELY(offset == 0u)) {
     return nullptr;
   }
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index 56e1f05..7976f6a 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -464,7 +464,7 @@
   // NOTE: We don't keep the number of methods and cannot do a bounds check for method_index.
   if (methods_pointer_ == NULL) {
     CHECK_EQ(kOatClassNoneCompiled, type_);
-    return OatMethod(NULL, 0, 0, 0, 0, 0);
+    return OatMethod(NULL, 0, 0);
   }
   size_t methods_pointer_index;
   if (bitmap_ == NULL) {
@@ -473,7 +473,7 @@
   } else {
     CHECK_EQ(kOatClassSomeCompiled, type_);
     if (!BitVector::IsBitSet(bitmap_, method_index)) {
-      return OatMethod(NULL, 0, 0, 0, 0, 0);
+      return OatMethod(NULL, 0, 0);
     }
     size_t num_set_bits = BitVector::NumSetBits(bitmap_, method_index);
     methods_pointer_index = num_set_bits;
@@ -482,23 +482,14 @@
   return OatMethod(
       oat_file_->Begin(),
       oat_method_offsets.code_offset_,
-      oat_method_offsets.frame_size_in_bytes_,
-      oat_method_offsets.core_spill_mask_,
-      oat_method_offsets.fp_spill_mask_,
       oat_method_offsets.gc_map_offset_);
 }
 
 OatFile::OatMethod::OatMethod(const byte* base,
                               const uint32_t code_offset,
-                              const size_t frame_size_in_bytes,
-                              const uint32_t core_spill_mask,
-                              const uint32_t fp_spill_mask,
                               const uint32_t gc_map_offset)
   : begin_(base),
     code_offset_(code_offset),
-    frame_size_in_bytes_(frame_size_in_bytes),
-    core_spill_mask_(core_spill_mask),
-    fp_spill_mask_(fp_spill_mask),
     native_gc_map_offset_(gc_map_offset) {
 }
 
@@ -519,9 +510,6 @@
   CHECK(method != NULL);
   method->SetEntryPointFromPortableCompiledCode(GetPortableCode());
   method->SetEntryPointFromQuickCompiledCode(GetQuickCode());
-  method->SetFrameSizeInBytes(frame_size_in_bytes_);
-  method->SetCoreSpillMask(core_spill_mask_);
-  method->SetFpSpillMask(fp_spill_mask_);
   method->SetNativeGcMap(GetNativeGcMap());  // Used by native methods in work around JNI mode.
 }
 
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index b358a00..e5dc53c 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -78,15 +78,6 @@
     uint32_t GetCodeOffset() const {
       return code_offset_;
     }
-    size_t GetFrameSizeInBytes() const {
-      return frame_size_in_bytes_;
-    }
-    uint32_t GetCoreSpillMask() const {
-      return core_spill_mask_;
-    }
-    uint32_t GetFpSpillMask() const {
-      return fp_spill_mask_;
-    }
     uint32_t GetNativeGcMapOffset() const {
       return native_gc_map_offset_;
     }
@@ -120,6 +111,9 @@
       return GetOatPointer<const uint8_t*>(native_gc_map_offset_);
     }
 
+    size_t GetFrameSizeInBytes() const;
+    uint32_t GetCoreSpillMask() const;
+    uint32_t GetFpSpillMask() const;
     uint32_t GetMappingTableOffset() const;
     uint32_t GetVmapTableOffset() const;
     const uint8_t* GetMappingTable() const;
@@ -130,9 +124,6 @@
     // Create an OatMethod with offsets relative to the given base address
     OatMethod(const byte* base,
               const uint32_t code_offset,
-              const size_t frame_size_in_bytes,
-              const uint32_t core_spill_mask,
-              const uint32_t fp_spill_mask,
               const uint32_t gc_map_offset);
 
    private:
@@ -147,9 +138,6 @@
     const byte* begin_;
 
     uint32_t code_offset_;
-    size_t frame_size_in_bytes_;
-    uint32_t core_spill_mask_;
-    uint32_t fp_spill_mask_;
     uint32_t native_gc_map_offset_;
 
     friend class OatClass;
@@ -165,7 +153,7 @@
       return type_;
     }
 
-    // get the OatMethod entry based on its index into the class
+    // Get the OatMethod entry based on its index into the class
     // defintion. direct methods come first, followed by virtual
     // methods. note that runtime created methods such as miranda
     // methods are not included.
diff --git a/runtime/object_utils.h b/runtime/object_utils.h
index 504537a..0dd6ca1 100644
--- a/runtime/object_utils.h
+++ b/runtime/object_utils.h
@@ -29,7 +29,7 @@
 #include "mirror/string.h"
 
 #include "runtime.h"
-#include "sirt_ref-inl.h"
+#include "handle_scope-inl.h"
 
 #include <string>
 
@@ -38,33 +38,33 @@
 template <typename T>
 class ObjectLock {
  public:
-  explicit ObjectLock(Thread* self, const SirtRef<T>* object)
+  explicit ObjectLock(Thread* self, const Handle<T>* object)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       : self_(self), obj_(object) {
     CHECK(object != nullptr);
-    CHECK(object->get() != nullptr);
-    obj_->get()->MonitorEnter(self_);
+    CHECK(object->Get() != nullptr);
+    obj_->Get()->MonitorEnter(self_);
   }
 
   ~ObjectLock() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    obj_->get()->MonitorExit(self_);
+    obj_->Get()->MonitorExit(self_);
   }
 
   void WaitIgnoringInterrupts() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    Monitor::Wait(self_, obj_->get(), 0, 0, false, kWaiting);
+    Monitor::Wait(self_, obj_->Get(), 0, 0, false, kWaiting);
   }
 
   void Notify() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    obj_->get()->Notify(self_);
+    obj_->Get()->Notify(self_);
   }
 
   void NotifyAll() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    obj_->get()->NotifyAll(self_);
+    obj_->Get()->NotifyAll(self_);
   }
 
  private:
   Thread* const self_;
-  const SirtRef<T>* const obj_;
+  const Handle<T>* const obj_;
   DISALLOW_COPY_AND_ASSIGN(ObjectLock);
 };
 
@@ -378,7 +378,8 @@
     const DexFile& dex_file = GetDexFile();
     uint32_t dex_method_idx = method_->GetDexMethodIndex();
     const DexFile::MethodId& method_id = dex_file.GetMethodId(dex_method_idx);
-    SirtRef<mirror::DexCache> dex_cache(Thread::Current(), GetDexCache());
+    StackHandleScope<1> hs(Thread::Current());
+    Handle<mirror::DexCache> dex_cache(hs.NewHandle(GetDexCache()));
     return GetClassLinker()->ResolveString(dex_file, method_id.name_idx_, dex_cache);
   }
 
@@ -607,7 +608,8 @@
   mirror::String* ResolveString(uint32_t string_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     mirror::String* s = method_->GetDexCacheStrings()->Get(string_idx);
     if (UNLIKELY(s == nullptr)) {
-      SirtRef<mirror::DexCache> dex_cache(Thread::Current(), GetDexCache());
+      StackHandleScope<1> hs(Thread::Current());
+      Handle<mirror::DexCache> dex_cache(hs.NewHandle(GetDexCache()));
       s = GetClassLinker()->ResolveString(GetDexFile(), string_idx, dex_cache);
     }
     return s;
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index 84ca23b..55b6a27 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -181,8 +181,16 @@
   parallel_gc_threads_ = sysconf(_SC_NPROCESSORS_CONF) - 1;
   // Only the main GC thread, no workers.
   conc_gc_threads_ = 0;
-  // Default is CMS which is Sticky + Partial + Full CMS GC.
+  // The default GC type is set in makefiles.
+#if ART_DEFAULT_GC_TYPE_IS_CMS
   collector_type_ = gc::kCollectorTypeCMS;
+#elif ART_DEFAULT_GC_TYPE_IS_SS
+  collector_type_ = gc::kCollectorTypeSS;
+#elif ART_DEFAULT_GC_TYPE_IS_GSS
+  collector_type_ = gc::kCollectorTypeGSS;
+#else
+#error "ART default GC type must be set"
+#endif
   // If background_collector_type_ is kCollectorTypeNone, it defaults to the collector_type_ after
   // parsing options.
   background_collector_type_ = gc::kCollectorTypeNone;
@@ -666,10 +674,17 @@
   // the art specific version. This can happen with on device
   // boot.art/boot.oat generation by GenerateImage which relies on the
   // value of BOOTCLASSPATH.
+#if defined(ART_TARGET)
   std::string core_jar("/core.jar");
+  std::string core_libart_jar("/core-libart.jar");
+#else
+  // The host uses hostdex files.
+  std::string core_jar("/core-hostdex.jar");
+  std::string core_libart_jar("/core-libart-hostdex.jar");
+#endif
   size_t core_jar_pos = boot_class_path_string_.find(core_jar);
   if (core_jar_pos != std::string::npos) {
-    boot_class_path_string_.replace(core_jar_pos, core_jar.size(), "/core-libart.jar");
+    boot_class_path_string_.replace(core_jar_pos, core_jar.size(), core_libart_jar);
   }
 
   if (compiler_callbacks_ == nullptr && image_.empty()) {
diff --git a/runtime/proxy_test.cc b/runtime/proxy_test.cc
index eebfba8..8517e34 100644
--- a/runtime/proxy_test.cc
+++ b/runtime/proxy_test.cc
@@ -107,8 +107,9 @@
 TEST_F(ProxyTest, ProxyClassHelper) {
   ScopedObjectAccess soa(Thread::Current());
   jobject jclass_loader = LoadDex("Interfaces");
-  SirtRef<mirror::ClassLoader> class_loader(soa.Self(),
-                                            soa.Decode<mirror::ClassLoader*>(jclass_loader));
+  StackHandleScope<1> hs(soa.Self());
+  Handle<mirror::ClassLoader> class_loader(
+      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
 
   mirror::Class* I = class_linker_->FindClass(soa.Self(), "LInterfaces$I;", class_loader);
   mirror::Class* J = class_linker_->FindClass(soa.Self(), "LInterfaces$J;", class_loader);
@@ -136,8 +137,9 @@
 TEST_F(ProxyTest, ProxyFieldHelper) {
   ScopedObjectAccess soa(Thread::Current());
   jobject jclass_loader = LoadDex("Interfaces");
-  SirtRef<mirror::ClassLoader> class_loader(soa.Self(),
-                                            soa.Decode<mirror::ClassLoader*>(jclass_loader));
+  StackHandleScope<1> hs(soa.Self());
+  Handle<mirror::ClassLoader> class_loader(
+      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
 
   mirror::Class* I = class_linker_->FindClass(soa.Self(), "LInterfaces$I;", class_loader);
   mirror::Class* J = class_linker_->FindClass(soa.Self(), "LInterfaces$J;", class_loader);
diff --git a/runtime/quick/quick_method_frame_info.h b/runtime/quick/quick_method_frame_info.h
new file mode 100644
index 0000000..684d4da
--- /dev/null
+++ b/runtime/quick/quick_method_frame_info.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2014 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_QUICK_QUICK_METHOD_FRAME_INFO_H_
+#define ART_RUNTIME_QUICK_QUICK_METHOD_FRAME_INFO_H_
+
+#include <stdint.h>
+
+#include "base/macros.h"
+
+namespace art {
+
+class PACKED(4) QuickMethodFrameInfo {
+ public:
+  constexpr QuickMethodFrameInfo()
+    : frame_size_in_bytes_(0u),
+      core_spill_mask_(0u),
+      fp_spill_mask_(0u) {
+  }
+
+  constexpr QuickMethodFrameInfo(uint32_t frame_size_in_bytes, uint32_t core_spill_mask,
+                                 uint32_t fp_spill_mask)
+    : frame_size_in_bytes_(frame_size_in_bytes),
+      core_spill_mask_(core_spill_mask),
+      fp_spill_mask_(fp_spill_mask) {
+  }
+
+  uint32_t FrameSizeInBytes() const {
+    return frame_size_in_bytes_;
+  }
+
+  uint32_t CoreSpillMask() const {
+    return core_spill_mask_;
+  }
+
+  uint32_t FpSpillMask() const {
+    return fp_spill_mask_;
+  }
+
+ private:
+  uint32_t frame_size_in_bytes_;
+  uint32_t core_spill_mask_;
+  uint32_t fp_spill_mask_;
+};
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_QUICK_QUICK_METHOD_FRAME_INFO_H_
diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc
index aee0d64..8300195 100644
--- a/runtime/quick_exception_handler.cc
+++ b/runtime/quick_exception_handler.cc
@@ -20,7 +20,7 @@
 #include "deoptimize_stack_visitor.h"
 #include "entrypoints/entrypoint_utils.h"
 #include "mirror/art_method-inl.h"
-#include "sirt_ref-inl.h"
+#include "handle_scope-inl.h"
 
 namespace art {
 
@@ -35,10 +35,11 @@
 void QuickExceptionHandler::FindCatch(const ThrowLocation& throw_location,
                                       mirror::Throwable* exception) {
   DCHECK(!is_deoptimization_);
-  SirtRef<mirror::Throwable> exception_ref(self_, exception);
+  StackHandleScope<1> hs(self_);
+  Handle<mirror::Throwable> exception_ref(hs.NewHandle(exception));
 
   // Walk the stack to find catch handler or prepare for deoptimization.
-  CatchBlockStackVisitor visitor(self_, context_, exception_ref, this);
+  CatchBlockStackVisitor visitor(self_, context_, &exception_ref, this);
   visitor.WalkStack(true);
 
   mirror::ArtMethod* catch_method = *handler_quick_frame_;
@@ -56,13 +57,13 @@
     DCHECK(!self_->IsExceptionPending());
   } else {
     // Put exception back in root set with clear throw location.
-    self_->SetException(ThrowLocation(), exception_ref.get());
+    self_->SetException(ThrowLocation(), exception_ref.Get());
   }
   // The debugger may suspend this thread and walk its stack. Let's do this before popping
   // instrumentation frames.
   instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
   instrumentation->ExceptionCaughtEvent(self_, throw_location, catch_method, handler_dex_pc_,
-                                        exception_ref.get());
+                                        exception_ref.Get());
 }
 
 void QuickExceptionHandler::DeoptimizeStack() {
diff --git a/runtime/reflection.cc b/runtime/reflection.cc
index f0ba003..98310e6 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -467,11 +467,12 @@
 
   mirror::Class* declaring_class = m->GetDeclaringClass();
   if (UNLIKELY(!declaring_class->IsInitialized())) {
-    SirtRef<mirror::Class> sirt_c(soa.Self(), declaring_class);
-    if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(sirt_c, true, true)) {
+    StackHandleScope<1> hs(soa.Self());
+    Handle<mirror::Class> h_class(hs.NewHandle(declaring_class));
+    if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(h_class, true, true)) {
       return nullptr;
     }
-    declaring_class = sirt_c.get();
+    declaring_class = h_class.Get();
   }
 
   mirror::Object* receiver = nullptr;
diff --git a/runtime/reflection_test.cc b/runtime/reflection_test.cc
index f7fc020..3b66abe 100644
--- a/runtime/reflection_test.cc
+++ b/runtime/reflection_test.cc
@@ -87,10 +87,10 @@
     const char* class_name = is_static ? "StaticLeafMethods" : "NonStaticLeafMethods";
     jobject jclass_loader(LoadDex(class_name));
     Thread* self = Thread::Current();
-    SirtRef<mirror::ClassLoader> null_class_loader(self, nullptr);
-    SirtRef<mirror::ClassLoader>
-        class_loader(self,
-                     ScopedObjectAccessUnchecked(self).Decode<mirror::ClassLoader*>(jclass_loader));
+    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);
@@ -485,8 +485,9 @@
   TEST_DISABLED_FOR_PORTABLE();
   ScopedObjectAccess soa(Thread::Current());
   jobject jclass_loader = LoadDex("Main");
-  SirtRef<mirror::ClassLoader>
-      class_loader(soa.Self(), soa.Decode<mirror::ClassLoader*>(jclass_loader));
+  StackHandleScope<1> hs(soa.Self());
+  Handle<mirror::ClassLoader> class_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-inl.h b/runtime/runtime-inl.h
new file mode 100644
index 0000000..29ddd1d
--- /dev/null
+++ b/runtime/runtime-inl.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2014 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_RUNTIME_INL_H_
+#define ART_RUNTIME_RUNTIME_INL_H_
+
+#include "runtime.h"
+
+namespace art {
+
+inline QuickMethodFrameInfo Runtime::GetRuntimeMethodFrameInfo(mirror::ArtMethod* method) const {
+  DCHECK(method != nullptr);
+  // Cannot be imt-conflict-method or resolution-method.
+  DCHECK(method != GetImtConflictMethod());
+  DCHECK(method != GetResolutionMethod());
+  // Don't use GetCalleeSaveMethod(), some tests don't set all callee save methods.
+  if (method == callee_save_methods_[Runtime::kRefsAndArgs]) {
+    return GetCalleeSaveMethodFrameInfo(Runtime::kRefsAndArgs);
+  } else if (method == callee_save_methods_[Runtime::kSaveAll]) {
+    return GetCalleeSaveMethodFrameInfo(Runtime::kSaveAll);
+  } else {
+    DCHECK(method == callee_save_methods_[Runtime::kRefsOnly]);
+    return GetCalleeSaveMethodFrameInfo(Runtime::kRefsOnly);
+  }
+}
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_RUNTIME_INL_H_
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index d78be92..78a93fd 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -30,10 +30,15 @@
 #include <vector>
 #include <fcntl.h>
 
+#include "arch/arm/quick_method_frame_info_arm.h"
 #include "arch/arm/registers_arm.h"
+#include "arch/arm64/quick_method_frame_info_arm64.h"
 #include "arch/arm64/registers_arm64.h"
+#include "arch/mips/quick_method_frame_info_mips.h"
 #include "arch/mips/registers_mips.h"
+#include "arch/x86/quick_method_frame_info_x86.h"
 #include "arch/x86/registers_x86.h"
+#include "arch/x86_64/quick_method_frame_info_x86_64.h"
 #include "arch/x86_64/registers_x86_64.h"
 #include "atomic.h"
 #include "class_linker.h"
@@ -55,12 +60,13 @@
 #include "monitor.h"
 #include "parsed_options.h"
 #include "oat_file.h"
+#include "quick/quick_method_frame_info.h"
 #include "reflection.h"
 #include "ScopedLocalRef.h"
 #include "scoped_thread_state_change.h"
 #include "signal_catcher.h"
 #include "signal_set.h"
-#include "sirt_ref.h"
+#include "handle_scope-inl.h"
 #include "thread.h"
 #include "thread_list.h"
 #include "trace.h"
@@ -88,6 +94,7 @@
       resolution_method_(nullptr),
       imt_conflict_method_(nullptr),
       default_imt_(nullptr),
+      instruction_set_(kNone),
       compiler_callbacks_(nullptr),
       is_zygote_(false),
       is_concurrent_gc_enabled_(true),
@@ -202,6 +209,8 @@
     Thread* self = Thread::Current();
     if (self == nullptr) {
       os << "(Aborting thread was not attached to runtime!)\n";
+      DumpKernelStack(os, GetTid(), "  kernel: ", false);
+      DumpNativeStack(os, GetTid(), "  native: ", nullptr);
     } else {
       os << "Aborting thread:\n";
       if (Locks::mutator_lock_->IsExclusiveHeld(self) || Locks::mutator_lock_->IsSharedHeld(self)) {
@@ -322,8 +331,9 @@
   ScopedObjectAccess soa(Thread::Current());
   ClassLinker* cl = Runtime::Current()->GetClassLinker();
 
-  SirtRef<mirror::Class> class_loader_class(
-      soa.Self(), soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_ClassLoader));
+  StackHandleScope<3> hs(soa.Self());
+  Handle<mirror::Class> class_loader_class(
+      hs.NewHandle(soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_ClassLoader)));
   CHECK(cl->EnsureInitialized(class_loader_class, true, true));
 
   mirror::ArtMethod* getSystemClassLoader =
@@ -331,19 +341,18 @@
   CHECK(getSystemClassLoader != NULL);
 
   JValue result = InvokeWithJValues(soa, nullptr, soa.EncodeMethod(getSystemClassLoader), nullptr);
-  SirtRef<mirror::ClassLoader> class_loader(soa.Self(),
-                                            down_cast<mirror::ClassLoader*>(result.GetL()));
-  CHECK(class_loader.get() != nullptr);
+  Handle<mirror::ClassLoader> class_loader(
+      hs.NewHandle(down_cast<mirror::ClassLoader*>(result.GetL())));
+  CHECK(class_loader.Get() != nullptr);
   JNIEnv* env = soa.Self()->GetJniEnv();
   ScopedLocalRef<jobject> system_class_loader(env,
-                                              soa.AddLocalReference<jobject>(class_loader.get()));
+                                              soa.AddLocalReference<jobject>(class_loader.Get()));
   CHECK(system_class_loader.get() != nullptr);
 
-  soa.Self()->SetClassLoaderOverride(class_loader.get());
+  soa.Self()->SetClassLoaderOverride(class_loader.Get());
 
-  SirtRef<mirror::Class> thread_class(
-      soa.Self(),
-      soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_Thread));
+  Handle<mirror::Class> thread_class(
+      hs.NewHandle(soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_Thread)));
   CHECK(cl->EnsureInitialized(thread_class, true, true));
 
   mirror::ArtField* contextClassLoader =
@@ -351,7 +360,7 @@
   CHECK(contextClassLoader != NULL);
 
   // We can't run in a transaction yet.
-  contextClassLoader->SetObject<false>(soa.Self()->GetPeer(), class_loader.get());
+  contextClassLoader->SetObject<false>(soa.Self()->GetPeer(), class_loader.Get());
 
   return env->NewGlobalRef(system_class_loader.get());
 }
@@ -673,7 +682,8 @@
     std::string mapped_name(StringPrintf(OS_SHARED_LIB_FORMAT_STR, "javacore"));
     std::string reason;
     self->TransitionFromSuspendedToRunnable();
-    SirtRef<mirror::ClassLoader> class_loader(self, nullptr);
+    StackHandleScope<1> hs(self);
+    auto class_loader(hs.NewHandle<mirror::ClassLoader>(nullptr));
     if (!instance_->java_vm_->LoadNativeLibrary(mapped_name, class_loader, &reason)) {
       LOG(FATAL) << "LoadNativeLibrary failed for \"" << mapped_name << "\": " << reason;
     }
@@ -929,25 +939,28 @@
 }
 
 void Runtime::VisitRoots(RootCallback* callback, void* arg, VisitRootFlags flags) {
-  VisitConcurrentRoots(callback, arg, flags);
   VisitNonConcurrentRoots(callback, arg);
+  VisitConcurrentRoots(callback, arg, flags);
 }
 
 mirror::ObjectArray<mirror::ArtMethod>* Runtime::CreateDefaultImt(ClassLinker* cl) {
   Thread* self = Thread::Current();
-  SirtRef<mirror::ObjectArray<mirror::ArtMethod> > imtable(self, cl->AllocArtMethodArray(self, 64));
+  StackHandleScope<1> hs(self);
+  Handle<mirror::ObjectArray<mirror::ArtMethod>> imtable(
+      hs.NewHandle(cl->AllocArtMethodArray(self, 64)));
   mirror::ArtMethod* imt_conflict_method = Runtime::Current()->GetImtConflictMethod();
   for (size_t i = 0; i < static_cast<size_t>(imtable->GetLength()); i++) {
     imtable->Set<false>(i, imt_conflict_method);
   }
-  return imtable.get();
+  return imtable.Get();
 }
 
 mirror::ArtMethod* Runtime::CreateImtConflictMethod() {
   Thread* self = Thread::Current();
   Runtime* runtime = Runtime::Current();
   ClassLinker* class_linker = runtime->GetClassLinker();
-  SirtRef<mirror::ArtMethod> method(self, class_linker->AllocArtMethod(self));
+  StackHandleScope<1> hs(self);
+  Handle<mirror::ArtMethod> method(hs.NewHandle(class_linker->AllocArtMethod(self)));
   method->SetDeclaringClass(mirror::ArtMethod::GetJavaLangReflectArtMethod());
   // TODO: use a special method for imt conflict method saves.
   method->SetDexMethodIndex(DexFile::kDexNoIndex);
@@ -959,14 +972,15 @@
     method->SetEntryPointFromPortableCompiledCode(GetPortableImtConflictTrampoline(class_linker));
     method->SetEntryPointFromQuickCompiledCode(GetQuickImtConflictTrampoline(class_linker));
   }
-  return method.get();
+  return method.Get();
 }
 
 mirror::ArtMethod* Runtime::CreateResolutionMethod() {
   Thread* self = Thread::Current();
   Runtime* runtime = Runtime::Current();
   ClassLinker* class_linker = runtime->GetClassLinker();
-  SirtRef<mirror::ArtMethod> method(self, class_linker->AllocArtMethod(self));
+  StackHandleScope<1> hs(self);
+  Handle<mirror::ArtMethod> method(hs.NewHandle(class_linker->AllocArtMethod(self)));
   method->SetDeclaringClass(mirror::ArtMethod::GetJavaLangReflectArtMethod());
   // TODO: use a special method for resolution method saves
   method->SetDexMethodIndex(DexFile::kDexNoIndex);
@@ -978,133 +992,22 @@
     method->SetEntryPointFromPortableCompiledCode(GetPortableResolutionTrampoline(class_linker));
     method->SetEntryPointFromQuickCompiledCode(GetQuickResolutionTrampoline(class_linker));
   }
-  return method.get();
+  return method.Get();
 }
 
-mirror::ArtMethod* Runtime::CreateCalleeSaveMethod(InstructionSet instruction_set,
-                                                   CalleeSaveType type) {
+mirror::ArtMethod* Runtime::CreateCalleeSaveMethod(CalleeSaveType type) {
   Thread* self = Thread::Current();
   Runtime* runtime = Runtime::Current();
   ClassLinker* class_linker = runtime->GetClassLinker();
-  SirtRef<mirror::ArtMethod> method(self, class_linker->AllocArtMethod(self));
+  StackHandleScope<1> hs(self);
+  Handle<mirror::ArtMethod> method(hs.NewHandle(class_linker->AllocArtMethod(self)));
   method->SetDeclaringClass(mirror::ArtMethod::GetJavaLangReflectArtMethod());
   // TODO: use a special method for callee saves
   method->SetDexMethodIndex(DexFile::kDexNoIndex);
   method->SetEntryPointFromPortableCompiledCode(nullptr);
   method->SetEntryPointFromQuickCompiledCode(nullptr);
-  if ((instruction_set == kThumb2) || (instruction_set == kArm)) {
-    uint32_t ref_spills = (1 << art::arm::R5) | (1 << art::arm::R6)  | (1 << art::arm::R7) |
-                          (1 << art::arm::R8) | (1 << art::arm::R10) | (1 << art::arm::R11);
-    uint32_t arg_spills = (1 << art::arm::R1) | (1 << art::arm::R2) | (1 << art::arm::R3);
-    uint32_t all_spills = (1 << art::arm::R4) | (1 << art::arm::R9);
-    uint32_t core_spills = ref_spills | (type == kRefsAndArgs ? arg_spills : 0) |
-                           (type == kSaveAll ? all_spills : 0) | (1 << art::arm::LR);
-    uint32_t fp_all_spills = (1 << art::arm::S0)  | (1 << art::arm::S1)  | (1 << art::arm::S2) |
-                             (1 << art::arm::S3)  | (1 << art::arm::S4)  | (1 << art::arm::S5) |
-                             (1 << art::arm::S6)  | (1 << art::arm::S7)  | (1 << art::arm::S8) |
-                             (1 << art::arm::S9)  | (1 << art::arm::S10) | (1 << art::arm::S11) |
-                             (1 << art::arm::S12) | (1 << art::arm::S13) | (1 << art::arm::S14) |
-                             (1 << art::arm::S15) | (1 << art::arm::S16) | (1 << art::arm::S17) |
-                             (1 << art::arm::S18) | (1 << art::arm::S19) | (1 << art::arm::S20) |
-                             (1 << art::arm::S21) | (1 << art::arm::S22) | (1 << art::arm::S23) |
-                             (1 << art::arm::S24) | (1 << art::arm::S25) | (1 << art::arm::S26) |
-                             (1 << art::arm::S27) | (1 << art::arm::S28) | (1 << art::arm::S29) |
-                             (1 << art::arm::S30) | (1 << art::arm::S31);
-    uint32_t fp_spills = type == kSaveAll ? fp_all_spills : 0;
-    size_t frame_size = RoundUp((POPCOUNT(core_spills) /* gprs */ +
-                                 POPCOUNT(fp_spills) /* fprs */ +
-                                 1 /* Method* */) * kArmPointerSize, kStackAlignment);
-    method->SetFrameSizeInBytes(frame_size);
-    method->SetCoreSpillMask(core_spills);
-    method->SetFpSpillMask(fp_spills);
-  } else if (instruction_set == kMips) {
-    uint32_t ref_spills = (1 << art::mips::S2) | (1 << art::mips::S3) | (1 << art::mips::S4) |
-                          (1 << art::mips::S5) | (1 << art::mips::S6) | (1 << art::mips::S7) |
-                          (1 << art::mips::GP) | (1 << art::mips::FP);
-    uint32_t arg_spills = (1 << art::mips::A1) | (1 << art::mips::A2) | (1 << art::mips::A3);
-    uint32_t all_spills = (1 << art::mips::S0) | (1 << art::mips::S1);
-    uint32_t core_spills = ref_spills | (type == kRefsAndArgs ? arg_spills : 0) |
-                           (type == kSaveAll ? all_spills : 0) | (1 << art::mips::RA);
-    size_t frame_size = RoundUp((POPCOUNT(core_spills) /* gprs */ +
-                                (type == kRefsAndArgs ? 0 : 3) + 1 /* Method* */) *
-                                kMipsPointerSize, kStackAlignment);
-    method->SetFrameSizeInBytes(frame_size);
-    method->SetCoreSpillMask(core_spills);
-    method->SetFpSpillMask(0);
-  } else if (instruction_set == kX86) {
-    uint32_t ref_spills = (1 << art::x86::EBP) | (1 << art::x86::ESI) | (1 << art::x86::EDI);
-    uint32_t arg_spills = (1 << art::x86::ECX) | (1 << art::x86::EDX) | (1 << art::x86::EBX);
-    uint32_t core_spills = ref_spills | (type == kRefsAndArgs ? arg_spills : 0) |
-                         (1 << art::x86::kNumberOfCpuRegisters);  // fake return address callee save
-    size_t frame_size = RoundUp((POPCOUNT(core_spills) /* gprs */ +
-                                 1 /* Method* */) * kX86PointerSize, kStackAlignment);
-    method->SetFrameSizeInBytes(frame_size);
-    method->SetCoreSpillMask(core_spills);
-    method->SetFpSpillMask(0);
-  } else if (instruction_set == kX86_64) {
-    uint32_t ref_spills =
-        (1 << art::x86_64::RBX) | (1 << art::x86_64::RBP) | (1 << art::x86_64::R12) |
-        (1 << art::x86_64::R13) | (1 << art::x86_64::R14) | (1 << art::x86_64::R15);
-    uint32_t arg_spills =
-        (1 << art::x86_64::RSI) | (1 << art::x86_64::RDX) | (1 << art::x86_64::RCX) |
-        (1 << art::x86_64::R8) | (1 << art::x86_64::R9);
-    uint32_t core_spills = ref_spills | (type == kRefsAndArgs ? arg_spills : 0) |
-        (1 << art::x86_64::kNumberOfCpuRegisters);  // fake return address callee save
-    uint32_t fp_arg_spills =
-        (1 << art::x86_64::XMM0) | (1 << art::x86_64::XMM1) | (1 << art::x86_64::XMM2) |
-        (1 << art::x86_64::XMM3) | (1 << art::x86_64::XMM4) | (1 << art::x86_64::XMM5) |
-        (1 << art::x86_64::XMM6) | (1 << art::x86_64::XMM7);
-    uint32_t fp_spills = (type == kRefsAndArgs ? fp_arg_spills : 0);
-    size_t frame_size = RoundUp((POPCOUNT(core_spills) /* gprs */ +
-                                 POPCOUNT(fp_spills) /* fprs */ +
-                                 1 /* Method* */) * kX86_64PointerSize, kStackAlignment);
-    method->SetFrameSizeInBytes(frame_size);
-    method->SetCoreSpillMask(core_spills);
-    method->SetFpSpillMask(fp_spills);
-  } else if (instruction_set == kArm64) {
-      // Callee saved registers
-      uint32_t ref_spills = (1 << art::arm64::X19) | (1 << art::arm64::X20) | (1 << art::arm64::X21) |
-                            (1 << art::arm64::X22) | (1 << art::arm64::X23) | (1 << art::arm64::X24) |
-                            (1 << art::arm64::X25) | (1 << art::arm64::X26) | (1 << art::arm64::X27) |
-                            (1 << art::arm64::X28);
-      // X0 is the method pointer. Not saved.
-      uint32_t arg_spills = (1 << art::arm64::X1) | (1 << art::arm64::X2) | (1 << art::arm64::X3) |
-                            (1 << art::arm64::X4) | (1 << art::arm64::X5) | (1 << art::arm64::X6) |
-                            (1 << art::arm64::X7);
-      // TODO  This is conservative. Only ALL should include the thread register.
-      // The thread register is not preserved by the aapcs64.
-      // LR is always saved.
-      uint32_t all_spills =  0;  // (1 << art::arm64::LR);
-      uint32_t core_spills = ref_spills | (type == kRefsAndArgs ? arg_spills : 0) |
-                             (type == kSaveAll ? all_spills : 0) | (1 << art::arm64::FP)
-                             | (1 << art::arm64::X18) | (1 << art::arm64::LR);
-
-      // Save callee-saved floating point registers. Rest are scratch/parameters.
-      uint32_t fp_arg_spills = (1 << art::arm64::D0) | (1 << art::arm64::D1) | (1 << art::arm64::D2) |
-                            (1 << art::arm64::D3) | (1 << art::arm64::D4) | (1 << art::arm64::D5) |
-                            (1 << art::arm64::D6) | (1 << art::arm64::D7);
-      uint32_t fp_ref_spills = (1 << art::arm64::D8)  | (1 << art::arm64::D9)  | (1 << art::arm64::D10) |
-                               (1 << art::arm64::D11)  | (1 << art::arm64::D12)  | (1 << art::arm64::D13) |
-                               (1 << art::arm64::D14)  | (1 << art::arm64::D15);
-      uint32_t fp_all_spills = fp_arg_spills |
-                          (1 << art::arm64::D16)  | (1 << art::arm64::D17) | (1 << art::arm64::D18) |
-                          (1 << art::arm64::D19)  | (1 << art::arm64::D20) | (1 << art::arm64::D21) |
-                          (1 << art::arm64::D22)  | (1 << art::arm64::D23) | (1 << art::arm64::D24) |
-                          (1 << art::arm64::D25)  | (1 << art::arm64::D26) | (1 << art::arm64::D27) |
-                          (1 << art::arm64::D28)  | (1 << art::arm64::D29) | (1 << art::arm64::D30) |
-                          (1 << art::arm64::D31);
-      uint32_t fp_spills = fp_ref_spills | (type == kRefsAndArgs ? fp_arg_spills: 0)
-                          | (type == kSaveAll ? fp_all_spills : 0);
-      size_t frame_size = RoundUp((POPCOUNT(core_spills) /* gprs */ +
-                                   POPCOUNT(fp_spills) /* fprs */ +
-                                   1 /* Method* */) * kArm64PointerSize, kStackAlignment);
-      method->SetFrameSizeInBytes(frame_size);
-      method->SetCoreSpillMask(core_spills);
-      method->SetFpSpillMask(fp_spills);
-  } else {
-    UNIMPLEMENTED(FATAL) << instruction_set;
-  }
-  return method.get();
+  DCHECK_NE(instruction_set_, kNone);
+  return method.Get();
 }
 
 void Runtime::DisallowNewSystemWeaks() {
@@ -1121,6 +1024,38 @@
   Dbg::AllowNewObjectRegistryObjects();
 }
 
+void Runtime::SetInstructionSet(InstructionSet instruction_set) {
+  instruction_set_ = instruction_set;
+  if ((instruction_set_ == kThumb2) || (instruction_set_ == kArm)) {
+    for (int i = 0; i != kLastCalleeSaveType; ++i) {
+      CalleeSaveType type = static_cast<CalleeSaveType>(i);
+      callee_save_method_frame_infos_[i] = arm::ArmCalleeSaveMethodFrameInfo(type);
+    }
+  } else if (instruction_set_ == kMips) {
+    for (int i = 0; i != kLastCalleeSaveType; ++i) {
+      CalleeSaveType type = static_cast<CalleeSaveType>(i);
+      callee_save_method_frame_infos_[i] = mips::MipsCalleeSaveMethodFrameInfo(type);
+    }
+  } else if (instruction_set_ == kX86) {
+    for (int i = 0; i != kLastCalleeSaveType; ++i) {
+      CalleeSaveType type = static_cast<CalleeSaveType>(i);
+      callee_save_method_frame_infos_[i] = x86::X86CalleeSaveMethodFrameInfo(type);
+    }
+  } else if (instruction_set_ == kX86_64) {
+    for (int i = 0; i != kLastCalleeSaveType; ++i) {
+      CalleeSaveType type = static_cast<CalleeSaveType>(i);
+      callee_save_method_frame_infos_[i] = x86_64::X86_64CalleeSaveMethodFrameInfo(type);
+    }
+  } else if (instruction_set_ == kArm64) {
+    for (int i = 0; i != kLastCalleeSaveType; ++i) {
+      CalleeSaveType type = static_cast<CalleeSaveType>(i);
+      callee_save_method_frame_infos_[i] = arm64::Arm64CalleeSaveMethodFrameInfo(type);
+    }
+  } else {
+    UNIMPLEMENTED(FATAL) << instruction_set_;
+  }
+}
+
 void Runtime::SetCalleeSaveMethod(mirror::ArtMethod* method, CalleeSaveType type) {
   DCHECK_LT(static_cast<int>(type), static_cast<int>(kLastCalleeSaveType));
   callee_save_methods_[type] = method;
@@ -1272,17 +1207,9 @@
   // Make the dex2oat instruction set match that of the launching runtime. If we have multiple
   // architecture support, dex2oat may be compiled as a different instruction-set than that
   // currently being executed.
-#if defined(__arm__)
-  argv->push_back("--instruction-set=arm");
-#elif defined(__aarch64__)
-  argv->push_back("--instruction-set=arm64");
-#elif defined(__i386__)
-  argv->push_back("--instruction-set=x86");
-#elif defined(__x86_64__)
-  argv->push_back("--instruction-set=x86_64");
-#elif defined(__mips__)
-  argv->push_back("--instruction-set=mips");
-#endif
+  std::string instruction_set("--instruction-set=");
+  instruction_set += GetInstructionSetString(kRuntimeISA);
+  argv->push_back(instruction_set);
 
   std::string features("--instruction-set-features=");
   features += GetDefaultInstructionSetFeatures();
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 1ee0b1a..07b47c3 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -34,6 +34,7 @@
 #include "instrumentation.h"
 #include "jobject_comparator.h"
 #include "object_callbacks.h"
+#include "quick/quick_method_frame_info.h"
 #include "runtime_stats.h"
 #include "safe_map.h"
 #include "fault_handler.h"
@@ -325,20 +326,25 @@
     return callee_save_methods_[type];
   }
 
+  QuickMethodFrameInfo GetCalleeSaveMethodFrameInfo(CalleeSaveType type) const {
+    return callee_save_method_frame_infos_[type];
+  }
+
+  QuickMethodFrameInfo GetRuntimeMethodFrameInfo(mirror::ArtMethod* method) const;
+
   static size_t GetCalleeSaveMethodOffset(CalleeSaveType type) {
     return OFFSETOF_MEMBER(Runtime, callee_save_methods_[type]);
   }
 
+  InstructionSet GetInstructionSet() const {
+    return instruction_set_;
+  }
+
+  void SetInstructionSet(InstructionSet instruction_set);
+
   void SetCalleeSaveMethod(mirror::ArtMethod* method, CalleeSaveType type);
 
-  mirror::ArtMethod* CreateCalleeSaveMethod(InstructionSet instruction_set,
-                                                 CalleeSaveType type)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
-  mirror::ArtMethod* CreateRefOnlyCalleeSaveMethod(InstructionSet instruction_set)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
-  mirror::ArtMethod* CreateRefAndArgsCalleeSaveMethod(InstructionSet instruction_set)
+  mirror::ArtMethod* CreateCalleeSaveMethod(CalleeSaveType type)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   int32_t GetStat(int kind);
@@ -468,6 +474,9 @@
   mirror::ArtMethod* imt_conflict_method_;
   mirror::ObjectArray<mirror::ArtMethod>* default_imt_;
 
+  InstructionSet instruction_set_;
+  QuickMethodFrameInfo callee_save_method_frame_infos_[kLastCalleeSaveType];
+
   CompilerCallbacks* compiler_callbacks_;
   bool is_zygote_;
   bool is_concurrent_gc_enabled_;
diff --git a/runtime/scoped_thread_state_change.h b/runtime/scoped_thread_state_change.h
index 7698d6a..dbd961f 100644
--- a/runtime/scoped_thread_state_change.h
+++ b/runtime/scoped_thread_state_change.h
@@ -25,7 +25,7 @@
 
 // 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,
+// 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:
diff --git a/runtime/sirt_ref-inl.h b/runtime/sirt_ref-inl.h
deleted file mode 100644
index 7de624a..0000000
--- a/runtime/sirt_ref-inl.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2014 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_SIRT_REF_INL_H_
-#define ART_RUNTIME_SIRT_REF_INL_H_
-
-#include "sirt_ref.h"
-
-#include "verify_object-inl.h"
-
-namespace art {
-
-template<class T> inline SirtRef<T>::SirtRef(Thread* self, T* object, bool should_verify)
-  : self_(self), sirt_(object) {
-  if (should_verify) {
-    VerifyObject(object);
-  }
-  self_->PushSirt(&sirt_);
-}
-
-template<class T> inline SirtRef<T>::~SirtRef() {
-  StackIndirectReferenceTable* top_sirt = self_->PopSirt();
-  DCHECK_EQ(top_sirt, &sirt_);
-}
-
-template<class T> inline T* SirtRef<T>::reset(T* object, bool should_verify) {
-  if (should_verify) {
-    VerifyObject(object);
-  }
-  T* old_ref = get();
-  sirt_.SetReference(0, object);
-  return old_ref;
-}
-
-}  // namespace art
-
-#endif  // ART_RUNTIME_SIRT_REF_INL_H_
diff --git a/runtime/sirt_ref.h b/runtime/sirt_ref.h
deleted file mode 100644
index cf23891..0000000
--- a/runtime/sirt_ref.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2011 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_SIRT_REF_H_
-#define ART_RUNTIME_SIRT_REF_H_
-
-#include "base/casts.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "stack_indirect_reference_table.h"
-#include "thread.h"
-
-namespace art {
-
-template<class T>
-class SirtRef {
- public:
-  SirtRef(Thread* self, T* object, bool should_verify = true);
-  ~SirtRef();
-
-  T& operator*() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return *get();
-  }
-  T* operator->() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return get();
-  }
-  T* get() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return down_cast<T*>(sirt_.GetReference(0));
-  }
-
-  // Returns the old reference.
-  T* reset(T* object = nullptr, bool should_verify = true)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
- private:
-  Thread* const self_;
-  StackIndirectReferenceTable sirt_;
-
-  DISALLOW_COPY_AND_ASSIGN(SirtRef);
-};
-
-// A version of SirtRef which disables the object verification.
-template<class T>
-class SirtRefNoVerify : public SirtRef<T> {
- public:
-  SirtRefNoVerify(Thread* self, T* object) : SirtRef<T>(self, object, false) {}
-  // Returns the old reference.
-  T* reset(T* object = nullptr) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return SirtRef<T>::reset(object, false);
-  }
-};
-
-}  // namespace art
-
-#endif  // ART_RUNTIME_SIRT_REF_H_
diff --git a/runtime/stack.cc b/runtime/stack.cc
index 5e64e59..e0189e9 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -23,6 +23,7 @@
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
 #include "object_utils.h"
+#include "quick/quick_method_frame_info.h"
 #include "runtime.h"
 #include "thread.h"
 #include "thread_list.h"
@@ -110,11 +111,9 @@
     return NULL;
   } else if (m->IsNative()) {
     if (cur_quick_frame_ != NULL) {
-      StackIndirectReferenceTable* sirt =
-          reinterpret_cast<StackIndirectReferenceTable*>(
-              reinterpret_cast<char*>(cur_quick_frame_) +
-              m->GetSirtOffsetInBytes());
-      return sirt->GetReference(0);
+      HandleScope* hs = reinterpret_cast<HandleScope*>(
+          reinterpret_cast<char*>(cur_quick_frame_) + m->GetHandleScopeOffsetInBytes());
+      return hs->GetReference(0);
     } else {
       return cur_shadow_frame_->GetVRegReference(0);
     }
@@ -142,18 +141,17 @@
     DCHECK(m == GetMethod());
     const VmapTable vmap_table(m->GetVmapTable());
     uint32_t vmap_offset;
+    QuickMethodFrameInfo frame_info = m->GetQuickFrameInfo();
     // TODO: IsInContext stops before spotting floating point registers.
     if (vmap_table.IsInContext(vreg, kind, &vmap_offset)) {
       bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg);
-      uint32_t spill_mask = is_float ? m->GetFpSpillMask()
-                                     : m->GetCoreSpillMask();
+      uint32_t spill_mask = is_float ? frame_info.FpSpillMask() : frame_info.CoreSpillMask();
       return GetGPR(vmap_table.ComputeRegister(spill_mask, vmap_offset, kind));
     } else {
       const DexFile::CodeItem* code_item = MethodHelper(m).GetCodeItem();
       DCHECK(code_item != NULL) << PrettyMethod(m);  // Can't be NULL or how would we compile its instructions?
-      size_t frame_size = m->GetFrameSizeInBytes();
-      return *GetVRegAddr(cur_quick_frame_, code_item, m->GetCoreSpillMask(), m->GetFpSpillMask(),
-                          frame_size, vreg);
+      return *GetVRegAddr(cur_quick_frame_, code_item, frame_info.CoreSpillMask(),
+                          frame_info.FpSpillMask(), frame_info.FrameSizeInBytes(), vreg);
     }
   } else {
     return cur_shadow_frame_->GetVReg(vreg);
@@ -167,19 +165,18 @@
     DCHECK(m == GetMethod());
     const VmapTable vmap_table(m->GetVmapTable());
     uint32_t vmap_offset;
+    QuickMethodFrameInfo frame_info = m->GetQuickFrameInfo();
     // TODO: IsInContext stops before spotting floating point registers.
     if (vmap_table.IsInContext(vreg, kind, &vmap_offset)) {
       bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg);
-      uint32_t spill_mask = is_float ? m->GetFpSpillMask() : m->GetCoreSpillMask();
+      uint32_t spill_mask = is_float ? frame_info.FpSpillMask() : frame_info.CoreSpillMask();
       const uint32_t reg = vmap_table.ComputeRegister(spill_mask, vmap_offset, kReferenceVReg);
       SetGPR(reg, new_value);
     } else {
       const DexFile::CodeItem* code_item = MethodHelper(m).GetCodeItem();
       DCHECK(code_item != NULL) << PrettyMethod(m);  // Can't be NULL or how would we compile its instructions?
-      uint32_t core_spills = m->GetCoreSpillMask();
-      uint32_t fp_spills = m->GetFpSpillMask();
-      size_t frame_size = m->GetFrameSizeInBytes();
-      int offset = GetVRegOffset(code_item, core_spills, fp_spills, frame_size, vreg, kRuntimeISA);
+      int offset = GetVRegOffset(code_item, frame_info.CoreSpillMask(), frame_info.FpSpillMask(),
+                                 frame_info.FrameSizeInBytes(), vreg, kRuntimeISA);
       byte* vreg_addr = reinterpret_cast<byte*>(GetCurrentQuickFrame()) + offset;
       *reinterpret_cast<uint32_t*>(vreg_addr) = new_value;
     }
@@ -270,7 +267,7 @@
 void StackVisitor::SanityCheckFrame() const {
   if (kIsDebugBuild) {
     mirror::ArtMethod* method = GetMethod();
-    CHECK(method->GetClass() == mirror::ArtMethod::GetJavaLangReflectArtMethod());
+    CHECK_EQ(method->GetClass(), mirror::ArtMethod::GetJavaLangReflectArtMethod());
     if (cur_quick_frame_ != nullptr) {
       method->AssertPcIsWithinQuickCode(cur_quick_frame_pc_);
       // Frame sanity.
@@ -278,7 +275,7 @@
       CHECK_NE(frame_size, 0u);
       // A rough guess at an upper size we expect to see for a frame.
       // 256 registers
-      // 2 words Sirt overhead
+      // 2 words HandleScope overhead
       // 3+3 register spills
       // TODO: this seems architecture specific for the case of JNI frames.
       // TODO: 083-compiler-regressions ManyFloatArgs shows this estimate is wrong.
diff --git a/runtime/stack.h b/runtime/stack.h
index 88ef78f..963983a 100644
--- a/runtime/stack.h
+++ b/runtime/stack.h
@@ -40,7 +40,7 @@
 
 class Context;
 class ShadowFrame;
-class StackIndirectReferenceTable;
+class HandleScope;
 class ScopedObjectAccess;
 class Thread;
 
@@ -677,10 +677,10 @@
     return cur_shadow_frame_;
   }
 
-  StackIndirectReferenceTable* GetCurrentSirt() const {
+  HandleScope* GetCurrentHandleScope() const {
     mirror::ArtMethod** sp = GetCurrentQuickFrame();
-    ++sp;  // Skip Method*; SIRT comes next;
-    return reinterpret_cast<StackIndirectReferenceTable*>(sp);
+    ++sp;  // Skip Method*; handle scope comes next;
+    return reinterpret_cast<HandleScope*>(sp);
   }
 
   std::string DescribeLocation() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/stack_indirect_reference_table.h b/runtime/stack_indirect_reference_table.h
deleted file mode 100644
index 3b632e7..0000000
--- a/runtime/stack_indirect_reference_table.h
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright (C) 2011 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_STACK_INDIRECT_REFERENCE_TABLE_H_
-#define ART_RUNTIME_STACK_INDIRECT_REFERENCE_TABLE_H_
-
-#include "base/logging.h"
-#include "base/macros.h"
-#include "stack.h"
-#include "utils.h"
-
-namespace art {
-namespace mirror {
-class Object;
-}
-class Thread;
-
-// Stack allocated indirect reference table. It can allocated within
-// the bridge frame between managed and native code backed by stack
-// storage or manually allocated by SirtRef to hold one reference.
-class StackIndirectReferenceTable {
- public:
-  explicit StackIndirectReferenceTable(mirror::Object* object) :
-      link_(NULL), number_of_references_(1) {
-    references_[0].Assign(object);
-  }
-
-  ~StackIndirectReferenceTable() {}
-
-  // Number of references contained within this SIRT.
-  uint32_t NumberOfReferences() const {
-    return number_of_references_;
-  }
-
-  // We have versions with and without explicit pointer size of the following. The first two are
-  // used at runtime, so OFFSETOF_MEMBER computes the right offsets automatically. The last one
-  // takes the pointer size explicitly so that at compile time we can cross-compile correctly.
-
-  // Returns the size of a StackIndirectReferenceTable containing num_references sirts.
-  static size_t SizeOf(uint32_t num_references) {
-    size_t header_size = OFFSETOF_MEMBER(StackIndirectReferenceTable, references_);
-    size_t data_size = sizeof(StackReference<mirror::Object>) * num_references;
-    return header_size + data_size;
-  }
-
-  // Get the size of the SIRT for the number of entries, with padding added for potential alignment.
-  static size_t GetAlignedSirtSize(uint32_t num_references) {
-    size_t sirt_size = SizeOf(num_references);
-    return RoundUp(sirt_size, 8);
-  }
-
-  // Get the size of the SIRT for the number of entries, with padding added for potential alignment.
-  static size_t GetAlignedSirtSizeTarget(size_t pointer_size, uint32_t num_references) {
-    // Assume that the layout is packed.
-    size_t header_size = pointer_size + sizeof(number_of_references_);
-    // This assumes there is no layout change between 32 and 64b.
-    size_t data_size = sizeof(StackReference<mirror::Object>) * num_references;
-    size_t sirt_size = header_size + data_size;
-    return RoundUp(sirt_size, 8);
-  }
-
-  // Link to previous SIRT or NULL.
-  StackIndirectReferenceTable* GetLink() const {
-    return link_;
-  }
-
-  void SetLink(StackIndirectReferenceTable* sirt) {
-    DCHECK_NE(this, sirt);
-    link_ = sirt;
-  }
-
-  // Sets the number_of_references_ field for constructing tables out of raw memory. Warning: will
-  // not resize anything.
-  void SetNumberOfReferences(uint32_t num_references) {
-    number_of_references_ = num_references;
-  }
-
-  mirror::Object* GetReference(size_t i) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    DCHECK_LT(i, number_of_references_);
-    return references_[i].AsMirrorPtr();
-  }
-
-  StackReference<mirror::Object>* GetStackReference(size_t i)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    DCHECK_LT(i, number_of_references_);
-    return &references_[i];
-  }
-
-  void SetReference(size_t i, mirror::Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    DCHECK_LT(i, number_of_references_);
-    references_[i].Assign(object);
-  }
-
-  bool Contains(StackReference<mirror::Object>* sirt_entry) const {
-    // A SIRT should always contain something. One created by the
-    // jni_compiler should have a jobject/jclass as a native method is
-    // passed in a this pointer or a class
-    DCHECK_GT(number_of_references_, 0U);
-    return ((&references_[0] <= sirt_entry)
-            && (sirt_entry <= (&references_[number_of_references_ - 1])));
-  }
-
-  // Offset of link within SIRT, used by generated code
-  static size_t LinkOffset(size_t pointer_size) {
-    return 0;
-  }
-
-  // Offset of length within SIRT, used by generated code
-  static size_t NumberOfReferencesOffset(size_t pointer_size) {
-    return pointer_size;
-  }
-
-  // Offset of link within SIRT, used by generated code
-  static size_t ReferencesOffset(size_t pointer_size) {
-    return pointer_size + sizeof(number_of_references_);
-  }
-
- private:
-  StackIndirectReferenceTable() {}
-
-  StackIndirectReferenceTable* link_;
-  uint32_t number_of_references_;
-
-  // number_of_references_ are available if this is allocated and filled in by jni_compiler.
-  StackReference<mirror::Object> references_[1];
-
-  DISALLOW_COPY_AND_ASSIGN(StackIndirectReferenceTable);
-};
-
-}  // namespace art
-
-#endif  // ART_RUNTIME_STACK_INDIRECT_REFERENCE_TABLE_H_
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 00a66d7..d535118 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -44,6 +44,7 @@
 #include "gc/accounting/card_table-inl.h"
 #include "gc/heap.h"
 #include "gc/space/space.h"
+#include "handle_scope.h"
 #include "indirect_reference_table-inl.h"
 #include "jni_internal.h"
 #include "mirror/art_field-inl.h"
@@ -55,14 +56,14 @@
 #include "monitor.h"
 #include "object_utils.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 "ScopedLocalRef.h"
 #include "ScopedUtfChars.h"
-#include "sirt_ref.h"
+#include "handle_scope-inl.h"
 #include "stack.h"
-#include "stack_indirect_reference_table.h"
 #include "thread-inl.h"
 #include "thread_list.h"
 #include "utils.h"
@@ -156,11 +157,7 @@
     self->tlsPtr_.opeer = soa.Decode<mirror::Object*>(self->tlsPtr_.jpeer);
     self->GetJniEnv()->DeleteGlobalRef(self->tlsPtr_.jpeer);
     self->tlsPtr_.jpeer = nullptr;
-
-    {
-      SirtRef<mirror::String> thread_name(self, self->GetThreadName(soa));
-      self->SetThreadName(thread_name->ToModifiedUtf8().c_str());
-    }
+    self->SetThreadName(self->GetThreadName(soa)->ToModifiedUtf8().c_str());
     Dbg::PostThreadStart(self);
 
     // Invoke the 'run' method of our java.lang.Thread.
@@ -430,8 +427,9 @@
                     reinterpret_cast<jlong>(self));
 
   ScopedObjectAccess soa(self);
-  SirtRef<mirror::String> peer_thread_name(soa.Self(), GetThreadName(soa));
-  if (peer_thread_name.get() == nullptr) {
+  StackHandleScope<1> hs(self);
+  Handle<mirror::String> peer_thread_name(hs.NewHandle(GetThreadName(soa)));
+  if (peer_thread_name.Get() == nullptr) {
     // The Thread constructor should have set the Thread.name to a
     // non-null value. However, because we can run without code
     // available (in the compiler, in tests), we manually assign the
@@ -441,10 +439,10 @@
     } else {
       InitPeer<false>(soa, thread_is_daemon, thread_group, thread_name.get(), thread_priority);
     }
-    peer_thread_name.reset(GetThreadName(soa));
+    peer_thread_name.Assign(GetThreadName(soa));
   }
   // 'thread_name' may have been null, so don't trust 'peer_thread_name' to be non-null.
-  if (peer_thread_name.get() != nullptr) {
+  if (peer_thread_name.Get() != nullptr) {
     SetThreadName(peer_thread_name->ToModifiedUtf8().c_str());
   }
 }
@@ -950,8 +948,7 @@
     // If we're currently in native code, dump that stack before dumping the managed stack.
     if (dump_for_abort || ShouldShowNativeStack(this)) {
       DumpKernelStack(os, GetTid(), "  kernel: ", false);
-      SirtRef<mirror::ArtMethod> method_ref(Thread::Current(), GetCurrentMethod(nullptr));
-      DumpNativeStack(os, GetTid(), "  native: ", method_ref.get());
+      DumpNativeStack(os, GetTid(), "  native: ", GetCurrentMethod(nullptr));
     }
     DumpJavaStack(os);
   } else {
@@ -1106,8 +1103,9 @@
         soa.DecodeField(WellKnownClasses::java_lang_Thread_lock)->GetObject(tlsPtr_.opeer);
     // (This conditional is only needed for tests, where Thread.lock won't have been set.)
     if (lock != nullptr) {
-      SirtRef<mirror::Object> sirt_obj(self, lock);
-      ObjectLock<mirror::Object> locker(self, &sirt_obj);
+      StackHandleScope<1> hs(self);
+      Handle<mirror::Object> h_obj(hs.NewHandle(lock));
+      ObjectLock<mirror::Object> locker(self, &h_obj);
       locker.NotifyAll();
     }
   }
@@ -1207,28 +1205,28 @@
   }
 }
 
-size_t Thread::NumSirtReferences() {
+size_t Thread::NumHandleReferences() {
   size_t count = 0;
-  for (StackIndirectReferenceTable* cur = tlsPtr_.top_sirt; cur; cur = cur->GetLink()) {
+  for (HandleScope* cur = tlsPtr_.top_handle_scope; cur; cur = cur->GetLink()) {
     count += cur->NumberOfReferences();
   }
   return count;
 }
 
-bool Thread::SirtContains(jobject obj) const {
-  StackReference<mirror::Object>* sirt_entry =
+bool Thread::HandleScopeContains(jobject obj) const {
+  StackReference<mirror::Object>* hs_entry =
       reinterpret_cast<StackReference<mirror::Object>*>(obj);
-  for (StackIndirectReferenceTable* cur = tlsPtr_.top_sirt; cur; cur = cur->GetLink()) {
-    if (cur->Contains(sirt_entry)) {
+  for (HandleScope* cur = tlsPtr_.top_handle_scope; cur; cur = cur->GetLink()) {
+    if (cur->Contains(hs_entry)) {
       return true;
     }
   }
-  // JNI code invoked from portable code uses shadow frames rather than the SIRT.
-  return tlsPtr_.managed_stack.ShadowFramesContain(sirt_entry);
+  // JNI code invoked from portable code uses shadow frames rather than the handle scope.
+  return tlsPtr_.managed_stack.ShadowFramesContain(hs_entry);
 }
 
-void Thread::SirtVisitRoots(RootCallback* visitor, void* arg, uint32_t thread_id) {
-  for (StackIndirectReferenceTable* cur = tlsPtr_.top_sirt; cur; cur = cur->GetLink()) {
+void Thread::HandleScopeVisitRoots(RootCallback* visitor, void* arg, uint32_t thread_id) {
+  for (HandleScope* cur = tlsPtr_.top_handle_scope; cur; cur = cur->GetLink()) {
     size_t num_refs = cur->NumberOfReferences();
     for (size_t j = 0; j < num_refs; ++j) {
       mirror::Object* object = cur->GetReference(j);
@@ -1255,11 +1253,11 @@
   if (kind == kLocal) {
     IndirectReferenceTable& locals = tlsPtr_.jni_env->locals;
     result = locals.Get(ref);
-  } else if (kind == kSirtOrInvalid) {
+  } else if (kind == kHandleScopeOrInvalid) {
     // TODO: make stack indirect reference table lookup more efficient.
-    // Check if this is a local reference in the SIRT.
-    if (LIKELY(SirtContains(obj))) {
-      // Read from SIRT.
+    // Check if this is a local reference in the handle scope.
+    if (LIKELY(HandleScopeContains(obj))) {
+      // Read from handle scope.
       result = reinterpret_cast<StackReference<mirror::Object>*>(obj)->AsMirrorPtr();
       VerifyObject(result);
     } else {
@@ -1368,11 +1366,11 @@
   bool Init(int depth)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     // Allocate method trace with an extra slot that will hold the PC trace
-    SirtRef<mirror::ObjectArray<mirror::Object> >
-        method_trace(self_,
-                     Runtime::Current()->GetClassLinker()->AllocObjectArray<mirror::Object>(self_,
-                                                                                            depth + 1));
-    if (method_trace.get() == nullptr) {
+    StackHandleScope<1> hs(self_);
+    ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+    Handle<mirror::ObjectArray<mirror::Object>> method_trace(
+        hs.NewHandle(class_linker->AllocObjectArray<mirror::Object>(self_, depth + 1)));
+    if (method_trace.Get() == nullptr) {
       return false;
     }
     mirror::IntArray* dex_pc_trace = mirror::IntArray::Alloc(self_, depth);
@@ -1387,7 +1385,7 @@
     const char* last_no_suspend_cause =
         self_->StartAssertNoThreadSuspension("Building internal stack trace");
     CHECK(last_no_suspend_cause == nullptr) << last_no_suspend_cause;
-    method_trace_ = method_trace.get();
+    method_trace_ = method_trace.Get();
     dex_pc_trace_ = dex_pc_trace;
     return true;
   }
@@ -1497,11 +1495,12 @@
     mirror::ArtMethod* method = down_cast<mirror::ArtMethod*>(method_trace->Get(i));
     MethodHelper mh(method);
     int32_t line_number;
-    SirtRef<mirror::String> class_name_object(soa.Self(), nullptr);
-    SirtRef<mirror::String> source_name_object(soa.Self(), nullptr);
+    StackHandleScope<3> hs(soa.Self());
+    auto class_name_object(hs.NewHandle<mirror::String>(nullptr));
+    auto source_name_object(hs.NewHandle<mirror::String>(nullptr));
     if (method->IsProxyMethod()) {
       line_number = -1;
-      class_name_object.reset(method->GetDeclaringClass()->GetName());
+      class_name_object.Assign(method->GetDeclaringClass()->GetName());
       // source_name_object intentionally left null for proxy methods
     } else {
       mirror::IntArray* pc_trace = down_cast<mirror::IntArray*>(method_trace->Get(depth));
@@ -1512,24 +1511,23 @@
       const char* descriptor = mh.GetDeclaringClassDescriptor();
       CHECK(descriptor != nullptr);
       std::string class_name(PrettyDescriptor(descriptor));
-      class_name_object.reset(mirror::String::AllocFromModifiedUtf8(soa.Self(), class_name.c_str()));
-      if (class_name_object.get() == nullptr) {
+      class_name_object.Assign(mirror::String::AllocFromModifiedUtf8(soa.Self(), class_name.c_str()));
+      if (class_name_object.Get() == nullptr) {
         return nullptr;
       }
       const char* source_file = mh.GetDeclaringClassSourceFile();
       if (source_file != nullptr) {
-        source_name_object.reset(mirror::String::AllocFromModifiedUtf8(soa.Self(), source_file));
-        if (source_name_object.get() == nullptr) {
+        source_name_object.Assign(mirror::String::AllocFromModifiedUtf8(soa.Self(), source_file));
+        if (source_name_object.Get() == nullptr) {
           return nullptr;
         }
       }
     }
     const char* method_name = mh.GetName();
     CHECK(method_name != nullptr);
-    SirtRef<mirror::String> method_name_object(soa.Self(),
-                                               mirror::String::AllocFromModifiedUtf8(soa.Self(),
-                                                                                     method_name));
-    if (method_name_object.get() == nullptr) {
+    Handle<mirror::String> method_name_object(
+        hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), method_name)));
+    if (method_name_object.Get() == nullptr) {
       return nullptr;
     }
     mirror::StackTraceElement* obj = mirror::StackTraceElement::Alloc(
@@ -1572,23 +1570,24 @@
                                       const char* msg) {
   DCHECK_EQ(this, Thread::Current());
   ScopedObjectAccessUnchecked soa(this);
+  StackHandleScope<5> hs(soa.Self());
   // Ensure we don't forget arguments over object allocation.
-  SirtRef<mirror::Object> saved_throw_this(this, throw_location.GetThis());
-  SirtRef<mirror::ArtMethod> saved_throw_method(this, throw_location.GetMethod());
+  Handle<mirror::Object> saved_throw_this(hs.NewHandle(throw_location.GetThis()));
+  Handle<mirror::ArtMethod> saved_throw_method(hs.NewHandle(throw_location.GetMethod()));
   // Ignore the cause throw location. TODO: should we report this as a re-throw?
   ScopedLocalRef<jobject> cause(GetJniEnv(), soa.AddLocalReference<jobject>(GetException(nullptr)));
   ClearException();
   Runtime* runtime = Runtime::Current();
 
   mirror::ClassLoader* cl = nullptr;
-  if (saved_throw_method.get() != nullptr) {
-    cl = saved_throw_method.get()->GetDeclaringClass()->GetClassLoader();
+  if (saved_throw_method.Get() != nullptr) {
+    cl = saved_throw_method.Get()->GetDeclaringClass()->GetClassLoader();
   }
-  SirtRef<mirror::ClassLoader> class_loader(this, cl);
-  SirtRef<mirror::Class>
-      exception_class(this, runtime->GetClassLinker()->FindClass(this, exception_class_descriptor,
-                                                                 class_loader));
-  if (UNLIKELY(exception_class.get() == nullptr)) {
+  Handle<mirror::ClassLoader> class_loader(hs.NewHandle(cl));
+  Handle<mirror::Class> exception_class(
+      hs.NewHandle(runtime->GetClassLinker()->FindClass(this, exception_class_descriptor,
+                                                        class_loader)));
+  if (UNLIKELY(exception_class.Get() == nullptr)) {
     CHECK(IsExceptionPending());
     LOG(ERROR) << "No exception class " << PrettyDescriptor(exception_class_descriptor);
     return;
@@ -1599,12 +1598,12 @@
     return;
   }
   DCHECK(!runtime->IsStarted() || exception_class->IsThrowableClass());
-  SirtRef<mirror::Throwable> exception(this,
-                                down_cast<mirror::Throwable*>(exception_class->AllocObject(this)));
+  Handle<mirror::Throwable> exception(
+      hs.NewHandle(down_cast<mirror::Throwable*>(exception_class->AllocObject(this))));
 
   // If we couldn't allocate the exception, throw the pre-allocated out of memory exception.
-  if (exception.get() == nullptr) {
-    ThrowLocation gc_safe_throw_location(saved_throw_this.get(), saved_throw_method.get(),
+  if (exception.Get() == nullptr) {
+    ThrowLocation gc_safe_throw_location(saved_throw_this.Get(), saved_throw_method.Get(),
                                          throw_location.GetDexPc());
     SetException(gc_safe_throw_location, Runtime::Current()->GetPreAllocatedOutOfMemoryError());
     return;
@@ -1656,9 +1655,9 @@
     if (trace.get() != nullptr) {
       exception->SetStackState(down_cast<mirror::Throwable*>(DecodeJObject(trace.get())));
     }
-    ThrowLocation gc_safe_throw_location(saved_throw_this.get(), saved_throw_method.get(),
+    ThrowLocation gc_safe_throw_location(saved_throw_this.Get(), saved_throw_method.Get(),
                                          throw_location.GetDexPc());
-    SetException(gc_safe_throw_location, exception.get());
+    SetException(gc_safe_throw_location, exception.Get());
   } else {
     jvalue jv_args[2];
     size_t i = 0;
@@ -1671,11 +1670,11 @@
       jv_args[i].l = cause.get();
       ++i;
     }
-    InvokeWithJValues(soa, exception.get(), soa.EncodeMethod(exception_init_method), jv_args);
+    InvokeWithJValues(soa, exception.Get(), soa.EncodeMethod(exception_init_method), jv_args);
     if (LIKELY(!IsExceptionPending())) {
-      ThrowLocation gc_safe_throw_location(saved_throw_this.get(), saved_throw_method.get(),
+      ThrowLocation gc_safe_throw_location(saved_throw_this.Get(), saved_throw_method.Get(),
                                            throw_location.GetDexPc());
-      SetException(gc_safe_throw_location, exception.get());
+      SetException(gc_safe_throw_location, exception.Get());
     }
   }
 }
@@ -1732,7 +1731,7 @@
   DO_THREAD_OFFSET(TopOfManagedStackOffset<ptr_size>(), "top_quick_frame_method")
   DO_THREAD_OFFSET(TopOfManagedStackPcOffset<ptr_size>(), "top_quick_frame_pc")
   DO_THREAD_OFFSET(TopShadowFrameOffset<ptr_size>(), "top_shadow_frame")
-  DO_THREAD_OFFSET(TopSirtOffset<ptr_size>(), "top_sirt")
+  DO_THREAD_OFFSET(TopHandleScopeOffset<ptr_size>(), "top_handle_scope")
   DO_THREAD_OFFSET(ThreadSuspendTriggerOffset<ptr_size>(), "suspend_trigger")
 #undef DO_THREAD_OFFSET
 
@@ -1966,7 +1965,7 @@
     mirror::ArtMethod* m = shadow_frame->GetMethod();
     size_t num_regs = shadow_frame->NumberOfVRegs();
     if (m->IsNative() || shadow_frame->HasReferenceArray()) {
-      // SIRT for JNI or References for interpreter.
+      // handle scope for JNI or References for interpreter.
       for (size_t reg = 0; reg < num_regs; ++reg) {
         mirror::Object* ref = shadow_frame->GetVRegReference(reg);
         if (ref != nullptr) {
@@ -2019,9 +2018,7 @@
         const uint8_t* reg_bitmap = map.FindBitMap(GetNativePcOffset());
         DCHECK(reg_bitmap != nullptr);
         const VmapTable vmap_table(m->GetVmapTable());
-        uint32_t core_spills = m->GetCoreSpillMask();
-        uint32_t fp_spills = m->GetFpSpillMask();
-        size_t frame_size = m->GetFrameSizeInBytes();
+        QuickMethodFrameInfo frame_info = m->GetQuickFrameInfo();
         // For all dex registers in the bitmap
         mirror::ArtMethod** cur_quick_frame = GetCurrentQuickFrame();
         DCHECK(cur_quick_frame != nullptr);
@@ -2030,7 +2027,8 @@
           if (TestBitmap(reg, reg_bitmap)) {
             uint32_t vmap_offset;
             if (vmap_table.IsInContext(reg, kReferenceVReg, &vmap_offset)) {
-              int vmap_reg = vmap_table.ComputeRegister(core_spills, vmap_offset, kReferenceVReg);
+              int vmap_reg = vmap_table.ComputeRegister(frame_info.CoreSpillMask(), vmap_offset,
+                                                        kReferenceVReg);
               // This is sound as spilled GPRs will be word sized (ie 32 or 64bit).
               mirror::Object** ref_addr = reinterpret_cast<mirror::Object**>(GetGPRAddress(vmap_reg));
               if (*ref_addr != nullptr) {
@@ -2039,8 +2037,8 @@
             } else {
               StackReference<mirror::Object>* ref_addr =
                   reinterpret_cast<StackReference<mirror::Object>*>(
-                      GetVRegAddr(cur_quick_frame, code_item, core_spills, fp_spills, frame_size,
-                                  reg));
+                      GetVRegAddr(cur_quick_frame, code_item, frame_info.CoreSpillMask(),
+                                  frame_info.FpSpillMask(), frame_info.FrameSizeInBytes(), reg));
               mirror::Object* ref = ref_addr->AsMirrorPtr();
               if (ref != nullptr) {
                 mirror::Object* new_ref = ref;
@@ -2105,7 +2103,7 @@
   }
   tlsPtr_.jni_env->locals.VisitRoots(visitor, arg, thread_id, kRootJNILocal);
   tlsPtr_.jni_env->monitors.VisitRoots(visitor, arg, thread_id, kRootJNIMonitor);
-  SirtVisitRoots(visitor, arg, thread_id);
+  HandleScopeVisitRoots(visitor, arg, thread_id);
   if (tlsPtr_.debug_invoke_req != nullptr) {
     tlsPtr_.debug_invoke_req->VisitRoots(visitor, arg, thread_id, kRootDebugger);
   }
diff --git a/runtime/thread.h b/runtime/thread.h
index 8c17082..1bbe617 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -31,12 +31,12 @@
 #include "entrypoints/quick/quick_entrypoints.h"
 #include "gc/allocator/rosalloc.h"
 #include "globals.h"
+#include "handle_scope.h"
 #include "jvalue.h"
 #include "object_callbacks.h"
 #include "offsets.h"
 #include "runtime_stats.h"
 #include "stack.h"
-#include "stack_indirect_reference_table.h"
 #include "thread_state.h"
 #include "throw_location.h"
 #include "UniquePtr.h"
@@ -648,35 +648,40 @@
     return tlsPtr_.managed_stack.NumJniShadowFrameReferences();
   }
 
-  // Number of references in SIRTs on this thread.
-  size_t NumSirtReferences();
+  // Number of references in handle scope on this thread.
+  size_t NumHandleReferences();
 
-  // Number of references allocated in SIRTs & JNI shadow frames on this thread.
+  // Number of references allocated in handle scopes & JNI shadow frames on this thread.
   size_t NumStackReferences() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return NumSirtReferences() + NumJniShadowFrameReferences();
+    return NumHandleReferences() + NumJniShadowFrameReferences();
   };
 
   // Is the given obj in this thread's stack indirect reference table?
-  bool SirtContains(jobject obj) const;
+  bool HandleScopeContains(jobject obj) const;
 
-  void SirtVisitRoots(RootCallback* visitor, void* arg, uint32_t thread_id)
+  void HandleScopeVisitRoots(RootCallback* visitor, void* arg, uint32_t thread_id)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void PushSirt(StackIndirectReferenceTable* sirt) {
-    sirt->SetLink(tlsPtr_.top_sirt);
-    tlsPtr_.top_sirt = sirt;
+  HandleScope* GetTopHandleScope() {
+    return tlsPtr_.top_handle_scope;
   }
 
-  StackIndirectReferenceTable* PopSirt() {
-    StackIndirectReferenceTable* sirt = tlsPtr_.top_sirt;
-    DCHECK(sirt != NULL);
-    tlsPtr_.top_sirt = tlsPtr_.top_sirt->GetLink();
-    return sirt;
+  void PushHandleScope(HandleScope* handle_scope) {
+    handle_scope->SetLink(tlsPtr_.top_handle_scope);
+    tlsPtr_.top_handle_scope = handle_scope;
+  }
+
+  HandleScope* PopHandleScope() {
+    HandleScope* handle_scope = tlsPtr_.top_handle_scope;
+    DCHECK(handle_scope != nullptr);
+    tlsPtr_.top_handle_scope = tlsPtr_.top_handle_scope->GetLink();
+    return handle_scope;
   }
 
   template<size_t pointer_size>
-  static ThreadOffset<pointer_size> TopSirtOffset() {
-    return ThreadOffsetFromTlsPtr<pointer_size>(OFFSETOF_MEMBER(tls_ptr_sized_values, top_sirt));
+  static ThreadOffset<pointer_size> TopHandleScopeOffset() {
+    return ThreadOffsetFromTlsPtr<pointer_size>(OFFSETOF_MEMBER(tls_ptr_sized_values,
+                                                                top_handle_scope));
   }
 
   DebugInvokeReq* GetInvokeReq() const {
@@ -950,7 +955,7 @@
       managed_stack(), suspend_trigger(nullptr), jni_env(nullptr), self(nullptr), opeer(nullptr),
       jpeer(nullptr), stack_begin(nullptr), stack_size(0), throw_location(),
       stack_trace_sample(nullptr), wait_next(nullptr), monitor_enter_object(nullptr),
-      top_sirt(nullptr), class_loader_override(nullptr), long_jump_context(nullptr),
+      top_handle_scope(nullptr), class_loader_override(nullptr), long_jump_context(nullptr),
       instrumentation_stack(nullptr), debug_invoke_req(nullptr), single_step_control(nullptr),
       deoptimization_shadow_frame(nullptr), name(nullptr), pthread_self(0),
       last_no_thread_suspension_cause(nullptr), thread_local_start(nullptr),
@@ -1006,8 +1011,8 @@
     // If we're blocked in MonitorEnter, this is the object we're trying to lock.
     mirror::Object* monitor_enter_object;
 
-    // Top of linked list of stack indirect reference tables or NULL for none.
-    StackIndirectReferenceTable* top_sirt;
+    // Top of linked list of handle scopes or nullptr for none.
+    HandleScope* top_handle_scope;
 
     // Needed to get the right ClassLoader in JNI_OnLoad, but also
     // useful for testing.
@@ -1082,6 +1087,7 @@
   friend class Runtime;  // For CreatePeer.
   friend class ScopedThreadStateChange;
   friend class SignalCatcher;  // For SetStateUnsafe.
+  friend class StubTest;  // For accessing entrypoints.
   friend class ThreadList;  // For ~Thread and Destroy.
 
   DISALLOW_COPY_AND_ASSIGN(Thread);
diff --git a/runtime/thread_pool.h b/runtime/thread_pool.h
index b8735a3..23bf294 100644
--- a/runtime/thread_pool.h
+++ b/runtime/thread_pool.h
@@ -96,7 +96,7 @@
   void SetMaxActiveWorkers(size_t threads);
 
  protected:
-  // Get a task to run, blocks if there are no tasks left
+  // get a task to run, blocks if there are no tasks left
   virtual Task* GetTask(Thread* self);
 
   // Try to get a task, returning NULL if there is none available.
diff --git a/runtime/transaction_test.cc b/runtime/transaction_test.cc
index 1dc2da0..3645ed2 100644
--- a/runtime/transaction_test.cc
+++ b/runtime/transaction_test.cc
@@ -27,56 +27,57 @@
 
 TEST_F(TransactionTest, Object_class) {
   ScopedObjectAccess soa(Thread::Current());
-  SirtRef<mirror::Class> sirt_klass(soa.Self(),
-                                    class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;"));
-  ASSERT_TRUE(sirt_klass.get() != nullptr);
+  StackHandleScope<2> hs(soa.Self());
+  Handle<mirror::Class> h_klass(
+      hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;")));
+  ASSERT_TRUE(h_klass.Get() != nullptr);
 
   Transaction transaction;
   Runtime::Current()->EnterTransactionMode(&transaction);
-  SirtRef<mirror::Object> sirt_obj(soa.Self(), sirt_klass->AllocObject(soa.Self()));
-  ASSERT_TRUE(sirt_obj.get() != nullptr);
-  ASSERT_EQ(sirt_obj->GetClass(), sirt_klass.get());
+  Handle<mirror::Object> h_obj(hs.NewHandle(h_klass->AllocObject(soa.Self())));
+  ASSERT_TRUE(h_obj.Get() != nullptr);
+  ASSERT_EQ(h_obj->GetClass(), h_klass.Get());
   Runtime::Current()->ExitTransactionMode();
 
   // Aborting transaction must not clear the Object::class field.
   transaction.Abort();
-  EXPECT_EQ(sirt_obj->GetClass(), sirt_klass.get());
+  EXPECT_EQ(h_obj->GetClass(), h_klass.Get());
 }
 
 TEST_F(TransactionTest, Object_monitor) {
   ScopedObjectAccess soa(Thread::Current());
-  SirtRef<mirror::Class> sirt_klass(soa.Self(),
-                                    class_linker_->FindSystemClass(soa.Self(),
-                                                                   "Ljava/lang/Object;"));
-  ASSERT_TRUE(sirt_klass.get() != nullptr);
-  SirtRef<mirror::Object> sirt_obj(soa.Self(), sirt_klass->AllocObject(soa.Self()));
-  ASSERT_TRUE(sirt_obj.get() != nullptr);
-  ASSERT_EQ(sirt_obj->GetClass(), sirt_klass.get());
+  StackHandleScope<2> hs(soa.Self());
+  Handle<mirror::Class> h_klass(
+      hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;")));
+  ASSERT_TRUE(h_klass.Get() != nullptr);
+  Handle<mirror::Object> h_obj(hs.NewHandle(h_klass->AllocObject(soa.Self())));
+  ASSERT_TRUE(h_obj.Get() != nullptr);
+  ASSERT_EQ(h_obj->GetClass(), h_klass.Get());
 
   // Lock object's monitor outside the transaction.
-  sirt_obj->MonitorEnter(soa.Self());
-  uint32_t old_lock_word = sirt_obj->GetLockWord(false).GetValue();
+  h_obj->MonitorEnter(soa.Self());
+  uint32_t old_lock_word = h_obj->GetLockWord(false).GetValue();
 
   Transaction transaction;
   Runtime::Current()->EnterTransactionMode(&transaction);
   // Unlock object's monitor inside the transaction.
-  sirt_obj->MonitorExit(soa.Self());
-  uint32_t new_lock_word = sirt_obj->GetLockWord(false).GetValue();
+  h_obj->MonitorExit(soa.Self());
+  uint32_t new_lock_word = h_obj->GetLockWord(false).GetValue();
   Runtime::Current()->ExitTransactionMode();
 
   // Aborting transaction must not clear the Object::class field.
   transaction.Abort();
-  uint32_t aborted_lock_word = sirt_obj->GetLockWord(false).GetValue();
+  uint32_t aborted_lock_word = h_obj->GetLockWord(false).GetValue();
   EXPECT_NE(old_lock_word, new_lock_word);
   EXPECT_EQ(aborted_lock_word, new_lock_word);
 }
 
 TEST_F(TransactionTest, Array_length) {
   ScopedObjectAccess soa(Thread::Current());
-  SirtRef<mirror::Class> sirt_klass(soa.Self(),
-                                    class_linker_->FindSystemClass(soa.Self(),
-                                                                   "[Ljava/lang/Object;"));
-  ASSERT_TRUE(sirt_klass.get() != nullptr);
+  StackHandleScope<2> hs(soa.Self());
+  Handle<mirror::Class> h_klass(
+      hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "[Ljava/lang/Object;")));
+  ASSERT_TRUE(h_klass.Get() != nullptr);
 
   constexpr int32_t kArraySize = 2;
 
@@ -84,304 +85,301 @@
   Runtime::Current()->EnterTransactionMode(&transaction);
 
   // Allocate an array during transaction.
-  SirtRef<mirror::Array> sirt_obj(soa.Self(),
-                                  mirror::Array::Alloc<true>(soa.Self(), sirt_klass.get(),
-                                                             kArraySize,
-                                                             sirt_klass->GetComponentSize(),
-                                                             Runtime::Current()->GetHeap()->GetCurrentAllocator()));
-  ASSERT_TRUE(sirt_obj.get() != nullptr);
-  ASSERT_EQ(sirt_obj->GetClass(), sirt_klass.get());
+  Handle<mirror::Array> h_obj(
+      hs.NewHandle(
+          mirror::Array::Alloc<true>(soa.Self(), h_klass.Get(), kArraySize,
+                                     h_klass->GetComponentSize(),
+                                     Runtime::Current()->GetHeap()->GetCurrentAllocator())));
+  ASSERT_TRUE(h_obj.Get() != nullptr);
+  ASSERT_EQ(h_obj->GetClass(), h_klass.Get());
   Runtime::Current()->ExitTransactionMode();
 
   // Aborting transaction must not clear the Object::class field.
   transaction.Abort();
-  EXPECT_EQ(sirt_obj->GetLength(), kArraySize);
+  EXPECT_EQ(h_obj->GetLength(), kArraySize);
 }
 
 TEST_F(TransactionTest, StaticFieldsTest) {
   ScopedObjectAccess soa(Thread::Current());
-  SirtRef<mirror::ClassLoader> class_loader(
-      soa.Self(), soa.Decode<mirror::ClassLoader*>(LoadDex("Transaction")));
-  ASSERT_TRUE(class_loader.get() != nullptr);
+  StackHandleScope<4> hs(soa.Self());
+  Handle<mirror::ClassLoader> class_loader(
+      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Transaction"))));
+  ASSERT_TRUE(class_loader.Get() != nullptr);
 
-  SirtRef<mirror::Class> sirt_klass(soa.Self(),
-                                    class_linker_->FindClass(soa.Self(), "LStaticFieldsTest;",
-                                                             class_loader));
-  ASSERT_TRUE(sirt_klass.get() != nullptr);
-  class_linker_->EnsureInitialized(sirt_klass, true, true);
-  ASSERT_TRUE(sirt_klass->IsInitialized());
+  Handle<mirror::Class> h_klass(
+      hs.NewHandle(class_linker_->FindClass(soa.Self(), "LStaticFieldsTest;", class_loader)));
+  ASSERT_TRUE(h_klass.Get() != nullptr);
+  class_linker_->EnsureInitialized(h_klass, true, true);
+  ASSERT_TRUE(h_klass->IsInitialized());
 
   // Lookup fields.
-  mirror::ArtField* booleanField = sirt_klass->FindDeclaredStaticField("booleanField", "Z");
+  mirror::ArtField* booleanField = h_klass->FindDeclaredStaticField("booleanField", "Z");
   ASSERT_TRUE(booleanField != nullptr);
   ASSERT_EQ(FieldHelper(booleanField).GetTypeAsPrimitiveType(), Primitive::kPrimBoolean);
-  ASSERT_EQ(booleanField->GetBoolean(sirt_klass.get()), false);
+  ASSERT_EQ(booleanField->GetBoolean(h_klass.Get()), false);
 
-  mirror::ArtField* byteField = sirt_klass->FindDeclaredStaticField("byteField", "B");
+  mirror::ArtField* byteField = h_klass->FindDeclaredStaticField("byteField", "B");
   ASSERT_TRUE(byteField != nullptr);
   ASSERT_EQ(FieldHelper(byteField).GetTypeAsPrimitiveType(), Primitive::kPrimByte);
-  ASSERT_EQ(byteField->GetByte(sirt_klass.get()), 0);
+  ASSERT_EQ(byteField->GetByte(h_klass.Get()), 0);
 
-  mirror::ArtField* charField = sirt_klass->FindDeclaredStaticField("charField", "C");
+  mirror::ArtField* charField = h_klass->FindDeclaredStaticField("charField", "C");
   ASSERT_TRUE(charField != nullptr);
   ASSERT_EQ(FieldHelper(charField).GetTypeAsPrimitiveType(), Primitive::kPrimChar);
-  ASSERT_EQ(charField->GetChar(sirt_klass.get()), 0u);
+  ASSERT_EQ(charField->GetChar(h_klass.Get()), 0u);
 
-  mirror::ArtField* shortField = sirt_klass->FindDeclaredStaticField("shortField", "S");
+  mirror::ArtField* shortField = h_klass->FindDeclaredStaticField("shortField", "S");
   ASSERT_TRUE(shortField != nullptr);
   ASSERT_EQ(FieldHelper(shortField).GetTypeAsPrimitiveType(), Primitive::kPrimShort);
-  ASSERT_EQ(shortField->GetShort(sirt_klass.get()), 0);
+  ASSERT_EQ(shortField->GetShort(h_klass.Get()), 0);
 
-  mirror::ArtField* intField = sirt_klass->FindDeclaredStaticField("intField", "I");
+  mirror::ArtField* intField = h_klass->FindDeclaredStaticField("intField", "I");
   ASSERT_TRUE(intField != nullptr);
   ASSERT_EQ(FieldHelper(intField).GetTypeAsPrimitiveType(), Primitive::kPrimInt);
-  ASSERT_EQ(intField->GetInt(sirt_klass.get()), 0);
+  ASSERT_EQ(intField->GetInt(h_klass.Get()), 0);
 
-  mirror::ArtField* longField = sirt_klass->FindDeclaredStaticField("longField", "J");
+  mirror::ArtField* longField = h_klass->FindDeclaredStaticField("longField", "J");
   ASSERT_TRUE(longField != nullptr);
   ASSERT_EQ(FieldHelper(longField).GetTypeAsPrimitiveType(), Primitive::kPrimLong);
-  ASSERT_EQ(longField->GetLong(sirt_klass.get()), static_cast<int64_t>(0));
+  ASSERT_EQ(longField->GetLong(h_klass.Get()), static_cast<int64_t>(0));
 
-  mirror::ArtField* floatField = sirt_klass->FindDeclaredStaticField("floatField", "F");
+  mirror::ArtField* floatField = h_klass->FindDeclaredStaticField("floatField", "F");
   ASSERT_TRUE(floatField != nullptr);
   ASSERT_EQ(FieldHelper(floatField).GetTypeAsPrimitiveType(), Primitive::kPrimFloat);
-  ASSERT_EQ(floatField->GetFloat(sirt_klass.get()), static_cast<float>(0.0f));
+  ASSERT_EQ(floatField->GetFloat(h_klass.Get()), static_cast<float>(0.0f));
 
-  mirror::ArtField* doubleField = sirt_klass->FindDeclaredStaticField("doubleField", "D");
+  mirror::ArtField* doubleField = h_klass->FindDeclaredStaticField("doubleField", "D");
   ASSERT_TRUE(doubleField != nullptr);
   ASSERT_EQ(FieldHelper(doubleField).GetTypeAsPrimitiveType(), Primitive::kPrimDouble);
-  ASSERT_EQ(doubleField->GetDouble(sirt_klass.get()), static_cast<double>(0.0));
+  ASSERT_EQ(doubleField->GetDouble(h_klass.Get()), static_cast<double>(0.0));
 
-  mirror::ArtField* objectField = sirt_klass->FindDeclaredStaticField("objectField",
+  mirror::ArtField* objectField = h_klass->FindDeclaredStaticField("objectField",
                                                                       "Ljava/lang/Object;");
   ASSERT_TRUE(objectField != nullptr);
   ASSERT_EQ(FieldHelper(objectField).GetTypeAsPrimitiveType(), Primitive::kPrimNot);
-  ASSERT_EQ(objectField->GetObject(sirt_klass.get()), nullptr);
+  ASSERT_EQ(objectField->GetObject(h_klass.Get()), nullptr);
 
   // Create a java.lang.Object instance to set objectField.
-  SirtRef<mirror::Class> object_klass(soa.Self(),
-                                      class_linker_->FindSystemClass(soa.Self(),
-                                                                     "Ljava/lang/Object;"));
-  ASSERT_TRUE(object_klass.get() != nullptr);
-  SirtRef<mirror::Object> sirt_obj(soa.Self(), sirt_klass->AllocObject(soa.Self()));
-  ASSERT_TRUE(sirt_obj.get() != nullptr);
-  ASSERT_EQ(sirt_obj->GetClass(), sirt_klass.get());
+  Handle<mirror::Class> object_klass(
+      hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;")));
+  ASSERT_TRUE(object_klass.Get() != nullptr);
+  Handle<mirror::Object> h_obj(hs.NewHandle(h_klass->AllocObject(soa.Self())));
+  ASSERT_TRUE(h_obj.Get() != nullptr);
+  ASSERT_EQ(h_obj->GetClass(), h_klass.Get());
 
   // Modify fields inside transaction and abort it.
   Transaction transaction;
   Runtime::Current()->EnterTransactionMode(&transaction);
-  booleanField->SetBoolean<true>(sirt_klass.get(), true);
-  byteField->SetByte<true>(sirt_klass.get(), 1);
-  charField->SetChar<true>(sirt_klass.get(), 1u);
-  shortField->SetShort<true>(sirt_klass.get(), 1);
-  intField->SetInt<true>(sirt_klass.get(), 1);
-  longField->SetLong<true>(sirt_klass.get(), 1);
-  floatField->SetFloat<true>(sirt_klass.get(), 1.0);
-  doubleField->SetDouble<true>(sirt_klass.get(), 1.0);
-  objectField->SetObject<true>(sirt_klass.get(), sirt_obj.get());
+  booleanField->SetBoolean<true>(h_klass.Get(), true);
+  byteField->SetByte<true>(h_klass.Get(), 1);
+  charField->SetChar<true>(h_klass.Get(), 1u);
+  shortField->SetShort<true>(h_klass.Get(), 1);
+  intField->SetInt<true>(h_klass.Get(), 1);
+  longField->SetLong<true>(h_klass.Get(), 1);
+  floatField->SetFloat<true>(h_klass.Get(), 1.0);
+  doubleField->SetDouble<true>(h_klass.Get(), 1.0);
+  objectField->SetObject<true>(h_klass.Get(), h_obj.Get());
   Runtime::Current()->ExitTransactionMode();
   transaction.Abort();
 
   // Check values have properly been restored to their original (default) value.
-  EXPECT_EQ(booleanField->GetBoolean(sirt_klass.get()), false);
-  EXPECT_EQ(byteField->GetByte(sirt_klass.get()), 0);
-  EXPECT_EQ(charField->GetChar(sirt_klass.get()), 0u);
-  EXPECT_EQ(shortField->GetShort(sirt_klass.get()), 0);
-  EXPECT_EQ(intField->GetInt(sirt_klass.get()), 0);
-  EXPECT_EQ(longField->GetLong(sirt_klass.get()), static_cast<int64_t>(0));
-  EXPECT_EQ(floatField->GetFloat(sirt_klass.get()), static_cast<float>(0.0f));
-  EXPECT_EQ(doubleField->GetDouble(sirt_klass.get()), static_cast<double>(0.0));
-  EXPECT_EQ(objectField->GetObject(sirt_klass.get()), nullptr);
+  EXPECT_EQ(booleanField->GetBoolean(h_klass.Get()), false);
+  EXPECT_EQ(byteField->GetByte(h_klass.Get()), 0);
+  EXPECT_EQ(charField->GetChar(h_klass.Get()), 0u);
+  EXPECT_EQ(shortField->GetShort(h_klass.Get()), 0);
+  EXPECT_EQ(intField->GetInt(h_klass.Get()), 0);
+  EXPECT_EQ(longField->GetLong(h_klass.Get()), static_cast<int64_t>(0));
+  EXPECT_EQ(floatField->GetFloat(h_klass.Get()), static_cast<float>(0.0f));
+  EXPECT_EQ(doubleField->GetDouble(h_klass.Get()), static_cast<double>(0.0));
+  EXPECT_EQ(objectField->GetObject(h_klass.Get()), nullptr);
 }
 
 TEST_F(TransactionTest, InstanceFieldsTest) {
   ScopedObjectAccess soa(Thread::Current());
-  SirtRef<mirror::ClassLoader> class_loader(
-      soa.Self(), soa.Decode<mirror::ClassLoader*>(LoadDex("Transaction")));
-  ASSERT_TRUE(class_loader.get() != nullptr);
+  StackHandleScope<5> hs(soa.Self());
+  Handle<mirror::ClassLoader> class_loader(
+      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Transaction"))));
+  ASSERT_TRUE(class_loader.Get() != nullptr);
 
-  SirtRef<mirror::Class> sirt_klass(soa.Self(),
-                                    class_linker_->FindClass(soa.Self(), "LInstanceFieldsTest;",
-                                                             class_loader));
-  ASSERT_TRUE(sirt_klass.get() != nullptr);
-  class_linker_->EnsureInitialized(sirt_klass, true, true);
-  ASSERT_TRUE(sirt_klass->IsInitialized());
+  Handle<mirror::Class> h_klass(
+      hs.NewHandle(class_linker_->FindClass(soa.Self(), "LInstanceFieldsTest;", class_loader)));
+  ASSERT_TRUE(h_klass.Get() != nullptr);
+  class_linker_->EnsureInitialized(h_klass, true, true);
+  ASSERT_TRUE(h_klass->IsInitialized());
 
   // Allocate an InstanceFieldTest object.
-  SirtRef<mirror::Object> sirt_instance(soa.Self(), sirt_klass->AllocObject(soa.Self()));
-  ASSERT_TRUE(sirt_instance.get() != nullptr);
+  Handle<mirror::Object> h_instance(hs.NewHandle(h_klass->AllocObject(soa.Self())));
+  ASSERT_TRUE(h_instance.Get() != nullptr);
 
   // Lookup fields.
-  mirror::ArtField* booleanField = sirt_klass->FindDeclaredInstanceField("booleanField", "Z");
+  mirror::ArtField* booleanField = h_klass->FindDeclaredInstanceField("booleanField", "Z");
   ASSERT_TRUE(booleanField != nullptr);
   ASSERT_EQ(FieldHelper(booleanField).GetTypeAsPrimitiveType(), Primitive::kPrimBoolean);
-  ASSERT_EQ(booleanField->GetBoolean(sirt_instance.get()), false);
+  ASSERT_EQ(booleanField->GetBoolean(h_instance.Get()), false);
 
-  mirror::ArtField* byteField = sirt_klass->FindDeclaredInstanceField("byteField", "B");
+  mirror::ArtField* byteField = h_klass->FindDeclaredInstanceField("byteField", "B");
   ASSERT_TRUE(byteField != nullptr);
   ASSERT_EQ(FieldHelper(byteField).GetTypeAsPrimitiveType(), Primitive::kPrimByte);
-  ASSERT_EQ(byteField->GetByte(sirt_instance.get()), 0);
+  ASSERT_EQ(byteField->GetByte(h_instance.Get()), 0);
 
-  mirror::ArtField* charField = sirt_klass->FindDeclaredInstanceField("charField", "C");
+  mirror::ArtField* charField = h_klass->FindDeclaredInstanceField("charField", "C");
   ASSERT_TRUE(charField != nullptr);
   ASSERT_EQ(FieldHelper(charField).GetTypeAsPrimitiveType(), Primitive::kPrimChar);
-  ASSERT_EQ(charField->GetChar(sirt_instance.get()), 0u);
+  ASSERT_EQ(charField->GetChar(h_instance.Get()), 0u);
 
-  mirror::ArtField* shortField = sirt_klass->FindDeclaredInstanceField("shortField", "S");
+  mirror::ArtField* shortField = h_klass->FindDeclaredInstanceField("shortField", "S");
   ASSERT_TRUE(shortField != nullptr);
   ASSERT_EQ(FieldHelper(shortField).GetTypeAsPrimitiveType(), Primitive::kPrimShort);
-  ASSERT_EQ(shortField->GetShort(sirt_instance.get()), 0);
+  ASSERT_EQ(shortField->GetShort(h_instance.Get()), 0);
 
-  mirror::ArtField* intField = sirt_klass->FindDeclaredInstanceField("intField", "I");
+  mirror::ArtField* intField = h_klass->FindDeclaredInstanceField("intField", "I");
   ASSERT_TRUE(intField != nullptr);
   ASSERT_EQ(FieldHelper(intField).GetTypeAsPrimitiveType(), Primitive::kPrimInt);
-  ASSERT_EQ(intField->GetInt(sirt_instance.get()), 0);
+  ASSERT_EQ(intField->GetInt(h_instance.Get()), 0);
 
-  mirror::ArtField* longField = sirt_klass->FindDeclaredInstanceField("longField", "J");
+  mirror::ArtField* longField = h_klass->FindDeclaredInstanceField("longField", "J");
   ASSERT_TRUE(longField != nullptr);
   ASSERT_EQ(FieldHelper(longField).GetTypeAsPrimitiveType(), Primitive::kPrimLong);
-  ASSERT_EQ(longField->GetLong(sirt_instance.get()), static_cast<int64_t>(0));
+  ASSERT_EQ(longField->GetLong(h_instance.Get()), static_cast<int64_t>(0));
 
-  mirror::ArtField* floatField = sirt_klass->FindDeclaredInstanceField("floatField", "F");
+  mirror::ArtField* floatField = h_klass->FindDeclaredInstanceField("floatField", "F");
   ASSERT_TRUE(floatField != nullptr);
   ASSERT_EQ(FieldHelper(floatField).GetTypeAsPrimitiveType(), Primitive::kPrimFloat);
-  ASSERT_EQ(floatField->GetFloat(sirt_instance.get()), static_cast<float>(0.0f));
+  ASSERT_EQ(floatField->GetFloat(h_instance.Get()), static_cast<float>(0.0f));
 
-  mirror::ArtField* doubleField = sirt_klass->FindDeclaredInstanceField("doubleField", "D");
+  mirror::ArtField* doubleField = h_klass->FindDeclaredInstanceField("doubleField", "D");
   ASSERT_TRUE(doubleField != nullptr);
   ASSERT_EQ(FieldHelper(doubleField).GetTypeAsPrimitiveType(), Primitive::kPrimDouble);
-  ASSERT_EQ(doubleField->GetDouble(sirt_instance.get()), static_cast<double>(0.0));
+  ASSERT_EQ(doubleField->GetDouble(h_instance.Get()), static_cast<double>(0.0));
 
-  mirror::ArtField* objectField = sirt_klass->FindDeclaredInstanceField("objectField",
+  mirror::ArtField* objectField = h_klass->FindDeclaredInstanceField("objectField",
                                                                         "Ljava/lang/Object;");
   ASSERT_TRUE(objectField != nullptr);
   ASSERT_EQ(FieldHelper(objectField).GetTypeAsPrimitiveType(), Primitive::kPrimNot);
-  ASSERT_EQ(objectField->GetObject(sirt_instance.get()), nullptr);
+  ASSERT_EQ(objectField->GetObject(h_instance.Get()), nullptr);
 
   // Create a java.lang.Object instance to set objectField.
-  SirtRef<mirror::Class> object_klass(soa.Self(),
-                                      class_linker_->FindSystemClass(soa.Self(),
-                                                                     "Ljava/lang/Object;"));
-  ASSERT_TRUE(object_klass.get() != nullptr);
-  SirtRef<mirror::Object> sirt_obj(soa.Self(), sirt_klass->AllocObject(soa.Self()));
-  ASSERT_TRUE(sirt_obj.get() != nullptr);
-  ASSERT_EQ(sirt_obj->GetClass(), sirt_klass.get());
+  Handle<mirror::Class> object_klass(
+      hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;")));
+  ASSERT_TRUE(object_klass.Get() != nullptr);
+  Handle<mirror::Object> h_obj(hs.NewHandle(h_klass->AllocObject(soa.Self())));
+  ASSERT_TRUE(h_obj.Get() != nullptr);
+  ASSERT_EQ(h_obj->GetClass(), h_klass.Get());
 
   // Modify fields inside transaction and abort it.
   Transaction transaction;
   Runtime::Current()->EnterTransactionMode(&transaction);
-  booleanField->SetBoolean<true>(sirt_instance.get(), true);
-  byteField->SetByte<true>(sirt_instance.get(), 1);
-  charField->SetChar<true>(sirt_instance.get(), 1u);
-  shortField->SetShort<true>(sirt_instance.get(), 1);
-  intField->SetInt<true>(sirt_instance.get(), 1);
-  longField->SetLong<true>(sirt_instance.get(), 1);
-  floatField->SetFloat<true>(sirt_instance.get(), 1.0);
-  doubleField->SetDouble<true>(sirt_instance.get(), 1.0);
-  objectField->SetObject<true>(sirt_instance.get(), sirt_obj.get());
+  booleanField->SetBoolean<true>(h_instance.Get(), true);
+  byteField->SetByte<true>(h_instance.Get(), 1);
+  charField->SetChar<true>(h_instance.Get(), 1u);
+  shortField->SetShort<true>(h_instance.Get(), 1);
+  intField->SetInt<true>(h_instance.Get(), 1);
+  longField->SetLong<true>(h_instance.Get(), 1);
+  floatField->SetFloat<true>(h_instance.Get(), 1.0);
+  doubleField->SetDouble<true>(h_instance.Get(), 1.0);
+  objectField->SetObject<true>(h_instance.Get(), h_obj.Get());
   Runtime::Current()->ExitTransactionMode();
   transaction.Abort();
 
   // Check values have properly been restored to their original (default) value.
-  EXPECT_EQ(booleanField->GetBoolean(sirt_instance.get()), false);
-  EXPECT_EQ(byteField->GetByte(sirt_instance.get()), 0);
-  EXPECT_EQ(charField->GetChar(sirt_instance.get()), 0u);
-  EXPECT_EQ(shortField->GetShort(sirt_instance.get()), 0);
-  EXPECT_EQ(intField->GetInt(sirt_instance.get()), 0);
-  EXPECT_EQ(longField->GetLong(sirt_instance.get()), static_cast<int64_t>(0));
-  EXPECT_EQ(floatField->GetFloat(sirt_instance.get()), static_cast<float>(0.0f));
-  EXPECT_EQ(doubleField->GetDouble(sirt_instance.get()), static_cast<double>(0.0));
-  EXPECT_EQ(objectField->GetObject(sirt_instance.get()), nullptr);
+  EXPECT_EQ(booleanField->GetBoolean(h_instance.Get()), false);
+  EXPECT_EQ(byteField->GetByte(h_instance.Get()), 0);
+  EXPECT_EQ(charField->GetChar(h_instance.Get()), 0u);
+  EXPECT_EQ(shortField->GetShort(h_instance.Get()), 0);
+  EXPECT_EQ(intField->GetInt(h_instance.Get()), 0);
+  EXPECT_EQ(longField->GetLong(h_instance.Get()), static_cast<int64_t>(0));
+  EXPECT_EQ(floatField->GetFloat(h_instance.Get()), static_cast<float>(0.0f));
+  EXPECT_EQ(doubleField->GetDouble(h_instance.Get()), static_cast<double>(0.0));
+  EXPECT_EQ(objectField->GetObject(h_instance.Get()), nullptr);
 }
 
 
 TEST_F(TransactionTest, StaticArrayFieldsTest) {
   ScopedObjectAccess soa(Thread::Current());
-  SirtRef<mirror::ClassLoader> class_loader(
-      soa.Self(), soa.Decode<mirror::ClassLoader*>(LoadDex("Transaction")));
-  ASSERT_TRUE(class_loader.get() != nullptr);
+  StackHandleScope<4> hs(soa.Self());
+  Handle<mirror::ClassLoader> class_loader(
+      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Transaction"))));
+  ASSERT_TRUE(class_loader.Get() != nullptr);
 
-  SirtRef<mirror::Class> sirt_klass(soa.Self(),
-                                    class_linker_->FindClass(soa.Self(), "LStaticArrayFieldsTest;",
-                                                             class_loader));
-  ASSERT_TRUE(sirt_klass.get() != nullptr);
-  class_linker_->EnsureInitialized(sirt_klass, true, true);
-  ASSERT_TRUE(sirt_klass->IsInitialized());
+  Handle<mirror::Class> h_klass(
+      hs.NewHandle(class_linker_->FindClass(soa.Self(), "LStaticArrayFieldsTest;", class_loader)));
+  ASSERT_TRUE(h_klass.Get() != nullptr);
+  class_linker_->EnsureInitialized(h_klass, true, true);
+  ASSERT_TRUE(h_klass->IsInitialized());
 
   // Lookup fields.
-  mirror::ArtField* booleanArrayField = sirt_klass->FindDeclaredStaticField("booleanArrayField", "[Z");
+  mirror::ArtField* booleanArrayField = h_klass->FindDeclaredStaticField("booleanArrayField", "[Z");
   ASSERT_TRUE(booleanArrayField != nullptr);
-  mirror::BooleanArray* booleanArray = booleanArrayField->GetObject(sirt_klass.get())->AsBooleanArray();
+  mirror::BooleanArray* booleanArray = booleanArrayField->GetObject(h_klass.Get())->AsBooleanArray();
   ASSERT_TRUE(booleanArray != nullptr);
   ASSERT_EQ(booleanArray->GetLength(), 1);
   ASSERT_EQ(booleanArray->GetWithoutChecks(0), false);
 
-  mirror::ArtField* byteArrayField = sirt_klass->FindDeclaredStaticField("byteArrayField", "[B");
+  mirror::ArtField* byteArrayField = h_klass->FindDeclaredStaticField("byteArrayField", "[B");
   ASSERT_TRUE(byteArrayField != nullptr);
-  mirror::ByteArray* byteArray = byteArrayField->GetObject(sirt_klass.get())->AsByteArray();
+  mirror::ByteArray* byteArray = byteArrayField->GetObject(h_klass.Get())->AsByteArray();
   ASSERT_TRUE(byteArray != nullptr);
   ASSERT_EQ(byteArray->GetLength(), 1);
   ASSERT_EQ(byteArray->GetWithoutChecks(0), 0);
 
-  mirror::ArtField* charArrayField = sirt_klass->FindDeclaredStaticField("charArrayField", "[C");
+  mirror::ArtField* charArrayField = h_klass->FindDeclaredStaticField("charArrayField", "[C");
   ASSERT_TRUE(charArrayField != nullptr);
-  mirror::CharArray* charArray = charArrayField->GetObject(sirt_klass.get())->AsCharArray();
+  mirror::CharArray* charArray = charArrayField->GetObject(h_klass.Get())->AsCharArray();
   ASSERT_TRUE(charArray != nullptr);
   ASSERT_EQ(charArray->GetLength(), 1);
   ASSERT_EQ(charArray->GetWithoutChecks(0), 0u);
 
-  mirror::ArtField* shortArrayField = sirt_klass->FindDeclaredStaticField("shortArrayField", "[S");
+  mirror::ArtField* shortArrayField = h_klass->FindDeclaredStaticField("shortArrayField", "[S");
   ASSERT_TRUE(shortArrayField != nullptr);
-  mirror::ShortArray* shortArray = shortArrayField->GetObject(sirt_klass.get())->AsShortArray();
+  mirror::ShortArray* shortArray = shortArrayField->GetObject(h_klass.Get())->AsShortArray();
   ASSERT_TRUE(shortArray != nullptr);
   ASSERT_EQ(shortArray->GetLength(), 1);
   ASSERT_EQ(shortArray->GetWithoutChecks(0), 0);
 
-  mirror::ArtField* intArrayField = sirt_klass->FindDeclaredStaticField("intArrayField", "[I");
+  mirror::ArtField* intArrayField = h_klass->FindDeclaredStaticField("intArrayField", "[I");
   ASSERT_TRUE(intArrayField != nullptr);
-  mirror::IntArray* intArray = intArrayField->GetObject(sirt_klass.get())->AsIntArray();
+  mirror::IntArray* intArray = intArrayField->GetObject(h_klass.Get())->AsIntArray();
   ASSERT_TRUE(intArray != nullptr);
   ASSERT_EQ(intArray->GetLength(), 1);
   ASSERT_EQ(intArray->GetWithoutChecks(0), 0);
 
-  mirror::ArtField* longArrayField = sirt_klass->FindDeclaredStaticField("longArrayField", "[J");
+  mirror::ArtField* longArrayField = h_klass->FindDeclaredStaticField("longArrayField", "[J");
   ASSERT_TRUE(longArrayField != nullptr);
-  mirror::LongArray* longArray = longArrayField->GetObject(sirt_klass.get())->AsLongArray();
+  mirror::LongArray* longArray = longArrayField->GetObject(h_klass.Get())->AsLongArray();
   ASSERT_TRUE(longArray != nullptr);
   ASSERT_EQ(longArray->GetLength(), 1);
   ASSERT_EQ(longArray->GetWithoutChecks(0), static_cast<int64_t>(0));
 
-  mirror::ArtField* floatArrayField = sirt_klass->FindDeclaredStaticField("floatArrayField", "[F");
+  mirror::ArtField* floatArrayField = h_klass->FindDeclaredStaticField("floatArrayField", "[F");
   ASSERT_TRUE(floatArrayField != nullptr);
-  mirror::FloatArray* floatArray = floatArrayField->GetObject(sirt_klass.get())->AsFloatArray();
+  mirror::FloatArray* floatArray = floatArrayField->GetObject(h_klass.Get())->AsFloatArray();
   ASSERT_TRUE(floatArray != nullptr);
   ASSERT_EQ(floatArray->GetLength(), 1);
   ASSERT_EQ(floatArray->GetWithoutChecks(0), static_cast<float>(0.0f));
 
-  mirror::ArtField* doubleArrayField = sirt_klass->FindDeclaredStaticField("doubleArrayField", "[D");
+  mirror::ArtField* doubleArrayField = h_klass->FindDeclaredStaticField("doubleArrayField", "[D");
   ASSERT_TRUE(doubleArrayField != nullptr);
-  mirror::DoubleArray* doubleArray = doubleArrayField->GetObject(sirt_klass.get())->AsDoubleArray();
+  mirror::DoubleArray* doubleArray = doubleArrayField->GetObject(h_klass.Get())->AsDoubleArray();
   ASSERT_TRUE(doubleArray != nullptr);
   ASSERT_EQ(doubleArray->GetLength(), 1);
   ASSERT_EQ(doubleArray->GetWithoutChecks(0), static_cast<double>(0.0f));
 
-  mirror::ArtField* objectArrayField = sirt_klass->FindDeclaredStaticField("objectArrayField",
+  mirror::ArtField* objectArrayField = h_klass->FindDeclaredStaticField("objectArrayField",
                                                                            "[Ljava/lang/Object;");
   ASSERT_TRUE(objectArrayField != nullptr);
   mirror::ObjectArray<mirror::Object>* objectArray =
-      objectArrayField->GetObject(sirt_klass.get())->AsObjectArray<mirror::Object>();
+      objectArrayField->GetObject(h_klass.Get())->AsObjectArray<mirror::Object>();
   ASSERT_TRUE(objectArray != nullptr);
   ASSERT_EQ(objectArray->GetLength(), 1);
   ASSERT_EQ(objectArray->GetWithoutChecks(0), nullptr);
 
   // Create a java.lang.Object instance to set objectField.
-  SirtRef<mirror::Class> object_klass(soa.Self(),
-                                      class_linker_->FindSystemClass(soa.Self(),
-                                                                     "Ljava/lang/Object;"));
-  ASSERT_TRUE(object_klass.get() != nullptr);
-  SirtRef<mirror::Object> sirt_obj(soa.Self(), sirt_klass->AllocObject(soa.Self()));
-  ASSERT_TRUE(sirt_obj.get() != nullptr);
-  ASSERT_EQ(sirt_obj->GetClass(), sirt_klass.get());
+  Handle<mirror::Class> object_klass(
+      hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;")));
+  ASSERT_TRUE(object_klass.Get() != nullptr);
+  Handle<mirror::Object> h_obj(hs.NewHandle(h_klass->AllocObject(soa.Self())));
+  ASSERT_TRUE(h_obj.Get() != nullptr);
+  ASSERT_EQ(h_obj->GetClass(), h_klass.Get());
 
   // Modify fields inside transaction and abort it.
   Transaction transaction;
@@ -394,7 +392,7 @@
   longArray->SetWithoutChecks<true>(0, 1);
   floatArray->SetWithoutChecks<true>(0, 1.0);
   doubleArray->SetWithoutChecks<true>(0, 1.0);
-  objectArray->SetWithoutChecks<true>(0, sirt_obj.get());
+  objectArray->SetWithoutChecks<true>(0, h_obj.Get());
   Runtime::Current()->ExitTransactionMode();
   transaction.Abort();
 
@@ -412,42 +410,41 @@
 
 TEST_F(TransactionTest, EmptyClass) {
   ScopedObjectAccess soa(Thread::Current());
-  SirtRef<mirror::ClassLoader> class_loader(
-      soa.Self(), soa.Decode<mirror::ClassLoader*>(LoadDex("Transaction")));
-  ASSERT_TRUE(class_loader.get() != nullptr);
+  StackHandleScope<2> hs(soa.Self());
+  Handle<mirror::ClassLoader> class_loader(
+      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Transaction"))));
+  ASSERT_TRUE(class_loader.Get() != nullptr);
 
-  SirtRef<mirror::Class> sirt_klass(soa.Self(),
-                                    class_linker_->FindClass(soa.Self(),
-                                                             "LTransaction$EmptyStatic;",
-                                                             class_loader));
-  ASSERT_TRUE(sirt_klass.get() != nullptr);
-  class_linker_->VerifyClass(sirt_klass);
-  ASSERT_TRUE(sirt_klass->IsVerified());
+  Handle<mirror::Class> h_klass(
+      hs.NewHandle(class_linker_->FindClass(soa.Self(), "LTransaction$EmptyStatic;", class_loader)));
+  ASSERT_TRUE(h_klass.Get() != nullptr);
+  class_linker_->VerifyClass(h_klass);
+  ASSERT_TRUE(h_klass->IsVerified());
 
   Transaction transaction;
   Runtime::Current()->EnterTransactionMode(&transaction);
-  class_linker_->EnsureInitialized(sirt_klass, true, true);
+  class_linker_->EnsureInitialized(h_klass, true, true);
   Runtime::Current()->ExitTransactionMode();
   ASSERT_FALSE(soa.Self()->IsExceptionPending());
 }
 
 TEST_F(TransactionTest, StaticFieldClass) {
   ScopedObjectAccess soa(Thread::Current());
-  SirtRef<mirror::ClassLoader> class_loader(
-      soa.Self(), soa.Decode<mirror::ClassLoader*>(LoadDex("Transaction")));
-  ASSERT_TRUE(class_loader.get() != nullptr);
+  StackHandleScope<2> hs(soa.Self());
+  Handle<mirror::ClassLoader> class_loader(
+      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Transaction"))));
+  ASSERT_TRUE(class_loader.Get() != nullptr);
 
-  SirtRef<mirror::Class> sirt_klass(soa.Self(),
-                                    class_linker_->FindClass(soa.Self(),
-                                                             "LTransaction$StaticFieldClass;",
-                                                             class_loader));
-  ASSERT_TRUE(sirt_klass.get() != nullptr);
-  class_linker_->VerifyClass(sirt_klass);
-  ASSERT_TRUE(sirt_klass->IsVerified());
+  Handle<mirror::Class> h_klass(
+      hs.NewHandle(class_linker_->FindClass(soa.Self(), "LTransaction$StaticFieldClass;",
+                                            class_loader)));
+  ASSERT_TRUE(h_klass.Get() != nullptr);
+  class_linker_->VerifyClass(h_klass);
+  ASSERT_TRUE(h_klass->IsVerified());
 
   Transaction transaction;
   Runtime::Current()->EnterTransactionMode(&transaction);
-  class_linker_->EnsureInitialized(sirt_klass, true, true);
+  class_linker_->EnsureInitialized(h_klass, true, true);
   Runtime::Current()->ExitTransactionMode();
   ASSERT_FALSE(soa.Self()->IsExceptionPending());
 }
@@ -455,39 +452,40 @@
 TEST_F(TransactionTest, BlacklistedClass) {
   ScopedObjectAccess soa(Thread::Current());
   jobject jclass_loader = LoadDex("Transaction");
-  SirtRef<mirror::ClassLoader> class_loader(soa.Self(),
-                                            soa.Decode<mirror::ClassLoader*>(jclass_loader));
-  ASSERT_TRUE(class_loader.get() != nullptr);
+  StackHandleScope<2> hs(soa.Self());
+  Handle<mirror::ClassLoader> class_loader(
+      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+  ASSERT_TRUE(class_loader.Get() != nullptr);
 
   // Load and verify java.lang.ExceptionInInitializerError and java.lang.InternalError which will
   // be thrown by class initialization due to native call.
-  SirtRef<mirror::Class> sirt_klass(soa.Self(),
-                                    class_linker_->FindSystemClass(soa.Self(),
-                                                                   "Ljava/lang/ExceptionInInitializerError;"));
-  ASSERT_TRUE(sirt_klass.get() != nullptr);
-  class_linker_->VerifyClass(sirt_klass);
-  ASSERT_TRUE(sirt_klass->IsVerified());
-  sirt_klass.reset(class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/InternalError;"));
-  ASSERT_TRUE(sirt_klass.get() != nullptr);
-  class_linker_->VerifyClass(sirt_klass);
-  ASSERT_TRUE(sirt_klass->IsVerified());
+  Handle<mirror::Class> h_klass(
+      hs.NewHandle(class_linker_->FindSystemClass(soa.Self(),
+                                                  "Ljava/lang/ExceptionInInitializerError;")));
+  ASSERT_TRUE(h_klass.Get() != nullptr);
+  class_linker_->VerifyClass(h_klass);
+  ASSERT_TRUE(h_klass->IsVerified());
+  h_klass.Assign(class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/InternalError;"));
+  ASSERT_TRUE(h_klass.Get() != nullptr);
+  class_linker_->VerifyClass(h_klass);
+  ASSERT_TRUE(h_klass->IsVerified());
 
   // Load and verify Transaction$NativeSupport used in class initialization.
-  sirt_klass.reset(class_linker_->FindClass(soa.Self(), "LTransaction$NativeSupport;",
-                                            class_loader));
-  ASSERT_TRUE(sirt_klass.get() != nullptr);
-  class_linker_->VerifyClass(sirt_klass);
-  ASSERT_TRUE(sirt_klass->IsVerified());
+  h_klass.Assign(class_linker_->FindClass(soa.Self(), "LTransaction$NativeSupport;",
+                                             class_loader));
+  ASSERT_TRUE(h_klass.Get() != nullptr);
+  class_linker_->VerifyClass(h_klass);
+  ASSERT_TRUE(h_klass->IsVerified());
 
-  sirt_klass.reset(class_linker_->FindClass(soa.Self(), "LTransaction$BlacklistedClass;",
-                                            class_loader));
-  ASSERT_TRUE(sirt_klass.get() != nullptr);
-  class_linker_->VerifyClass(sirt_klass);
-  ASSERT_TRUE(sirt_klass->IsVerified());
+  h_klass.Assign(class_linker_->FindClass(soa.Self(), "LTransaction$BlacklistedClass;",
+                                             class_loader));
+  ASSERT_TRUE(h_klass.Get() != nullptr);
+  class_linker_->VerifyClass(h_klass);
+  ASSERT_TRUE(h_klass->IsVerified());
 
   Transaction transaction;
   Runtime::Current()->EnterTransactionMode(&transaction);
-  class_linker_->EnsureInitialized(sirt_klass, true, true);
+  class_linker_->EnsureInitialized(h_klass, true, true);
   Runtime::Current()->ExitTransactionMode();
   ASSERT_TRUE(soa.Self()->IsExceptionPending());
 }
diff --git a/runtime/utils_test.cc b/runtime/utils_test.cc
index d425620..8a8834d 100644
--- a/runtime/utils_test.cc
+++ b/runtime/utils_test.cc
@@ -23,7 +23,7 @@
 #include "mirror/object_array-inl.h"
 #include "mirror/string.h"
 #include "scoped_thread_state_change.h"
-#include "sirt_ref.h"
+#include "handle_scope-inl.h"
 
 #include <valgrind.h>
 
@@ -95,11 +95,12 @@
   ScopedObjectAccess soa(Thread::Current());
   EXPECT_EQ("null", PrettyTypeOf(NULL));
 
-  SirtRef<mirror::String> s(soa.Self(), mirror::String::AllocFromModifiedUtf8(soa.Self(), ""));
-  EXPECT_EQ("java.lang.String", PrettyTypeOf(s.get()));
+  StackHandleScope<2> hs(soa.Self());
+  Handle<mirror::String> s(hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "")));
+  EXPECT_EQ("java.lang.String", PrettyTypeOf(s.Get()));
 
-  SirtRef<mirror::ShortArray> a(soa.Self(), mirror::ShortArray::Alloc(soa.Self(), 2));
-  EXPECT_EQ("short[]", PrettyTypeOf(a.get()));
+  Handle<mirror::ShortArray> a(hs.NewHandle(mirror::ShortArray::Alloc(soa.Self(), 2)));
+  EXPECT_EQ("short[]", PrettyTypeOf(a.Get()));
 
   mirror::Class* c = class_linker_->FindSystemClass(soa.Self(), "[Ljava/lang/String;");
   ASSERT_TRUE(c != NULL);
diff --git a/runtime/verifier/method_verifier-inl.h b/runtime/verifier/method_verifier-inl.h
index c554394..62ecf4b 100644
--- a/runtime/verifier/method_verifier-inl.h
+++ b/runtime/verifier/method_verifier-inl.h
@@ -21,7 +21,7 @@
 #include "method_verifier.h"
 #include "mirror/class_loader.h"
 #include "mirror/dex_cache.h"
-#include "sirt_ref-inl.h"
+#include "handle_scope-inl.h"
 
 namespace art {
 namespace verifier {
@@ -39,11 +39,11 @@
 }
 
 inline mirror::ClassLoader* MethodVerifier::GetClassLoader() {
-  return class_loader_->get();
+  return class_loader_->Get();
 }
 
 inline mirror::DexCache* MethodVerifier::GetDexCache() {
-  return dex_cache_->get();
+  return dex_cache_->Get();
 }
 
 inline MethodReference MethodVerifier::GetMethodReference() const {
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 41ff96e..9dd366d 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -40,7 +40,7 @@
 #include "register_line-inl.h"
 #include "runtime.h"
 #include "scoped_thread_state_change.h"
-#include "sirt_ref-inl.h"
+#include "handle_scope-inl.h"
 #include "verifier/dex_gc_map.h"
 
 namespace art {
@@ -115,15 +115,15 @@
     }
     return kHardFailure;
   }
-  Thread* self = Thread::Current();
-  SirtRef<mirror::DexCache> dex_cache(self, kh.GetDexCache());
-  SirtRef<mirror::ClassLoader> class_loader(self, klass->GetClassLoader());
+  StackHandleScope<2> hs(Thread::Current());
+  Handle<mirror::DexCache> dex_cache(hs.NewHandle(kh.GetDexCache()));
+  Handle<mirror::ClassLoader> class_loader(hs.NewHandle(klass->GetClassLoader()));
   return VerifyClass(&dex_file, dex_cache, class_loader, class_def, allow_soft_failures, error);
 }
 
 MethodVerifier::FailureKind MethodVerifier::VerifyClass(const DexFile* dex_file,
-                                                        SirtRef<mirror::DexCache>& dex_cache,
-                                                        SirtRef<mirror::ClassLoader>& class_loader,
+                                                        Handle<mirror::DexCache>& dex_cache,
+                                                        Handle<mirror::ClassLoader>& class_loader,
                                                         const DexFile::ClassDef* class_def,
                                                         bool allow_soft_failures,
                                                         std::string* error) {
@@ -233,8 +233,8 @@
 
 MethodVerifier::FailureKind MethodVerifier::VerifyMethod(uint32_t method_idx,
                                                          const DexFile* dex_file,
-                                                         SirtRef<mirror::DexCache>& dex_cache,
-                                                         SirtRef<mirror::ClassLoader>& class_loader,
+                                                         Handle<mirror::DexCache>& dex_cache,
+                                                         Handle<mirror::ClassLoader>& class_loader,
                                                          const DexFile::ClassDef* class_def,
                                                          const DexFile::CodeItem* code_item,
                                                          mirror::ArtMethod* method,
@@ -278,8 +278,8 @@
 
 void MethodVerifier::VerifyMethodAndDump(std::ostream& os, uint32_t dex_method_idx,
                                          const DexFile* dex_file,
-                                         SirtRef<mirror::DexCache>& dex_cache,
-                                         SirtRef<mirror::ClassLoader>& class_loader,
+                                         Handle<mirror::DexCache>& dex_cache,
+                                         Handle<mirror::ClassLoader>& class_loader,
                                          const DexFile::ClassDef* class_def,
                                          const DexFile::CodeItem* code_item,
                                          mirror::ArtMethod* method,
@@ -292,8 +292,8 @@
   verifier.Dump(os);
 }
 
-MethodVerifier::MethodVerifier(const DexFile* dex_file, SirtRef<mirror::DexCache>* dex_cache,
-                               SirtRef<mirror::ClassLoader>* class_loader,
+MethodVerifier::MethodVerifier(const DexFile* dex_file, Handle<mirror::DexCache>* dex_cache,
+                               Handle<mirror::ClassLoader>* class_loader,
                                const DexFile::ClassDef* class_def,
                                const DexFile::CodeItem* code_item, uint32_t dex_method_idx,
                                mirror::ArtMethod* method, uint32_t method_access_flags,
@@ -332,9 +332,9 @@
 void MethodVerifier::FindLocksAtDexPc(mirror::ArtMethod* m, uint32_t dex_pc,
                                       std::vector<uint32_t>& monitor_enter_dex_pcs) {
   MethodHelper mh(m);
-  Thread* self = Thread::Current();
-  SirtRef<mirror::DexCache> dex_cache(self, mh.GetDexCache());
-  SirtRef<mirror::ClassLoader> class_loader(self, mh.GetClassLoader());
+  StackHandleScope<2> hs(Thread::Current());
+  Handle<mirror::DexCache> dex_cache(hs.NewHandle(mh.GetDexCache()));
+  Handle<mirror::ClassLoader> class_loader(hs.NewHandle(mh.GetClassLoader()));
   MethodVerifier verifier(&mh.GetDexFile(), &dex_cache, &class_loader, &mh.GetClassDef(),
                           mh.GetCodeItem(), m->GetDexMethodIndex(), m, m->GetAccessFlags(), false,
                           true);
@@ -357,9 +357,9 @@
 mirror::ArtField* MethodVerifier::FindAccessedFieldAtDexPc(mirror::ArtMethod* m,
                                                         uint32_t dex_pc) {
   MethodHelper mh(m);
-  Thread* self = Thread::Current();
-  SirtRef<mirror::DexCache> dex_cache(self, mh.GetDexCache());
-  SirtRef<mirror::ClassLoader> class_loader(self, mh.GetClassLoader());
+  StackHandleScope<2> hs(Thread::Current());
+  Handle<mirror::DexCache> dex_cache(hs.NewHandle(mh.GetDexCache()));
+  Handle<mirror::ClassLoader> class_loader(hs.NewHandle(mh.GetClassLoader()));
   MethodVerifier verifier(&mh.GetDexFile(), &dex_cache, &class_loader, &mh.GetClassDef(),
                           mh.GetCodeItem(), m->GetDexMethodIndex(), m, m->GetAccessFlags(), true,
                           true);
@@ -388,9 +388,9 @@
 mirror::ArtMethod* MethodVerifier::FindInvokedMethodAtDexPc(mirror::ArtMethod* m,
                                                             uint32_t dex_pc) {
   MethodHelper mh(m);
-  Thread* self = Thread::Current();
-  SirtRef<mirror::DexCache> dex_cache(self, mh.GetDexCache());
-  SirtRef<mirror::ClassLoader> class_loader(self, mh.GetClassLoader());
+  StackHandleScope<2> hs(Thread::Current());
+  Handle<mirror::DexCache> dex_cache(hs.NewHandle(mh.GetDexCache()));
+  Handle<mirror::ClassLoader> class_loader(hs.NewHandle(mh.GetClassLoader()));
   MethodVerifier verifier(&mh.GetDexFile(), &dex_cache, &class_loader, &mh.GetClassDef(),
                           mh.GetCodeItem(), m->GetDexMethodIndex(), m, m->GetAccessFlags(), true,
                           true);
@@ -1834,7 +1834,7 @@
                                             << array_type;
         } else {
           const RegType& component_type = reg_types_.GetComponentType(array_type,
-                                                                      class_loader_->get());
+                                                                      class_loader_->Get());
           DCHECK(!component_type.IsConflict());
           if (component_type.IsNonZeroReferenceTypes()) {
             Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid fill-array-data with component type "
@@ -2149,7 +2149,7 @@
         const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
         uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
         const char* descriptor = dex_file_->StringByTypeIdx(return_type_idx);
-        return_type = &reg_types_.FromDescriptor(class_loader_->get(), descriptor, false);
+        return_type = &reg_types_.FromDescriptor(class_loader_->Get(), descriptor, false);
       }
       if (!return_type->IsLowHalf()) {
         work_line_->SetResultRegisterType(*return_type);
@@ -2216,7 +2216,7 @@
          */
         work_line_->MarkRefsAsInitialized(this_type);
       }
-      const RegType& return_type = reg_types_.FromDescriptor(class_loader_->get(),
+      const RegType& return_type = reg_types_.FromDescriptor(class_loader_->Get(),
                                                              return_type_descriptor, false);
       if (!return_type.IsLowHalf()) {
         work_line_->SetResultRegisterType(return_type);
@@ -2242,7 +2242,7 @@
         } else {
           descriptor = MethodHelper(called_method).GetReturnTypeDescriptor();
         }
-        const RegType& return_type =  reg_types_.FromDescriptor(class_loader_->get(), descriptor,
+        const RegType& return_type =  reg_types_.FromDescriptor(class_loader_->Get(), descriptor,
                                                                 false);
         if (!return_type.IsLowHalf()) {
           work_line_->SetResultRegisterType(return_type);
@@ -2300,7 +2300,7 @@
       } else {
         descriptor = MethodHelper(abs_method).GetReturnTypeDescriptor();
       }
-      const RegType& return_type = reg_types_.FromDescriptor(class_loader_->get(), descriptor,
+      const RegType& return_type = reg_types_.FromDescriptor(class_loader_->Get(), descriptor,
                                                              false);
       if (!return_type.IsLowHalf()) {
         work_line_->SetResultRegisterType(return_type);
@@ -2566,7 +2566,7 @@
       mirror::ArtMethod* called_method = VerifyInvokeVirtualQuickArgs(inst, is_range);
       if (called_method != NULL) {
         const char* descriptor = MethodHelper(called_method).GetReturnTypeDescriptor();
-        const RegType& return_type = reg_types_.FromDescriptor(class_loader_->get(), descriptor,
+        const RegType& return_type = reg_types_.FromDescriptor(class_loader_->Get(), descriptor,
                                                                false);
         if (!return_type.IsLowHalf()) {
           work_line_->SetResultRegisterType(return_type);
@@ -2837,7 +2837,7 @@
   const RegType& result =
       klass != NULL ? reg_types_.FromClass(descriptor, klass,
                                            klass->CannotBeAssignedFromOtherTypes())
-                    : reg_types_.FromDescriptor(class_loader_->get(), descriptor, false);
+                    : reg_types_.FromDescriptor(class_loader_->Get(), descriptor, false);
   if (result.IsConflict()) {
     Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "accessing broken descriptor '" << descriptor
         << "' in " << referrer;
@@ -3093,7 +3093,7 @@
           << " missing signature component";
       return NULL;
     }
-    const RegType& reg_type = reg_types_.FromDescriptor(class_loader_->get(), descriptor, false);
+    const RegType& reg_type = reg_types_.FromDescriptor(class_loader_->Get(), descriptor, false);
     uint32_t get_reg = is_range ? inst->VRegC_3rc() + actual_args : arg[actual_args];
     if (reg_type.IsIntegralTypes()) {
       const RegType& src_type = work_line_->GetRegisterType(get_reg);
@@ -3218,7 +3218,7 @@
                                         << " missing signature component";
       return NULL;
     }
-    const RegType& reg_type = reg_types_.FromDescriptor(class_loader_->get(), descriptor, false);
+    const RegType& reg_type = reg_types_.FromDescriptor(class_loader_->Get(), descriptor, false);
     uint32_t get_reg = is_range ? inst->VRegC_3rc() + actual_args : arg[actual_args];
     if (!work_line_->VerifyRegisterType(get_reg, reg_type)) {
       return res_method;
@@ -3262,7 +3262,7 @@
     } else {
       // Verify each register. If "arg_count" is bad, VerifyRegisterType() will run off the end of
       // the list and fail. It's legal, if silly, for arg_count to be zero.
-      const RegType& expected_type = reg_types_.GetComponentType(res_type, class_loader_->get());
+      const RegType& expected_type = reg_types_.GetComponentType(res_type, class_loader_->Get());
       uint32_t arg_count = (is_range) ? inst->VRegA_3rc() : inst->VRegA_35c();
       uint32_t arg[5];
       if (!is_range) {
@@ -3304,7 +3304,7 @@
       Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "not array type " << array_type << " with aget";
     } else {
       /* verify the class */
-      const RegType& component_type = reg_types_.GetComponentType(array_type, class_loader_->get());
+      const RegType& component_type = reg_types_.GetComponentType(array_type, class_loader_->Get());
       if (!component_type.IsReferenceTypes() && !is_primitive) {
         Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "primitive array type " << array_type
             << " source for aget-object";
@@ -3381,7 +3381,7 @@
     } else if (!array_type.IsArrayTypes()) {
       Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "not array type " << array_type << " with aput";
     } else {
-      const RegType& component_type = reg_types_.GetComponentType(array_type, class_loader_->get());
+      const RegType& component_type = reg_types_.GetComponentType(array_type, class_loader_->Get());
       const uint32_t vregA = inst->VRegA_23x();
       if (is_primitive) {
         VerifyPrimitivePut(component_type, insn_type, vregA);
@@ -3523,7 +3523,7 @@
   if (field_type == nullptr) {
     const DexFile::FieldId& field_id = dex_file_->GetFieldId(field_idx);
     const char* descriptor = dex_file_->GetFieldTypeDescriptor(field_id);
-    field_type = &reg_types_.FromDescriptor(class_loader_->get(), descriptor, false);
+    field_type = &reg_types_.FromDescriptor(class_loader_->Get(), descriptor, false);
   }
   DCHECK(field_type != nullptr);
   const uint32_t vregA = (is_static) ? inst->VRegA_21c() : inst->VRegA_22c();
@@ -3547,7 +3547,7 @@
       Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "expected field " << PrettyField(field)
                                         << " to be compatible with type '" << insn_type
                                         << "' but found type '" << *field_type
-                                        << "' in get-object";
+                                        << "' in Get-object";
       work_line_->SetRegisterType(vregA, reg_types_.Conflict());
       return;
     }
@@ -3590,7 +3590,7 @@
   if (field_type == nullptr) {
     const DexFile::FieldId& field_id = dex_file_->GetFieldId(field_idx);
     const char* descriptor = dex_file_->GetFieldTypeDescriptor(field_id);
-    field_type = &reg_types_.FromDescriptor(class_loader_->get(), descriptor, false);
+    field_type = &reg_types_.FromDescriptor(class_loader_->Get(), descriptor, false);
   }
   DCHECK(field_type != nullptr);
   const uint32_t vregA = (is_static) ? inst->VRegA_21c() : inst->VRegA_22c();
@@ -3666,7 +3666,7 @@
       // compile time
       Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "expected field " << PrettyField(field)
                                         << " to be of type '" << insn_type
-                                        << "' but found type '" << *field_type << "' in get";
+                                        << "' but found type '" << *field_type << "' in Get";
       return;
     }
   } else {
@@ -3842,7 +3842,7 @@
       const DexFile::ProtoId& proto_id = dex_file_->GetMethodPrototype(method_id);
       uint16_t return_type_idx = proto_id.return_type_idx_;
       const char* descriptor = dex_file_->GetTypeDescriptor(dex_file_->GetTypeId(return_type_idx));
-      return_type_ = &reg_types_.FromDescriptor(class_loader_->get(), descriptor, false);
+      return_type_ = &reg_types_.FromDescriptor(class_loader_->Get(), descriptor, false);
     }
   }
   return *return_type_;
@@ -3858,7 +3858,7 @@
       declaring_class_ = &reg_types_.FromClass(descriptor, klass,
                                                klass->CannotBeAssignedFromOtherTypes());
     } else {
-      declaring_class_ = &reg_types_.FromDescriptor(class_loader_->get(), descriptor, false);
+      declaring_class_ = &reg_types_.FromDescriptor(class_loader_->Get(), descriptor, false);
     }
   }
   return *declaring_class_;
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index 5f13191..cea2403 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -38,7 +38,7 @@
 namespace art {
 
 struct ReferenceMap2Visitor;
-template<class T> class SirtRef;
+template<class T> class Handle;
 
 namespace verifier {
 
@@ -142,15 +142,15 @@
   /* Verify a class. Returns "kNoFailure" on success. */
   static FailureKind VerifyClass(mirror::Class* klass, bool allow_soft_failures, std::string* error)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  static FailureKind VerifyClass(const DexFile* dex_file, SirtRef<mirror::DexCache>& dex_cache,
-                                 SirtRef<mirror::ClassLoader>& class_loader,
+  static FailureKind VerifyClass(const DexFile* dex_file, Handle<mirror::DexCache>& dex_cache,
+                                 Handle<mirror::ClassLoader>& class_loader,
                                  const DexFile::ClassDef* class_def,
                                  bool allow_soft_failures, std::string* error)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   static void VerifyMethodAndDump(std::ostream& os, uint32_t method_idx, const DexFile* dex_file,
-                                  SirtRef<mirror::DexCache>& dex_cache,
-                                  SirtRef<mirror::ClassLoader>& class_loader,
+                                  Handle<mirror::DexCache>& dex_cache,
+                                  Handle<mirror::ClassLoader>& class_loader,
                                   const DexFile::ClassDef* class_def,
                                   const DexFile::CodeItem* code_item,
                                   mirror::ArtMethod* method, uint32_t method_access_flags)
@@ -205,8 +205,8 @@
     return can_load_classes_;
   }
 
-  MethodVerifier(const DexFile* dex_file, SirtRef<mirror::DexCache>* dex_cache,
-                 SirtRef<mirror::ClassLoader>* class_loader, const DexFile::ClassDef* class_def,
+  MethodVerifier(const DexFile* dex_file, Handle<mirror::DexCache>* dex_cache,
+                 Handle<mirror::ClassLoader>* class_loader, const DexFile::ClassDef* class_def,
                  const DexFile::CodeItem* code_item, uint32_t method_idx, mirror::ArtMethod* method,
                  uint32_t access_flags, bool can_load_classes, bool allow_soft_failures)
           SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -255,8 +255,8 @@
    *      for code flow problems.
    */
   static FailureKind VerifyMethod(uint32_t method_idx, const DexFile* dex_file,
-                                  SirtRef<mirror::DexCache>& dex_cache,
-                                  SirtRef<mirror::ClassLoader>& class_loader,
+                                  Handle<mirror::DexCache>& dex_cache,
+                                  Handle<mirror::ClassLoader>& class_loader,
                                   const DexFile::ClassDef* class_def_idx,
                                   const DexFile::CodeItem* code_item,
                                   mirror::ArtMethod* method, uint32_t method_access_flags,
@@ -347,7 +347,7 @@
   /* Ensure that the wide register index is valid for this code item. */
   bool CheckWideRegisterIndex(uint32_t idx);
 
-  // Perform static checks on a field get or set instruction. All we do here is ensure that the
+  // Perform static checks on a field Get or set instruction. All we do here is ensure that the
   // field index is in the valid range.
   bool CheckFieldIndex(uint32_t idx);
 
@@ -633,9 +633,9 @@
   const RegType* return_type_;  // Lazily computed return type of the method.
   const DexFile* const dex_file_;  // The dex file containing the method.
   // The dex_cache for the declaring class of the method.
-  SirtRef<mirror::DexCache>* dex_cache_ GUARDED_BY(Locks::mutator_lock_);
+  Handle<mirror::DexCache>* dex_cache_ GUARDED_BY(Locks::mutator_lock_);
   // The class loader for the declaring class of the method.
-  SirtRef<mirror::ClassLoader>* class_loader_ GUARDED_BY(Locks::mutator_lock_);
+  Handle<mirror::ClassLoader>* class_loader_ GUARDED_BY(Locks::mutator_lock_);
   const DexFile::ClassDef* const class_def_;  // The class def of the declaring class of the method.
   const DexFile::CodeItem* const code_item_;  // The code item containing the code for the method.
   const RegType* declaring_class_;  // Lazily computed reg type of the method's declaring class.
diff --git a/runtime/verifier/reg_type_cache.cc b/runtime/verifier/reg_type_cache.cc
index 111e867..689a33e 100644
--- a/runtime/verifier/reg_type_cache.cc
+++ b/runtime/verifier/reg_type_cache.cc
@@ -142,15 +142,16 @@
   // Try resolving class
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   Thread* self = Thread::Current();
-  SirtRef<mirror::ClassLoader> class_loader(self, loader);
+  StackHandleScope<1> hs(self);
+  Handle<mirror::ClassLoader> class_loader(hs.NewHandle(loader));
   mirror::Class* klass = NULL;
   if (can_load_classes_) {
     klass = class_linker->FindClass(self, descriptor, class_loader);
   } else {
     klass = class_linker->LookupClass(descriptor, loader);
-    if (klass != NULL && !klass->IsLoaded()) {
+    if (klass != nullptr && !klass->IsLoaded()) {
       // We found the class but without it being loaded its not safe for use.
-      klass = NULL;
+      klass = nullptr;
     }
   }
   return klass;
diff --git a/runtime/verifier/register_line.cc b/runtime/verifier/register_line.cc
index 31b0113..a3e3e3b 100644
--- a/runtime/verifier/register_line.cc
+++ b/runtime/verifier/register_line.cc
@@ -94,7 +94,7 @@
     verifier_->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invoke lacks 'this'";
     return verifier_->GetRegTypeCache()->Conflict();
   }
-  /* get the element type of the array held in vsrc */
+  /* Get the element type of the array held in vsrc */
   const uint32_t this_reg = (is_range) ? inst->VRegC_3rc() : inst->VRegC_35c();
   const RegType& this_type = GetRegisterType(this_reg);
   if (!this_type.IsReferenceTypes()) {
diff --git a/test/111-unresolvable-exception/build b/test/111-unresolvable-exception/build
new file mode 100644
index 0000000..c21a9ef
--- /dev/null
+++ b/test/111-unresolvable-exception/build
@@ -0,0 +1,25 @@
+#!/bin/bash
+#
+# Copyright (C) 2014 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.
+
+# Stop if something fails.
+set -e
+
+mkdir classes
+${JAVAC} -d classes `find src -name '*.java'`
+rm classes/TestException.class
+
+${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex classes
+zip $TEST_NAME.jar classes.dex
diff --git a/test/111-unresolvable-exception/expected.txt b/test/111-unresolvable-exception/expected.txt
new file mode 100644
index 0000000..052dd74
--- /dev/null
+++ b/test/111-unresolvable-exception/expected.txt
@@ -0,0 +1 @@
+Caught class java.lang.NoClassDefFoundError
diff --git a/test/111-unresolvable-exception/info.txt b/test/111-unresolvable-exception/info.txt
new file mode 100644
index 0000000..5ba3733
--- /dev/null
+++ b/test/111-unresolvable-exception/info.txt
@@ -0,0 +1,2 @@
+Test that we do not segfault when we check a catch handler
+for an unresolvable exception.
diff --git a/test/111-unresolvable-exception/src/Main.java b/test/111-unresolvable-exception/src/Main.java
new file mode 100644
index 0000000..ba07ee1
--- /dev/null
+++ b/test/111-unresolvable-exception/src/Main.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+public class Main {
+    static public void main(String[] args) throws Exception {
+      try {
+        check(false);
+      } catch (Throwable t) {          // Should catch the NoClassDefFoundError
+        System.out.println("Caught " + t.getClass());
+      }
+    }
+
+    private static void check(boolean b) {
+      try {
+        if (b) {                   // Need this to not be dead code, but also not be invoked.
+          throwsTestException();   // TestException is checked, so we need something potentially
+                                   // throwing it.
+        }
+        throw new RuntimeException();  // Trigger exception handling.
+      } catch (TestException e) {      // This handler will have an unresolvable class.
+      } catch (Exception e) {          // General-purpose handler
+        System.out.println("Should not get here!");
+      }
+    }
+
+    // This avoids having to construct one explicitly, which won't work.
+    private static native void throwsTestException() throws TestException;
+}
diff --git a/test/111-unresolvable-exception/src/TestException.java b/test/111-unresolvable-exception/src/TestException.java
new file mode 100644
index 0000000..2d8b234
--- /dev/null
+++ b/test/111-unresolvable-exception/src/TestException.java
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+public class TestException extends Exception {
+}
diff --git a/test/Android.mk b/test/Android.mk
index aacd7b4..6e37af3 100644
--- a/test/Android.mk
+++ b/test/Android.mk
@@ -78,7 +78,7 @@
     LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common.mk
     LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
     include $(BUILD_JAVA_LIBRARY)
-    
+
     ART_TEST_TARGET_DEX_FILES += $$(LOCAL_INSTALLED_MODULE)
     ART_TEST_TARGET_DEX_FILES$(ART_PHONY_TEST_TARGET_SUFFIX) += $$(LOCAL_INSTALLED_MODULE)
 
@@ -88,7 +88,7 @@
       # TODO: make this a simple copy
 $(4)/$(1)-$(2).jar: $(3)/$(1)-$(2).jar $(4)
 	cp $$< $(4)/
-    endif    
+    endif
   endif
 
   ifeq ($(ART_BUILD_HOST),true)
@@ -108,6 +108,9 @@
 $(foreach dir,$(TEST_DEX_DIRECTORIES), $(eval $(call build-art-test-dex,art-test-dex,$(dir),$(ART_NATIVETEST_OUT),$(2ND_ART_NATIVETEST_OUT))))
 $(foreach dir,$(TEST_OAT_DIRECTORIES), $(eval $(call build-art-test-dex,oat-test-dex,$(dir),$(ART_TEST_OUT),$(2ND_ART_TEST_OUT))))
 
+# Used outside the art project to get a list of the current tests
+ART_TEST_DEX_MAKE_TARGETS := $(addprefix art-test-dex-, $(TEST_DEX_DIRECTORIES))
+
 # Rules to explicitly create 2nd-arch test directories, as we use a "cp" for them
 # instead of BUILD_JAVA_LIBRARY
 ifneq ($(2ND_ART_NATIVETEST_OUT),)
@@ -151,7 +154,7 @@
   $(call declare-test-art-oat-targets-impl,$(1),)
 
 $(HOST_OUT_JAVA_LIBRARIES)/oat-test-dex-$(1).odex: $(HOST_OUT_JAVA_LIBRARIES)/oat-test-dex-$(1).jar $(HOST_CORE_IMG_OUT) | $(DEX2OATD)
-	$(DEX2OATD) $(DEX2OAT_FLAGS) --runtime-arg -Xms16m --runtime-arg -Xmx16m --boot-image=$(HOST_CORE_IMG_OUT) --dex-file=$(PWD)/$$< --oat-file=$(PWD)/$$@ --instruction-set=$(ART_HOST_ARCH) --host --android-root=$(HOST_OUT)
+	$(DEX2OATD) $(DEX2OAT_FLAGS) --runtime-arg -Xms16m --runtime-arg -Xmx16m --boot-image=$(HOST_CORE_IMG_OUT) --dex-file=$$(realpath $$<) --oat-file=$$(realpath $(HOST_OUT_JAVA_LIBRARIES))/oat-test-dex-$(1).odex --instruction-set=$(ART_HOST_ARCH) --host --android-root=$(HOST_OUT)
 
 .PHONY: test-art-host-oat-default-$(1)
 test-art-host-oat-default-$(1): $(HOST_OUT_JAVA_LIBRARIES)/oat-test-dex-$(1).odex test-art-host-dependencies
@@ -159,7 +162,7 @@
 	ANDROID_DATA=/tmp/android-data/test-art-host-oat-default-$(1) \
 	  ANDROID_ROOT=$(HOST_OUT) \
 	  LD_LIBRARY_PATH=$(HOST_OUT_SHARED_LIBRARIES) \
-	  $(HOST_OUT_EXECUTABLES)/dalvikvm $(DALVIKVM_FLAGS) -XXlib:libartd.so -Ximage:$(shell pwd)/$(HOST_CORE_IMG_OUT) -classpath $(HOST_OUT_JAVA_LIBRARIES)/oat-test-dex-$(1).jar -Djava.library.path=$(HOST_OUT_SHARED_LIBRARIES) $(1) $(2) \
+	  $(HOST_OUT_EXECUTABLES)/dalvikvm $(DALVIKVM_FLAGS) -XXlib:libartd.so -Ximage:$$(realpath $(HOST_CORE_IMG_OUT)) -classpath $(HOST_OUT_JAVA_LIBRARIES)/oat-test-dex-$(1).jar -Djava.library.path=$(HOST_OUT_SHARED_LIBRARIES) $(1) $(2) \
           && echo test-art-host-oat-default-$(1) PASSED || (echo test-art-host-oat-default-$(1) FAILED && exit 1)
 	$(hide) rm -r /tmp/android-data/test-art-host-oat-default-$(1)
 
@@ -169,7 +172,7 @@
 	ANDROID_DATA=/tmp/android-data/test-art-host-oat-interpreter-$(1) \
 	  ANDROID_ROOT=$(HOST_OUT) \
 	  LD_LIBRARY_PATH=$(HOST_OUT_SHARED_LIBRARIES) \
-	  $(HOST_OUT_EXECUTABLES)/dalvikvm -XXlib:libartd.so -Ximage:$(shell pwd)/$(HOST_CORE_IMG_OUT) -Xint -classpath $(HOST_OUT_JAVA_LIBRARIES)/oat-test-dex-$(1).jar -Djava.library.path=$(HOST_OUT_SHARED_LIBRARIES) $(1) $(2) \
+	  $(HOST_OUT_EXECUTABLES)/dalvikvm -XXlib:libartd.so -Ximage:$$(realpath $(HOST_CORE_IMG_OUT)) -Xint -classpath $(HOST_OUT_JAVA_LIBRARIES)/oat-test-dex-$(1).jar -Djava.library.path=$(HOST_OUT_SHARED_LIBRARIES) $(1) $(2) \
           && echo test-art-host-oat-interpreter-$(1) PASSED || (echo test-art-host-oat-interpreter-$(1) FAILED && exit 1)
 	$(hide) rm -r /tmp/android-data/test-art-host-oat-interpreter-$(1)